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