source: branches/1.9x/third-party/miniupnp/connecthostport.c @ 10587

Last change on this file since 10587 was 10587, checked in by charles, 12 years ago

(1.9x) more miniupnpc

File size: 5.4 KB
Line 
1/* $Id: connecthostport.c,v 1.2 2010/04/05 00:08:15 nanard Exp $ */
2/* Project : miniupnp
3 * Author : Thomas Bernard
4 * Copyright (c) 2010 Thomas Bernard
5 * This software is subject to the conditions detailed in the
6 * LICENCE file provided in this distribution. */
7
8/* use getaddrinfo() or gethostbyname()
9 * uncomment the following line in order to use gethostbyname() */
10/* #define USE_GETHOSTBYNAME */
11
12#include <string.h>
13#include <stdio.h>
14#ifdef WIN32
15#include <winsock2.h>
16#include <ws2tcpip.h>
17#include <io.h>
18#define snprintf _snprintf
19#define herror
20#define socklen_t int
21#else /* #ifdef WIN32 */
22#include <unistd.h>
23#include <errno.h>
24#define closesocket close
25#include <netdb.h>
26/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
27 * during the connect() call */
28#define MINIUPNPC_IGNORE_EINTR
29#ifndef USE_GETHOSTBYNAME
30#include <sys/types.h>
31#include <sys/socket.h>
32#endif /* #ifndef USE_GETHOSTBYNAME */
33#endif /* #else WIN32 */
34
35/* definition of PRINT_SOCKET_ERROR */
36#ifdef WIN32
37#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError());
38#else
39#define PRINT_SOCKET_ERROR(x) perror(x)
40#endif
41
42#if defined(__amigaos__) || defined(__amigaos4__)
43#define herror(A) printf("%s\n", A)
44#endif
45
46#include "connecthostport.h"
47
48/* connecthostport()
49 * return a socket connected (TCP) to the host and port
50 * or -1 in case of error */
51int connecthostport(const char * host, unsigned short port)
52{
53        int s, n;
54#ifdef USE_GETHOSTBYNAME
55        struct sockaddr_in dest;
56        struct hostent *hp;
57#else /* #ifdef USE_GETHOSTBYNAME */
58        char port_str[8];
59        struct addrinfo *ai, *p;
60        struct addrinfo hints;
61#endif /* #ifdef USE_GETHOSTBYNAME */
62#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
63        struct timeval timeout;
64#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
65       
66#ifdef USE_GETHOSTBYNAME
67        hp = gethostbyname(host);
68        if(hp == NULL)
69        {
70                herror(host);
71                return -1;
72        }
73        memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr));
74        memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
75        s = socket(PF_INET, SOCK_STREAM, 0);
76        if(s < 0)
77        {
78                PRINT_SOCKET_ERROR("socket");
79                return -1;
80        }
81#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
82        /* setting a 3 seconds timeout for the connect() call */
83        timeout.tv_sec = 3;
84        timeout.tv_usec = 0;
85        if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
86        {
87                PRINT_SOCKET_ERROR("setsockopt");
88        }
89        timeout.tv_sec = 3;
90        timeout.tv_usec = 0;
91        if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
92        {
93                PRINT_SOCKET_ERROR("setsockopt");
94        }
95#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
96        dest.sin_family = AF_INET;
97        dest.sin_port = htons(port);
98        n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
99#ifdef MINIUPNPC_IGNORE_EINTR
100        while(n < 0 && errno == EINTR)
101        {
102                socklen_t len;
103                fd_set wset;
104                int err;
105                FD_ZERO(&wset);
106                FD_SET(s, &wset);
107                if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
108                        continue;
109                /*len = 0;*/
110                /*n = getpeername(s, NULL, &len);*/
111                len = sizeof(err);
112                if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
113                        PRINT_SOCKET_ERROR("getsockopt");
114                        closesocket(s);
115                        return -1;
116                }
117                if(err != 0) {
118                        errno = err;
119                        n = -1;
120                }
121        }
122#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
123        if(n<0)
124        {
125                PRINT_SOCKET_ERROR("connect");
126                closesocket(s);
127                return -1;
128        }
129#else /* #ifdef USE_GETHOSTBYNAME */
130        /* use getaddrinfo() instead of gethostbyname() */
131        memset(&hints, 0, sizeof(hints));
132        /* hints.ai_flags = AI_ADDRCONFIG; */
133#ifdef AI_NUMERICSERV
134        hints.ai_flags = AI_NUMERICSERV;
135#endif
136        hints.ai_socktype = SOCK_STREAM;
137        hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
138        /* hints.ai_protocol = IPPROTO_TCP; */
139        snprintf(port_str, sizeof(port_str), "%hu", port);
140        n = getaddrinfo(host, port_str, &hints, &ai);
141        if(n != 0)
142        {
143#ifdef WIN32
144                fprintf(stderr, "getaddrinfo() error : %d\n", n);
145#else
146                fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
147#endif
148                return -1;
149        }
150        s = -1;
151        for(p = ai; p; p = p->ai_next)
152        {
153                s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
154                if(s < 0)
155                        continue;
156#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
157                /* setting a 3 seconds timeout for the connect() call */
158                timeout.tv_sec = 3;
159                timeout.tv_usec = 0;
160                if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
161                {
162                        PRINT_SOCKET_ERROR("setsockopt");
163                }
164                timeout.tv_sec = 3;
165                timeout.tv_usec = 0;
166                if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
167                {
168                        PRINT_SOCKET_ERROR("setsockopt");
169                }
170#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
171                n = connect(s, p->ai_addr, p->ai_addrlen);
172#ifdef MINIUPNPC_IGNORE_EINTR
173                while(n < 0 && errno == EINTR)
174                {
175                        socklen_t len;
176                        fd_set wset;
177                        int err;
178                        FD_ZERO(&wset);
179                        FD_SET(s, &wset);
180                        if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
181                                continue;
182                        /*len = 0;*/
183                        /*n = getpeername(s, NULL, &len);*/
184                        len = sizeof(err);
185                        if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
186                                PRINT_SOCKET_ERROR("getsockopt");
187                                closesocket(s);
188                                freeaddrinfo(ai);
189                                return -1;
190                        }
191                        if(err != 0) {
192                                errno = err;
193                                n = -1;
194                        }
195                }
196#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
197                if(n < 0)
198                {
199                        closesocket(s);
200                        continue;
201                }
202                else
203                {
204                        break;
205                }
206        }
207        freeaddrinfo(ai);
208        if(s < 0)
209        {
210                PRINT_SOCKET_ERROR("socket");
211                return -1;
212        }
213        if(n < 0)
214        {
215                PRINT_SOCKET_ERROR("connect");
216                return -1;
217        }
218#endif /* #ifdef USE_GETHOSTBYNAME */
219        return s;
220}
221
Note: See TracBrowser for help on using the repository browser.