Annotation of embedaddon/miniupnpc/connecthostport.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* $Id: connecthostport.c,v 1.9 2012/06/26 00:00:27 nanard Exp $ */
1.1 misho 2: /* Project : miniupnp
3: * Author : Thomas Bernard
1.1.1.2 ! misho 4: * Copyright (c) 2010-2012 Thomas Bernard
1.1 misho 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: #ifdef NO_GETADDRINFO
11: #define USE_GETHOSTBYNAME
12: #endif
13:
14: #include <string.h>
15: #include <stdio.h>
1.1.1.2 ! misho 16: #ifdef _WIN32
1.1 misho 17: #include <winsock2.h>
18: #include <ws2tcpip.h>
19: #include <io.h>
20: #define MAXHOSTNAMELEN 64
21: #define snprintf _snprintf
22: #define herror
23: #define socklen_t int
1.1.1.2 ! misho 24: #else /* #ifdef _WIN32 */
1.1 misho 25: #include <unistd.h>
26: #include <sys/param.h>
27: #include <errno.h>
28: #define closesocket close
29: #include <netdb.h>
1.1.1.2 ! misho 30: #include <netinet/in.h>
1.1 misho 31: /* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
32: * during the connect() call */
33: #define MINIUPNPC_IGNORE_EINTR
34: #ifndef USE_GETHOSTBYNAME
35: #include <sys/types.h>
36: #include <sys/socket.h>
37: #endif /* #ifndef USE_GETHOSTBYNAME */
1.1.1.2 ! misho 38: #endif /* #else _WIN32 */
1.1 misho 39:
40: /* definition of PRINT_SOCKET_ERROR */
1.1.1.2 ! misho 41: #ifdef _WIN32
1.1 misho 42: #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
43: #else
44: #define PRINT_SOCKET_ERROR(x) perror(x)
45: #endif
46:
47: #if defined(__amigaos__) || defined(__amigaos4__)
48: #define herror(A) printf("%s\n", A)
49: #endif
50:
51: #include "connecthostport.h"
52:
53: /* connecthostport()
54: * return a socket connected (TCP) to the host and port
55: * or -1 in case of error */
1.1.1.2 ! misho 56: int connecthostport(const char * host, unsigned short port,
! 57: unsigned int scope_id)
1.1 misho 58: {
59: int s, n;
60: #ifdef USE_GETHOSTBYNAME
61: struct sockaddr_in dest;
62: struct hostent *hp;
63: #else /* #ifdef USE_GETHOSTBYNAME */
64: char tmp_host[MAXHOSTNAMELEN+1];
65: char port_str[8];
66: struct addrinfo *ai, *p;
67: struct addrinfo hints;
68: #endif /* #ifdef USE_GETHOSTBYNAME */
69: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
70: struct timeval timeout;
71: #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
1.1.1.2 ! misho 72:
1.1 misho 73: #ifdef USE_GETHOSTBYNAME
74: hp = gethostbyname(host);
75: if(hp == NULL)
76: {
77: herror(host);
78: return -1;
79: }
80: memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr));
81: memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
82: s = socket(PF_INET, SOCK_STREAM, 0);
83: if(s < 0)
84: {
85: PRINT_SOCKET_ERROR("socket");
86: return -1;
87: }
88: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
89: /* setting a 3 seconds timeout for the connect() call */
90: timeout.tv_sec = 3;
91: timeout.tv_usec = 0;
92: if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
93: {
94: PRINT_SOCKET_ERROR("setsockopt");
95: }
96: timeout.tv_sec = 3;
97: timeout.tv_usec = 0;
98: if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
99: {
100: PRINT_SOCKET_ERROR("setsockopt");
101: }
102: #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
103: dest.sin_family = AF_INET;
104: dest.sin_port = htons(port);
105: n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
106: #ifdef MINIUPNPC_IGNORE_EINTR
107: while(n < 0 && errno == EINTR)
108: {
109: socklen_t len;
110: fd_set wset;
111: int err;
112: FD_ZERO(&wset);
113: FD_SET(s, &wset);
114: if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
115: continue;
116: /*len = 0;*/
117: /*n = getpeername(s, NULL, &len);*/
118: len = sizeof(err);
119: if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
120: PRINT_SOCKET_ERROR("getsockopt");
121: closesocket(s);
122: return -1;
123: }
124: if(err != 0) {
125: errno = err;
126: n = -1;
127: }
128: }
129: #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
130: if(n<0)
131: {
132: PRINT_SOCKET_ERROR("connect");
133: closesocket(s);
134: return -1;
135: }
136: #else /* #ifdef USE_GETHOSTBYNAME */
137: /* use getaddrinfo() instead of gethostbyname() */
138: memset(&hints, 0, sizeof(hints));
139: /* hints.ai_flags = AI_ADDRCONFIG; */
140: #ifdef AI_NUMERICSERV
141: hints.ai_flags = AI_NUMERICSERV;
142: #endif
143: hints.ai_socktype = SOCK_STREAM;
144: hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
145: /* hints.ai_protocol = IPPROTO_TCP; */
146: snprintf(port_str, sizeof(port_str), "%hu", port);
147: if(host[0] == '[')
148: {
149: /* literal ip v6 address */
1.1.1.2 ! misho 150: int i, j;
! 151: for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++)
1.1 misho 152: {
1.1.1.2 ! misho 153: tmp_host[i] = host[j];
! 154: if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */
! 155: j+=2; /* skip "25" */
1.1 misho 156: }
157: tmp_host[i] = '\0';
158: }
159: else
160: {
161: strncpy(tmp_host, host, MAXHOSTNAMELEN);
162: }
163: tmp_host[MAXHOSTNAMELEN] = '\0';
164: n = getaddrinfo(tmp_host, port_str, &hints, &ai);
165: if(n != 0)
166: {
1.1.1.2 ! misho 167: #ifdef _WIN32
1.1 misho 168: fprintf(stderr, "getaddrinfo() error : %d\n", n);
169: #else
170: fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
171: #endif
172: return -1;
173: }
174: s = -1;
175: for(p = ai; p; p = p->ai_next)
176: {
177: s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
178: if(s < 0)
179: continue;
1.1.1.2 ! misho 180: if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) {
! 181: struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr;
! 182: addr6->sin6_scope_id = scope_id;
! 183: }
1.1 misho 184: #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
185: /* setting a 3 seconds timeout for the connect() call */
186: timeout.tv_sec = 3;
187: timeout.tv_usec = 0;
188: if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
189: {
190: PRINT_SOCKET_ERROR("setsockopt");
191: }
192: timeout.tv_sec = 3;
193: timeout.tv_usec = 0;
194: if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
195: {
196: PRINT_SOCKET_ERROR("setsockopt");
197: }
198: #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
199: n = connect(s, p->ai_addr, p->ai_addrlen);
200: #ifdef MINIUPNPC_IGNORE_EINTR
201: while(n < 0 && errno == EINTR)
202: {
203: socklen_t len;
204: fd_set wset;
205: int err;
206: FD_ZERO(&wset);
207: FD_SET(s, &wset);
208: if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
209: continue;
210: /*len = 0;*/
211: /*n = getpeername(s, NULL, &len);*/
212: len = sizeof(err);
213: if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
214: PRINT_SOCKET_ERROR("getsockopt");
215: closesocket(s);
216: freeaddrinfo(ai);
217: return -1;
218: }
219: if(err != 0) {
220: errno = err;
221: n = -1;
222: }
223: }
224: #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
225: if(n < 0)
226: {
227: closesocket(s);
228: continue;
229: }
230: else
231: {
232: break;
233: }
234: }
235: freeaddrinfo(ai);
236: if(s < 0)
237: {
238: PRINT_SOCKET_ERROR("socket");
239: return -1;
240: }
241: if(n < 0)
242: {
243: PRINT_SOCKET_ERROR("connect");
244: return -1;
245: }
246: #endif /* #ifdef USE_GETHOSTBYNAME */
247: return s;
248: }
249:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>