1 /* sim_sock.c: OS-dependent socket routines
2
3 Copyright (c) 2001-2010 Robert M Supnik
4 Copyright (c) 2021 The DPS8M Development Team
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Except as contained in this notice, the name of Robert M Supnik shall not be
24 used in advertising or otherwise to promote the sale, use or other dealings
25 in this Software without prior written authorization from Robert M Supnik.
26 */
27
28 #include "sim_sock.h"
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #if defined(AF_INET6) && defined(_WIN32)
34 # include <ws2tcpip.h>
35 #endif
36
37 #ifndef WSAAPI
38 # define WSAAPI
39 #endif
40
41 #if defined(SHUT_RDWR) && !defined(SD_BOTH)
42 # define SD_BOTH SHUT_RDWR
43 #endif
44
45 #ifndef NI_MAXHOST
46 # define NI_MAXHOST 1025
47 #endif
48
49 /* OS dependent routines
50
51 sim_master_sock create master socket
52 sim_connect_sock connect a socket to a remote destination
53 sim_connect_sock_ex connect a socket to a remote destination
54 sim_accept_conn accept connection
55 sim_read_sock read from socket
56 sim_write_sock write from socket
57 sim_close_sock close socket
58 sim_setnonblock set socket non-blocking
59 */
60
61 /* First, all the non-implemented versions */
62
63 /* Standard Berkeley socket routines */
64
65 static struct sock_errors {
66 int value;
67 const char *text;
68 } sock_errors[] = {
69 {WSAEWOULDBLOCK, "Operation would block"},
70 {WSAENAMETOOLONG, "File name too long"},
71 {WSAEINPROGRESS, "Operation now in progress "},
72 {WSAETIMEDOUT, "Connection timed out"},
73 {WSAEISCONN, "Transport endpoint is already connected"},
74 {WSAECONNRESET, "Connection reset by peer"},
75 {WSAECONNREFUSED, "Connection refused"},
76 {WSAECONNABORTED, "Connection aborted"},
77 {WSAEHOSTUNREACH, "No route to host"},
78 {WSAEADDRINUSE, "Address already in use"},
79 #if defined (WSAEAFNOSUPPORT)
80 {WSAEAFNOSUPPORT, "Address family not supported by protocol"},
81 #endif
82 {WSAEACCES, "Permission denied"},
83 {0, NULL}
84 };
85
sim_get_err_sock(const char * emsg)86 const char *sim_get_err_sock (const char *emsg)
87 {
88 int err = WSAGetLastError ();
89 int i;
90 static char err_buf[512];
91
92 for (i=0; (sock_errors[i].text) && (sock_errors[i].value != err); i++)
93 ;
94 if (sock_errors[i].value == err)
95 sprintf (err_buf, "Sockets: %s error %d - %s\n", emsg, err, sock_errors[i].text);
96 else
97 #if defined(_WIN32)
98 sprintf (err_buf, "Sockets: %s error %d\n", emsg, err);
99 #else
100 sprintf (err_buf, "Sockets: %s error %d - %s\n", emsg, err, strerror(err));
101 #endif
102 return err_buf;
103 }
104
sim_err_sock(SOCKET s,const char * emsg)105 SOCKET sim_err_sock (SOCKET s, const char *emsg)
106 {
107 sim_printf ("%s", sim_get_err_sock (emsg));
108 if (s != INVALID_SOCKET) {
109 int err = WSAGetLastError ();
110 sim_close_sock (s);
111 WSASetLastError (err); /* Retain Original socket error value */
112 }
113 return INVALID_SOCKET;
114 }
115
116 typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo *ai);
117 static freeaddrinfo_func p_freeaddrinfo;
118
119 typedef int (WSAAPI *getaddrinfo_func) (const char *hostname,
120 const char *service,
121 const struct addrinfo *hints,
122 struct addrinfo **res);
123 static getaddrinfo_func p_getaddrinfo;
124
125 typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
126 static getnameinfo_func p_getnameinfo;
127
128 #if defined(_WIN32) || defined(__CYGWIN__)
s_freeaddrinfo(struct addrinfo * ai)129 static void WSAAPI s_freeaddrinfo (struct addrinfo *ai)
130 {
131 struct addrinfo *a, *an;
132
133 for (a=ai; a != NULL; a=an) {
134 an = a->ai_next;
135 free (a->ai_canonname);
136 free (a->ai_addr);
137 free (a);
138 }
139 }
140
s_getaddrinfo(const char * hostname,const char * service,const struct addrinfo * hints,struct addrinfo ** res)141 static int WSAAPI s_getaddrinfo (const char *hostname,
142 const char *service,
143 const struct addrinfo *hints,
144 struct addrinfo **res)
145 {
146 struct hostent *he;
147 struct servent *se = NULL;
148 struct sockaddr_in *sin;
149 struct addrinfo *result = NULL;
150 struct addrinfo *ai, *lai = NULL;
151 struct addrinfo dhints;
152 struct in_addr ipaddr;
153 struct in_addr *fixed[2];
154 struct in_addr **ips = NULL;
155 struct in_addr **ip;
156 const char *cname = NULL;
157 int port = 0;
158
159 // Validate parameters
160 if ((hostname == NULL) && (service == NULL))
161 return EAI_NONAME;
162
163 if (hints) {
164 if ((hints->ai_family != PF_INET) && (hints->ai_family != PF_UNSPEC))
165 return EAI_FAMILY;
166 switch (hints->ai_socktype)
167 {
168 default:
169 return EAI_SOCKTYPE;
170 case SOCK_DGRAM:
171 case SOCK_STREAM:
172 case 0:
173 break;
174 }
175 }
176 else {
177 hints = &dhints;
178 memset(&dhints, 0, sizeof(dhints));
179 dhints.ai_family = PF_UNSPEC;
180 }
181 if (service) {
182 char *c;
183
184 port = strtoul(service, &c, 10);
185 if ((port == 0) || (*c != '\0')) {
186 switch (hints->ai_socktype)
187 {
188 case SOCK_DGRAM:
189 se = getservbyname(service, "udp");
190 break;
191 case SOCK_STREAM:
192 case 0:
193 se = getservbyname(service, "tcp");
194 break;
195 }
196 if (NULL == se)
197 return EAI_SERVICE;
198 port = se->s_port;
199 }
200 }
201
202 if (hostname) {
203 if ((0xffffffff != (ipaddr.s_addr = inet_addr(hostname))) ||
204 (0 == strcmp("255.255.255.255", hostname))) {
205 fixed[0] = &ipaddr;
206 fixed[1] = NULL;
207 }
208 else {
209 if ((0xffffffff != (ipaddr.s_addr = inet_addr(hostname))) ||
210 (0 == strcmp("255.255.255.255", hostname))) {
211 fixed[0] = &ipaddr;
212 fixed[1] = NULL;
213 if ((hints->ai_flags & AI_CANONNAME) && !(hints->ai_flags & AI_NUMERICHOST)) {
214 he = gethostbyaddr((char *)&ipaddr, 4, AF_INET);
215 if (NULL != he)
216 cname = he->h_name;
217 else
218 cname = hostname;
219 }
220 ips = fixed;
221 }
222 else {
223 if (hints->ai_flags & AI_NUMERICHOST)
224 return EAI_NONAME;
225 he = gethostbyname(hostname);
226 if (he) {
227 ips = (struct in_addr **)he->h_addr_list;
228 if (hints->ai_flags & AI_CANONNAME)
229 cname = he->h_name;
230 }
231 else {
232 switch (h_errno)
233 {
234 case HOST_NOT_FOUND:
235 case NO_DATA:
236 return EAI_NONAME;
237 case TRY_AGAIN:
238 return EAI_AGAIN;
239 default:
240 return EAI_FAIL;
241 }
242 }
243 }
244 }
245 }
246 else {
247 if (hints->ai_flags & AI_PASSIVE)
248 ipaddr.s_addr = htonl(INADDR_ANY);
249 else
250 ipaddr.s_addr = htonl(INADDR_LOOPBACK);
251 fixed[0] = &ipaddr;
252 fixed[1] = NULL;
253 ips = fixed;
254 }
255 for (ip=ips; (ip != NULL) && (*ip != NULL); ++ip) {
256 ai = (struct addrinfo *)calloc(1, sizeof(*ai));
257 if (NULL == ai) {
258 s_freeaddrinfo(result);
259 return EAI_MEMORY;
260 }
261 ai->ai_family = PF_INET;
262 ai->ai_socktype = hints->ai_socktype;
263 ai->ai_protocol = hints->ai_protocol;
264 ai->ai_addr = NULL;
265 ai->ai_addrlen = sizeof(struct sockaddr_in);
266 ai->ai_canonname = NULL;
267 ai->ai_next = NULL;
268 ai->ai_addr = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in));
269 if (NULL == ai->ai_addr) {
270 free(ai);
271 s_freeaddrinfo(result);
272 return EAI_MEMORY;
273 }
274 sin = (struct sockaddr_in *)ai->ai_addr;
275 sin->sin_family = PF_INET;
276 sin->sin_port = (unsigned short)port;
277 memcpy(&sin->sin_addr, *ip, sizeof(sin->sin_addr));
278 if (NULL == result)
279 result = ai;
280 else
281 lai->ai_next = ai;
282 lai = ai;
283 }
284 if (cname) {
285 result->ai_canonname = (char *)calloc(1, strlen(cname)+1);
286 if (NULL == result->ai_canonname) {
287 s_freeaddrinfo(result);
288 return EAI_MEMORY;
289 }
290 strcpy(result->ai_canonname, cname);
291 }
292 *res = result;
293 return 0;
294 }
295
296 # ifndef EAI_OVERFLOW
297 # define EAI_OVERFLOW WSAENAMETOOLONG
298 # endif
299
s_getnameinfo(const struct sockaddr * sa,socklen_t salen,char * host,size_t hostlen,char * serv,size_t servlen,int flags)300 static int WSAAPI s_getnameinfo (const struct sockaddr *sa, socklen_t salen,
301 char *host, size_t hostlen,
302 char *serv, size_t servlen,
303 int flags)
304 {
305 struct hostent *he;
306 struct servent *se = NULL;
307 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
308
309 if (sin->sin_family != PF_INET)
310 return EAI_FAMILY;
311 if ((NULL == host) && (NULL == serv))
312 return EAI_NONAME;
313 if ((serv) && (servlen > 0)) {
314 if (flags & NI_NUMERICSERV)
315 se = NULL;
316 else
317 if (flags & NI_DGRAM)
318 se = getservbyport(sin->sin_port, "udp");
319 else
320 se = getservbyport(sin->sin_port, "tcp");
321 if (se) {
322 if (servlen <= strlen(se->s_name))
323 return EAI_OVERFLOW;
324 strcpy(serv, se->s_name);
325 }
326 else {
327 char buf[16];
328
329 sprintf(buf, "%d", ntohs(sin->sin_port));
330 if (servlen <= strlen(buf))
331 return EAI_OVERFLOW;
332 strcpy(serv, buf);
333 }
334 }
335 if ((host) && (hostlen > 0)) {
336 if (flags & NI_NUMERICHOST)
337 he = NULL;
338 else
339 he = gethostbyaddr((const char *)&sin->sin_addr, 4, AF_INET);
340 if (he) {
341 if (hostlen < strlen(he->h_name)+1)
342 return EAI_OVERFLOW;
343 strcpy(host, he->h_name);
344 }
345 else {
346 if (flags & NI_NAMEREQD)
347 return EAI_NONAME;
348 if (hostlen < strlen(inet_ntoa(sin->sin_addr))+1)
349 return EAI_OVERFLOW;
350 strcpy(host, inet_ntoa(sin->sin_addr));
351 }
352 }
353 return 0;
354 }
355
356 # if !defined(IPV6_V6ONLY) /* Older environments may not define IPV6_V6ONLY */
357 # define IPV6_V6ONLY 27 /* Treat wildcard bind as AF_INET6-only. */
358 # endif
359 /* Dynamic DLL load variables */
360 # ifdef _WIN32
361 static HINSTANCE hLib = 0; /* handle to DLL */
362 # else
363 static void *hLib = NULL; /* handle to Library */
364 # endif
365 static int lib_loaded = 0; /* 0=not loaded, 1=loaded, 2=library load failed, 3=Func load failed */
366 static const char* lib_name = "Ws2_32.dll";
367
368 /* load function pointer from DLL */
369 typedef int (*_func)();
370
load_function(const char * function,_func * func_ptr)371 static void load_function(const char* function, _func* func_ptr) {
372 # ifdef _WIN32
373 *func_ptr = (_func)GetProcAddress(hLib, function);
374 # else
375 *func_ptr = (_func)dlsym(hLib, function);
376 # endif
377 if (*func_ptr == 0) {
378 sim_printf ("Sockets: Failed to find function '%s' in %s\r\n", function, lib_name);
379 lib_loaded = 3;
380 }
381 }
382
383 /* load Ws2_32.dll as required */
load_ws2(void)384 int load_ws2(void) {
385 switch(lib_loaded) {
386 case 0: /* not loaded */
387 # if defined(_WIN32) || defined(__CYGWIN__)
388 hLib = LoadLibraryA(lib_name);
389 # else
390 hLib = dlopen(lib_name, RTLD_NOW);
391 # endif
392 if (hLib == 0) {
393 /* failed to load DLL */
394 sim_printf ("Sockets: Failed to load %s\r\n", lib_name);
395 lib_loaded = 2;
396 break;
397 } else {
398 /* library loaded OK */
399 lib_loaded = 1;
400 }
401
402 /* load required functions; sets dll_load=3 on error */
403 load_function("getaddrinfo", (_func *) &p_getaddrinfo);
404 load_function("getnameinfo", (_func *) &p_getnameinfo);
405 load_function("freeaddrinfo", (_func *) &p_freeaddrinfo);
406
407 if (lib_loaded != 1) {
408 /* unsuccessful load, connect stubs */
409 p_getaddrinfo = (getaddrinfo_func)s_getaddrinfo;
410 p_getnameinfo = (getnameinfo_func)s_getnameinfo;
411 p_freeaddrinfo = (freeaddrinfo_func)s_freeaddrinfo;
412 }
413 break;
414 default: /* loaded or failed */
415 break;
416 }
417 return (lib_loaded == 1) ? 1 : 0;
418 }
419 #endif
420
421 /* OS independent routines
422
423 sim_parse_addr parse a hostname/ipaddress from port and apply defaults and
424 optionally validate an address match
425 */
426
427 /* sim_parse_addr host:port
428
429 Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
430 If the host field contains one or more colon characters (i.e. it is an IPv6 address),
431 the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format)
432
433 Inputs:
434 cptr = pointer to input string
435 default_host
436 = optional pointer to default host if none specified
437 host_len = length of host buffer
438 default_port
439 = optional pointer to default port if none specified
440 port_len = length of port buffer
441 validate_addr = optional name/addr which is checked to be equivalent
442 to the host result of parsing the other input. This
443 address would usually be returned by sim_accept_conn.
444 Outputs:
445 host = pointer to buffer for IP address (may be NULL), 0 = none
446 port = pointer to buffer for IP port (may be NULL), 0 = none
447 result = status (0 on complete success or -1 if
448 parsing can't happen due to bad syntax, a value is
449 out of range, a result can't fit into a result buffer,
450 a service name doesn't exist, or a validation name
451 doesn't match the parsed host)
452 */
453
sim_parse_addr(const char * cptr,char * host,size_t host_len,const char * default_host,char * port,size_t port_len,const char * default_port,const char * validate_addr)454 int sim_parse_addr (const char *cptr, char *host, size_t host_len, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr)
455 {
456 char gbuf[CBUFSIZE], default_pbuf[CBUFSIZE];
457 const char *hostp;
458 char *portp;
459 char *endc;
460 unsigned long portval;
461
462 if ((host != NULL) && (host_len != 0))
463 memset (host, 0, host_len);
464 if ((port != NULL) && (port_len != 0))
465 memset (port, 0, port_len);
466 if ((cptr == NULL) || (*cptr == 0)) {
467 if (((default_host == NULL) || (*default_host == 0)) || ((default_port == NULL) || (*default_port == 0)))
468 return -1;
469 if ((host == NULL) || (port == NULL))
470 return -1; /* no place */
471 if ((strlen(default_host) >= host_len) || (strlen(default_port) >= port_len))
472 return -1; /* no room */
473 strcpy (host, default_host);
474 strcpy (port, default_port);
475 return 0;
476 }
477 memset (default_pbuf, 0, sizeof(default_pbuf));
478 if (default_port)
479 strncpy (default_pbuf, default_port, sizeof(default_pbuf)-1);
480 gbuf[sizeof(gbuf)-1] = '\0';
481 strncpy (gbuf, cptr, sizeof(gbuf)-1);
482 hostp = gbuf; /* default addr */
483 portp = NULL;
484 if ((portp = strrchr (gbuf, ':')) && /* x:y? split */
485 (NULL == strchr (portp, ']'))) {
486 *portp++ = 0;
487 if (*portp == '\0')
488 portp = default_pbuf;
489 }
490 else { /* No colon in input */
491 portp = gbuf; /* Input is the port specifier */
492 hostp = (const char *)default_host; /* host is defaulted if provided */
493 }
494 if (portp != NULL) {
495 portval = strtoul(portp, &endc, 10);
496 if ((*endc == '\0') && ((portval == 0) || (portval > 65535)))
497 return -1; /* numeric value too big */
498 if (*endc != '\0') {
499 struct servent *se = getservbyname(portp, "tcp");
500
501 if (se == NULL)
502 return -1; /* invalid service name */
503 }
504 }
505 if (port) /* port wanted? */
506 if (portp != NULL) {
507 if (strlen(portp) >= port_len)
508 return -1; /* no room */
509 else
510 strcpy (port, portp);
511 }
512 if (hostp != NULL) {
513 if (']' == hostp[strlen(hostp)-1]) {
514 if ('[' != hostp[0])
515 return -1; /* invalid domain literal */
516 /* host may be the const default_host so move to temp buffer before modifying */
517 strncpy(gbuf, hostp+1, sizeof(gbuf)-1); /* remove brackets from domain literal host */
518 gbuf[strlen(gbuf)-1] = '\0';
519 hostp = gbuf;
520 }
521 }
522 if (host) { /* host wanted? */
523 if (hostp != NULL) {
524 if (strlen(hostp) >= host_len)
525 return -1; /* no room */
526 else
527 if (('\0' != hostp[0]) || (default_host == NULL))
528 strcpy (host, hostp);
529 else
530 if (strlen(default_host) >= host_len)
531 return -1; /* no room */
532 else
533 strcpy (host, default_host);
534 }
535 else {
536 if (default_host) {
537 if (strlen(default_host) >= host_len)
538 return -1; /* no room */
539 else
540 strcpy (host, default_host);
541 }
542 }
543 }
544 if (validate_addr) {
545 struct addrinfo *ai_host, *ai_validate, *ai, *aiv;
546 int status;
547
548 if (hostp == NULL)
549 return -1;
550 if (p_getaddrinfo(hostp, NULL, NULL, &ai_host))
551 return -1;
552 if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate)) {
553 p_freeaddrinfo (ai_host);
554 return -1;
555 }
556 status = -1;
557 for (ai = ai_host; ai != NULL; ai = ai->ai_next) {
558 for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) {
559 if ((ai->ai_addrlen == aiv->ai_addrlen) &&
560 (ai->ai_family == aiv->ai_family) &&
561 (0 == memcmp (ai->ai_addr, aiv->ai_addr, ai->ai_addrlen))) {
562 status = 0;
563 break;
564 }
565 }
566 }
567 if (status != 0) {
568 /* be generous and allow successful validations against variations of localhost addresses */
569 if (((0 == strcmp("127.0.0.1", hostp)) &&
570 (0 == strcmp("::1", validate_addr))) ||
571 ((0 == strcmp("127.0.0.1", validate_addr)) &&
572 (0 == strcmp("::1", hostp))))
573 status = 0;
574 }
575 p_freeaddrinfo (ai_host);
576 p_freeaddrinfo (ai_validate);
577 return status;
578 }
579 return 0;
580 }
581
582 #ifdef UNUSED
583 /* sim_parse_addr_ex localport:host:port
584
585 Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
586 If the host field contains one or more colon characters (i.e. it is an IPv6 address),
587 the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format)
588
589 llll:w.x.y.z:rrrr
590 llll:name.domain.com:rrrr
591 llll::rrrr
592 rrrr
593 w.x.y.z:rrrr
594 [w.x.y.z]:rrrr
595 name.domain.com:rrrr
596
597 Inputs:
598 cptr = pointer to input string
599 default_host
600 = optional pointer to default host if none specified
601 host_len = length of host buffer
602 default_port
603 = optional pointer to default port if none specified
604 port_len = length of port buffer
605
606 Outputs:
607 host = pointer to buffer for IP address (may be NULL), 0 = none
608 port = pointer to buffer for IP port (may be NULL), 0 = none
609 localport
610 = pointer to buffer for local IP port (may be NULL), 0 = none
611 result = status (SCPE_OK on complete success or SCPE_ARG if
612 parsing can't happen due to bad syntax, a value is
613 out of range, a result can't fit into a result buffer,
614 a service name doesn't exist, or a validation name
615 doesn't match the parsed host)
616 */
sim_parse_addr_ex(const char * cptr,char * host,size_t hostlen,const char * default_host,char * port,size_t port_len,char * localport,size_t localport_len,const char * default_port)617 int sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, char *localport, size_t localport_len, const char *default_port)
618 {
619 const char *hostp;
620
621 if ((localport != NULL) && (localport_len != 0))
622 memset (localport, 0, localport_len);
623 hostp = strchr (cptr, ':');
624 if ((hostp != NULL) && ((hostp[1] == '[') || (NULL != strchr (hostp+1, ':')))) {
625 if ((localport != NULL) && (localport_len != 0)) {
626 localport_len -= 1;
627 if (localport_len > (size_t)(hostp-cptr))
628 localport_len = (size_t)(hostp-cptr);
629 memcpy (localport, cptr, localport_len);
630 }
631 return sim_parse_addr (hostp+1, host, hostlen, default_host, port, port_len, default_port, NULL);
632 }
633 return sim_parse_addr (cptr, host, hostlen, default_host, port, port_len, default_port, NULL);
634 }
635 #endif
636
sim_init_sock(void)637 void sim_init_sock (void)
638 {
639 #if defined (_WIN32)
640 int err;
641 WORD wVersionRequested;
642 WSADATA wsaData;
643 wVersionRequested = MAKEWORD (2, 2);
644
645 err = WSAStartup (wVersionRequested, &wsaData); /* start Winsock */
646 if (err != 0)
647 sim_printf ("Winsock: startup error %d\n", err);
648 # if defined(AF_INET6)
649 load_ws2 ();
650 # endif /* endif AF_INET6 */
651 #else /* Use native addrinfo APIs */
652 # if defined(AF_INET6)
653 p_getaddrinfo = (getaddrinfo_func)getaddrinfo;
654 p_getnameinfo = (getnameinfo_func)getnameinfo;
655 p_freeaddrinfo = (freeaddrinfo_func)freeaddrinfo;
656 # else
657 /* Native APIs not available, connect stubs */
658 p_getaddrinfo = (getaddrinfo_func)s_getaddrinfo;
659 p_getnameinfo = (getnameinfo_func)s_getnameinfo;
660 p_freeaddrinfo = (freeaddrinfo_func)s_freeaddrinfo;
661 # endif /* endif AF_INET6 */
662 #endif /* endif _WIN32 */
663 #if defined (SIGPIPE)
664 signal (SIGPIPE, SIG_IGN); /* no pipe signals */
665 #endif
666 }
667
sim_cleanup_sock(void)668 void sim_cleanup_sock (void)
669 {
670 #if defined (_WIN32)
671 WSACleanup ();
672 #endif
673 }
674
675 #if defined (_WIN32) /* Windows */
sim_setnonblock(SOCKET sock)676 static int sim_setnonblock (SOCKET sock)
677 {
678 unsigned long non_block = 1;
679
680 return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */
681 }
682
683 #else /* Mac, Unix, OS/2 */
sim_setnonblock(SOCKET sock)684 static int sim_setnonblock (SOCKET sock)
685 {
686 int fl, sta;
687
688 fl = fcntl (sock, F_GETFL,0); /* get flags */
689 if (fl == -1)
690 return SOCKET_ERROR;
691 sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK); /* set nonblock */
692 if (sta == -1)
693 return SOCKET_ERROR;
694 # if !defined (__HAIKU__) /* Unix only */
695 sta = fcntl (sock, F_SETOWN, getpid()); /* set ownership */
696 if (sta == -1)
697 return SOCKET_ERROR;
698 # endif
699 return 0;
700 }
701 #endif /* endif !Win32 */
702
sim_setnodelay(SOCKET sock)703 static int sim_setnodelay (SOCKET sock)
704 {
705 int nodelay = 1;
706 int sta;
707
708 /* disable Nagle algorithm */
709 sta = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay));
710 if (sta == -1)
711 return SOCKET_ERROR;
712
713 #if defined(TCP_NODELAYACK)
714 /* disable delayed ack algorithm */
715 sta = setsockopt (sock, IPPROTO_TCP, TCP_NODELAYACK, (char *)&nodelay, sizeof(nodelay));
716 if (sta == -1)
717 return SOCKET_ERROR;
718 #endif
719
720 #if defined(TCP_QUICKACK)
721 /* disable delayed ack algorithm */
722 sta = setsockopt (sock, IPPROTO_TCP, TCP_QUICKACK, (char *)&nodelay, sizeof(nodelay));
723 if (sta == -1)
724 return SOCKET_ERROR;
725 #endif
726
727 return sta;
728 }
729
sim_create_sock(int af,int opt_flags)730 static SOCKET sim_create_sock (int af, int opt_flags)
731 {
732 SOCKET newsock;
733 int err;
734
735 newsock = socket (af, ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM), 0);/* create socket */
736 if (newsock == INVALID_SOCKET) { /* socket error? */
737 #if defined(WSAEAFNOSUPPORT)
738 err = WSAGetLastError ();
739 if (err == WSAEAFNOSUPPORT) /* expected error, just return */
740 return newsock;
741 #endif
742 return sim_err_sock (newsock, "socket"); /* report error and return */
743 }
744 return newsock;
745 }
746
747 /*
748 Some platforms and/or network stacks have varying support for listening on
749 an IPv6 socket and receiving connections from both IPv4 and IPv6 client
750 connections. This is known as IPv4-Mapped. Some platforms claim such
751 support (i.e. some Windows versions), but it doesn't work in all cases.
752 */
753
sim_master_sock_ex(const char * hostport,int * parse_status,int opt_flags)754 SOCKET sim_master_sock_ex (const char *hostport, int *parse_status, int opt_flags)
755 {
756 SOCKET newsock = INVALID_SOCKET;
757 int sta;
758 char host[CBUFSIZE], port[CBUFSIZE];
759 int r;
760 struct addrinfo hints;
761 struct addrinfo *result = NULL, *preferred;
762
763 r = sim_parse_addr (hostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL);
764 if (parse_status)
765 *parse_status = r;
766 if (r)
767 return newsock;
768
769 memset(&hints, 0, sizeof(hints));
770 hints.ai_flags = AI_PASSIVE;
771 hints.ai_family = AF_UNSPEC;
772 hints.ai_protocol = IPPROTO_TCP;
773 hints.ai_socktype = SOCK_STREAM;
774 if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result)) {
775 if (parse_status)
776 *parse_status = -1;
777 return newsock;
778 }
779 preferred = result;
780 #ifdef IPV6_V6ONLY
781 /*
782 When we can create a dual stack socket, be sure to find the IPv6 addrinfo
783 to bind to.
784 */
785 for (; preferred != NULL; preferred = preferred->ai_next) {
786 if (preferred->ai_family == AF_INET6)
787 break;
788 }
789 if (preferred == NULL)
790 preferred = result;
791 #endif
792 retry:
793 newsock = sim_create_sock (preferred->ai_family, 0); /* create socket */
794 if (newsock == INVALID_SOCKET) { /* socket error? */
795 #ifndef IPV6_V6ONLY
796 if (preferred->ai_next) {
797 preferred = preferred->ai_next;
798 goto retry;
799 }
800 #else
801 if ((preferred->ai_family == AF_INET6) &&
802 (preferred != result)) {
803 preferred = result;
804 goto retry;
805 }
806 #endif
807 p_freeaddrinfo(result);
808 return newsock;
809 }
810 #ifdef IPV6_V6ONLY
811 if (preferred->ai_family == AF_INET6) {
812 int off = 0;
813 sta = setsockopt (newsock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
814 }
815 #endif
816 if (opt_flags & SIM_SOCK_OPT_REUSEADDR) {
817 int on = 1;
818
819 sta = setsockopt (newsock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
820 }
821 #if defined (SO_EXCLUSIVEADDRUSE)
822 else {
823 int on = 1;
824
825 sta = setsockopt (newsock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&on, sizeof(on));
826 }
827 #endif
828 sta = bind (newsock, preferred->ai_addr, preferred->ai_addrlen);
829 p_freeaddrinfo(result);
830 if (sta == SOCKET_ERROR) /* bind error? */
831 return sim_err_sock (newsock, "bind");
832 if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
833 sta = sim_setnonblock (newsock); /* set nonblocking */
834 if (sta == SOCKET_ERROR) /* fcntl error? */
835 return sim_err_sock (newsock, "setnonblock");
836 }
837 sta = listen (newsock, 1); /* listen on socket */
838 if (sta == SOCKET_ERROR) /* listen error? */
839 return sim_err_sock (newsock, "listen");
840 return newsock; /* got it! */
841 }
842
sim_connect_sock_ex(const char * sourcehostport,const char * hostport,const char * default_host,const char * default_port,int opt_flags)843 SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, int opt_flags)
844 {
845 SOCKET newsock = INVALID_SOCKET;
846 int sta;
847 char host[CBUFSIZE], port[CBUFSIZE];
848 struct addrinfo hints;
849 struct addrinfo *result = NULL, *source = NULL;
850
851 if (sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port, NULL))
852 return INVALID_SOCKET;
853
854 memset(&hints, 0, sizeof(hints));
855 hints.ai_family = AF_UNSPEC;
856 hints.ai_protocol = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? IPPROTO_UDP : IPPROTO_TCP);
857 hints.ai_socktype = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM);
858 if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result))
859 return INVALID_SOCKET;
860
861 if (sourcehostport) {
862
863 /* Validate the local/source side address which we'll bind to */
864 if (sim_parse_addr (sourcehostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL)) {
865 p_freeaddrinfo (result);
866 return INVALID_SOCKET;
867 }
868
869 memset(&hints, 0, sizeof(hints));
870 hints.ai_flags = AI_PASSIVE;
871 hints.ai_family = result->ai_family; /* Same family as connect destination */
872 hints.ai_protocol = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? IPPROTO_UDP : IPPROTO_TCP);
873 hints.ai_socktype = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM);
874 if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &source)) {
875 p_freeaddrinfo (result);
876 return INVALID_SOCKET;
877 }
878
879 newsock = sim_create_sock (result->ai_family, opt_flags & SIM_SOCK_OPT_DATAGRAM);/* create socket */
880 if (newsock == INVALID_SOCKET) { /* socket error? */
881 p_freeaddrinfo (result);
882 p_freeaddrinfo (source);
883 return newsock;
884 }
885
886 sta = bind (newsock, source->ai_addr, source->ai_addrlen);
887 p_freeaddrinfo(source);
888 source = NULL;
889 if (sta == SOCKET_ERROR) { /* bind error? */
890 p_freeaddrinfo (result);
891 return sim_err_sock (newsock, "bind");
892 }
893 }
894
895 if (newsock == INVALID_SOCKET) { /* socket error? */
896 newsock = sim_create_sock (result->ai_family, opt_flags & SIM_SOCK_OPT_DATAGRAM);/* create socket */
897 if (newsock == INVALID_SOCKET) { /* socket error? */
898 p_freeaddrinfo (result);
899 return newsock;
900 }
901 }
902
903 if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
904 sta = sim_setnonblock (newsock); /* set nonblocking */
905 if (sta == SOCKET_ERROR) { /* fcntl error? */
906 p_freeaddrinfo (result);
907 return sim_err_sock (newsock, "setnonblock");
908 }
909 }
910 if ((!(opt_flags & SIM_SOCK_OPT_DATAGRAM)) && (opt_flags & SIM_SOCK_OPT_NODELAY)) {
911 sta = sim_setnodelay (newsock); /* set nodelay */
912 if (sta == SOCKET_ERROR) { /* setsock error? */
913 p_freeaddrinfo (result);
914 return sim_err_sock (newsock, "setnodelay");
915 }
916 }
917 if (!(opt_flags & SIM_SOCK_OPT_DATAGRAM)) {
918 int keepalive = 1;
919
920 /* enable TCP Keep Alives */
921 sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive));
922 if (sta == -1)
923 return sim_err_sock (newsock, "setsockopt KEEPALIVE");
924 }
925 if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
926 sta = sim_setnonblock (newsock); /* set nonblocking */
927 if (sta == SOCKET_ERROR) /* fcntl error? */
928 return sim_err_sock (newsock, "setnonblock");
929 }
930 sta = connect (newsock, result->ai_addr, result->ai_addrlen);
931 p_freeaddrinfo (result);
932 if (sta == SOCKET_ERROR) {
933 if (opt_flags & SIM_SOCK_OPT_BLOCKING) {
934 if ((WSAGetLastError () == WSAETIMEDOUT) || /* expected errors after a connect failure */
935 (WSAGetLastError () == WSAEHOSTUNREACH) ||
936 (WSAGetLastError () == WSAECONNREFUSED) ||
937 (WSAGetLastError () == WSAECONNABORTED) ||
938 (WSAGetLastError () == WSAECONNRESET)) {
939 sim_close_sock (newsock);
940 newsock = INVALID_SOCKET;
941 }
942 else
943 return sim_err_sock (newsock, "connect");
944 }
945 else /* Non Blocking case won't return errors until some future read */
946 if ((WSAGetLastError () != WSAEWOULDBLOCK) &&
947 (WSAGetLastError () != WSAEINPROGRESS))
948 return sim_err_sock (newsock, "connect");
949 }
950 return newsock; /* got it! */
951 }
952
sim_accept_conn_ex(SOCKET master,char ** connectaddr,int opt_flags)953 SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, int opt_flags)
954 {
955 int sta = 0, err;
956 int keepalive = 1;
957 #if defined (__linux) || defined (__linux__) || \
958 defined (__APPLE__) || defined (__OpenBSD__) || \
959 defined (__NetBSD__) || defined(__FreeBSD__) || \
960 defined (__FreeBSD_kernel__) || defined (__HAIKU__)
961 socklen_t size;
962 #elif defined (_WIN32)
963 int size;
964 #else
965 size_t size;
966 #endif
967 SOCKET newsock;
968 struct sockaddr_storage clientname;
969
970 if (master == 0) /* not attached? */
971 return INVALID_SOCKET;
972 size = sizeof (clientname);
973 memset (&clientname, 0, sizeof(clientname));
974 newsock = accept (master, (struct sockaddr *) &clientname, &size);
975 if (newsock == INVALID_SOCKET) { /* error? */
976 err = WSAGetLastError ();
977 if (err != WSAEWOULDBLOCK)
978 sim_err_sock(newsock, "accept");
979 return INVALID_SOCKET;
980 }
981 if (connectaddr != NULL) {
982 *connectaddr = (char *)calloc(1, NI_MAXHOST+1);
983 #ifdef AF_INET6
984 p_getnameinfo((struct sockaddr *)&clientname, size, *connectaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
985 if (0 == memcmp("::ffff:", *connectaddr, 7)) /* is this a IPv4-mapped IPv6 address? */
986 memmove(*connectaddr, 7+*connectaddr, /* prefer bare IPv4 address */
987 strlen(*connectaddr) - 7 + 1); /* length to include terminating \0 */
988 #else
989 strcpy(*connectaddr, inet_ntoa(((struct sockaddr_in *)&connectaddr)->s_addr));
990 #endif
991 }
992
993 if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
994 sta = sim_setnonblock (newsock); /* set nonblocking */
995 if (sta == SOCKET_ERROR) /* fcntl error? */
996 return sim_err_sock (newsock, "setnonblock");
997 }
998
999 if ((opt_flags & SIM_SOCK_OPT_NODELAY)) {
1000 sta = sim_setnodelay (newsock); /* set nonblocking */
1001 if (sta == SOCKET_ERROR) /* setsockopt error? */
1002 return sim_err_sock (newsock, "setnodelay");
1003 }
1004
1005 /* enable TCP Keep Alives */
1006 sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive));
1007 if (sta == -1)
1008 return sim_err_sock (newsock, "setsockopt KEEPALIVE");
1009
1010 return newsock;
1011 }
1012
sim_check_conn(SOCKET sock,int rd)1013 int sim_check_conn (SOCKET sock, int rd)
1014 {
1015 fd_set rw_set, er_set;
1016 fd_set *rw_p = &rw_set;
1017 fd_set *er_p = &er_set;
1018 struct timeval zero;
1019 struct sockaddr_storage peername;
1020 #if defined (__linux) || defined (__linux__) || \
1021 defined (__APPLE__) || defined (__OpenBSD__) || \
1022 defined (__NetBSD__) || defined(__FreeBSD__) || \
1023 defined (__FreeBSD_kernel__) || defined (__HAIKU__)
1024 socklen_t peernamesize = (socklen_t)sizeof(peername);
1025 #elif defined (_WIN32)
1026 int peernamesize = (int)sizeof(peername);
1027 #else
1028 size_t peernamesize = sizeof(peername);
1029 #endif
1030
1031 memset (&zero, 0, sizeof(zero));
1032 FD_ZERO (rw_p);
1033 FD_ZERO (er_p);
1034 FD_SET (sock, rw_p);
1035 FD_SET (sock, er_p);
1036 if (rd)
1037 select ((int) sock + 1, rw_p, NULL, er_p, &zero);
1038 else
1039 select ((int) sock + 1, NULL, rw_p, er_p, &zero);
1040 if (FD_ISSET (sock, er_p))
1041 return -1;
1042 if (FD_ISSET (sock, rw_p)) {
1043 if (0 == getpeername (sock, (struct sockaddr *)&peername, &peernamesize))
1044 return 1;
1045 else
1046 return -1;
1047 }
1048 return 0;
1049 }
1050
_sim_getaddrname(struct sockaddr * addr,size_t addrsize,char * hostnamebuf,char * portnamebuf)1051 static int _sim_getaddrname (struct sockaddr *addr, size_t addrsize, char *hostnamebuf, char *portnamebuf)
1052 {
1053 int ret = 0;
1054
1055 #ifdef AF_INET6
1056 # if defined (__linux) || defined (__linux__) || \
1057 defined (__APPLE__) || defined (__OpenBSD__) || \
1058 defined (__NetBSD__) || defined(__FreeBSD__) || \
1059 defined (__FreeBSD_kernel__) || defined (__HAIKU__)
1060 socklen_t size = (socklen_t)addrsize;
1061 # elif defined (_WIN32)
1062 int size = (int)addrsize;
1063 # else
1064 size_t size = addrsize;
1065 # endif
1066 *hostnamebuf = '\0';
1067 *portnamebuf = '\0';
1068 ret = p_getnameinfo(addr, size, hostnamebuf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
1069 if (0 == memcmp("::ffff:", hostnamebuf, 7)) /* is this a IPv4-mapped IPv6 address? */
1070 memmove(hostnamebuf, 7+hostnamebuf, /* prefer bare IPv4 address */
1071 strlen(hostnamebuf) + 7 - 1); /* length to include terminating \0 */
1072 if (!ret)
1073 ret = p_getnameinfo(addr, size, NULL, 0, portnamebuf, NI_MAXSERV, NI_NUMERICSERV);
1074 #else
1075 strcpy(hostnamebuf, inet_ntoa(((struct sockaddr_in *)addr)->s_addr));
1076 sprintf(portnamebuf, "%d", (int)ntohs(((struct sockaddr_in *)addr)->s_port));
1077 #endif
1078 return ret;
1079 }
1080
sim_getnames_sock(SOCKET sock,char ** socknamebuf,char ** peernamebuf)1081 int sim_getnames_sock (SOCKET sock, char **socknamebuf, char **peernamebuf)
1082 {
1083 struct sockaddr_storage sockname, peername;
1084 #if defined (__linux) || defined (__linux__) || \
1085 defined (__APPLE__) || defined (__OpenBSD__) || \
1086 defined (__NetBSD__) || defined(__FreeBSD__) || \
1087 defined (__FreeBSD_kernel__) || defined (__HAIKU__)
1088 socklen_t socknamesize = (socklen_t)sizeof(sockname);
1089 socklen_t peernamesize = (socklen_t)sizeof(peername);
1090 #elif defined (_WIN32)
1091 int socknamesize = (int)sizeof(sockname);
1092 int peernamesize = (int)sizeof(peername);
1093 #else
1094 size_t socknamesize = sizeof(sockname);
1095 size_t peernamesize = sizeof(peername);
1096 #endif
1097 char hostbuf[NI_MAXHOST+1];
1098 char portbuf[NI_MAXSERV+1];
1099
1100 if (socknamebuf)
1101 *socknamebuf = (char *)calloc(1, NI_MAXHOST+NI_MAXSERV+4);
1102 if (peernamebuf)
1103 *peernamebuf = (char *)calloc(1, NI_MAXHOST+NI_MAXSERV+4);
1104 getsockname (sock, (struct sockaddr *)&sockname, &socknamesize);
1105 getpeername (sock, (struct sockaddr *)&peername, &peernamesize);
1106 if (socknamebuf != NULL) {
1107 _sim_getaddrname ((struct sockaddr *)&sockname, (size_t)socknamesize, hostbuf, portbuf);
1108 sprintf(*socknamebuf, "[%s]:%s", hostbuf, portbuf);
1109 }
1110 if (peernamebuf != NULL) {
1111 _sim_getaddrname ((struct sockaddr *)&peername, (size_t)peernamesize, hostbuf, portbuf);
1112 sprintf(*peernamebuf, "[%s]:%s", hostbuf, portbuf);
1113 }
1114 return 0;
1115 }
1116
sim_read_sock(SOCKET sock,char * buf,int nbytes)1117 int sim_read_sock (SOCKET sock, char *buf, int nbytes)
1118 {
1119 int rbytes, err;
1120
1121 rbytes = recv (sock, buf, nbytes, 0);
1122 if (rbytes == 0) /* disconnect */
1123 return -1;
1124 if (rbytes == SOCKET_ERROR) {
1125 err = WSAGetLastError ();
1126 if (err == WSAEWOULDBLOCK) /* no data */
1127 return 0;
1128 #if defined(EAGAIN)
1129 if (err == EAGAIN) /* no data */
1130 return 0;
1131 #endif
1132 if ((err != WSAETIMEDOUT) && /* expected errors after a connect failure */
1133 (err != WSAEHOSTUNREACH) &&
1134 (err != WSAECONNREFUSED) &&
1135 (err != WSAECONNABORTED) &&
1136 (err != WSAECONNRESET) &&
1137 (err != WSAEINTR)) /* or a close of a blocking read */
1138 sim_err_sock (INVALID_SOCKET, "read");
1139 return -1;
1140 }
1141 return rbytes;
1142 }
1143
sim_write_sock(SOCKET sock,const char * msg,int nbytes)1144 int sim_write_sock (SOCKET sock, const char *msg, int nbytes)
1145 {
1146 int err, sbytes = send (sock, msg, nbytes, 0);
1147
1148 if (sbytes == SOCKET_ERROR) {
1149 err = WSAGetLastError ();
1150 if (err == WSAEWOULDBLOCK) /* no data */
1151 return 0;
1152 #if defined(EAGAIN)
1153 if (err == EAGAIN) /* no data */
1154 return 0;
1155 #endif
1156 }
1157 return sbytes;
1158 }
1159
sim_close_sock(SOCKET sock)1160 void sim_close_sock (SOCKET sock)
1161 {
1162 shutdown(sock, SD_BOTH);
1163 closesocket (sock);
1164 }
1165
1166