]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/ada/socket.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / ada / socket.c
CommitLineData
fbf5a39b
AC
1/****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
b1c1e25c 5 * S O C K E T *
fbf5a39b
AC
6 * *
7 * C Implementation File *
8 * *
8d0d46f4 9 * Copyright (C) 2003-2021, Free Software Foundation, Inc. *
fbf5a39b
AC
10 * *
11 * GNAT is free software; you can redistribute it and/or modify it under *
12 * terms of the GNU General Public License as published by the Free Soft- *
748086b7 13 * ware Foundation; either version 3, or (at your option) any later ver- *
fbf5a39b
AC
14 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
15 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
748086b7
JJ
16 * or FITNESS FOR A PARTICULAR PURPOSE. *
17 * *
18 * As a special exception under Section 7 of GPL version 3, you are granted *
19 * additional permissions described in the GCC Runtime Library Exception, *
20 * version 3.1, as published by the Free Software Foundation. *
21 * *
22 * You should have received a copy of the GNU General Public License and *
23 * a copy of the GCC Runtime Library Exception along with this program; *
24 * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see *
25 * <http://www.gnu.org/licenses/>. *
fbf5a39b
AC
26 * *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
29 * *
30 ****************************************************************************/
31
b1c1e25c 32/* This file provides a portable binding to the sockets API */
c80645ab 33
005f870e
EB
34#define ATTRIBUTE_UNUSED __attribute__((unused))
35
783d035b 36/* Ensure access to errno is thread safe. */
08611be2 37#ifndef _REENTRANT
783d035b 38#define _REENTRANT
08611be2 39#endif
783d035b
AC
40#define _THREAD_SAFE
41
b1c1e25c 42#include "gsocket.h"
4a214958 43
90af5990
JM
44#if defined (__FreeBSD__) || defined (__DragonFly__) \
45 || defined (__NetBSD__) || defined (__OpenBSD__)
6db566c3
AC
46typedef unsigned int IOCTL_Req_T;
47#else
48typedef int IOCTL_Req_T;
8737a29a 49#endif
c80645ab
TQ
50
51#if defined(HAVE_SOCKETS)
52
82675755 53/* Include all the necessary system-specific headers and define the
0c78ce5a
TQ
54 * necessary macros (shared with gen-oscons).
55 */
82675755 56
3d3bf932
TQ
57#if !defined(SO_NOSIGPIPE) && !defined (MSG_NOSIGNAL)
58#include <signal.h>
59#endif
60/* Required if we will be calling signal() in __gnat_disable_all_sigpipes() */
61
fbf5a39b 62#include "raise.h"
82675755 63/* Required for __gnat_malloc() */
fbf5a39b 64
da8f5fd9 65#include <string.h>
3e1fd98f 66/* Required for memcpy() */
da8f5fd9 67
d6c7ed50 68extern void __gnat_disable_sigpipe (int fd);
3d3bf932
TQ
69extern void __gnat_disable_all_sigpipes (void);
70extern int __gnat_create_signalling_fds (int *fds);
71extern int __gnat_read_signalling_fd (int rsig);
72extern int __gnat_write_signalling_fd (int wsig);
1c8e4e2e 73extern void __gnat_close_signalling_fd (int sig);
9373164a
KC
74extern void __gnat_last_socket_in_set (fd_set *, int *);
75extern void __gnat_get_socket_from_set (fd_set *, int *, int *);
76extern void __gnat_insert_socket_in_set (fd_set *, int);
77extern int __gnat_is_socket_in_set (fd_set *, int);
78extern fd_set *__gnat_new_socket_set (fd_set *);
79extern void __gnat_remove_socket_from_set (fd_set *, int);
9013065b 80extern void __gnat_reset_socket_set (fd_set *);
3d3bf932 81extern int __gnat_get_h_errno (void);
6db566c3 82extern int __gnat_socket_ioctl (int, IOCTL_Req_T, int *);
4a214958 83
1dfddbb4 84extern char * __gnat_servent_s_name (struct servent *);
4a214958
AC
85extern char * __gnat_servent_s_alias (struct servent *, int index);
86extern unsigned short __gnat_servent_s_port (struct servent *);
1dfddbb4 87extern char * __gnat_servent_s_proto (struct servent *);
4a214958
AC
88
89extern char * __gnat_hostent_h_name (struct hostent *);
90extern char * __gnat_hostent_h_alias (struct hostent *, int);
91extern int __gnat_hostent_h_addrtype (struct hostent *);
92extern int __gnat_hostent_h_length (struct hostent *);
93extern char * __gnat_hostent_h_addr (struct hostent *, int);
94
759f1648
DA
95extern int __gnat_getaddrinfo(
96 const char *node,
97 const char *service,
98 const struct addrinfo *hints,
99 struct addrinfo **res);
100int __gnat_getnameinfo(
101 const struct sockaddr *sa, socklen_t salen,
102 char *host, size_t hostlen,
103 char *serv, size_t servlen, int flags);
104extern void __gnat_freeaddrinfo(struct addrinfo *res);
105extern const char * __gnat_gai_strerror(int errcode);
106
3a13e785 107#ifndef HAVE_INET_PTON
9013065b
AC
108extern int __gnat_inet_pton (int, const char *, void *);
109#endif
759f1648
DA
110
111#ifndef HAVE_INET_NTOP
112extern const char *
113__gnat_inet_ntop(int, const void *, char *, socklen_t);
114#endif
115
d6c7ed50 116/* Disable the sending of SIGPIPE for writes on a broken stream */
3e1fd98f 117
d6c7ed50 118void
005f870e 119__gnat_disable_sigpipe (int fd ATTRIBUTE_UNUSED)
d6c7ed50
TQ
120{
121#ifdef SO_NOSIGPIPE
122 int val = 1;
123 (void) setsockopt (fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof val);
124#endif
125}
126
3d3bf932
TQ
127void
128__gnat_disable_all_sigpipes (void)
129{
130#if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) && defined(SIGPIPE)
131 (void) signal (SIGPIPE, SIG_IGN);
132#endif
133}
759f1648 134
e08add8e 135#if defined (_WIN32) || defined (__vxworks)
3d3bf932
TQ
136/*
137 * Signalling FDs operations are implemented in Ada for these platforms
138 * (see subunit GNAT.Sockets.Thin.Signalling_Fds).
139 */
140#else
141/*
142 * Create a pair of connected file descriptors fds[0] and fds[1] used for
143 * signalling by a Selector object. fds[0] is the read end, and fds[1] the
144 * write end.
145 */
146int
147__gnat_create_signalling_fds (int *fds) {
148 return pipe (fds);
149}
759f1648 150
3d3bf932
TQ
151/*
152 * Read one byte of data from rsig, the read end of a pair of signalling fds
153 * created by __gnat_create_signalling_fds.
154 */
155int
156__gnat_read_signalling_fd (int rsig) {
157 char c;
158 return read (rsig, &c, 1);
159}
759f1648 160
3d3bf932
TQ
161/*
162 * Write one byte of data to wsig, the write end of a pair of signalling fds
163 * created by __gnat_create_signalling_fds.
164 */
165int
166__gnat_write_signalling_fd (int wsig) {
167 char c = 0;
168 return write (wsig, &c, 1);
169}
759f1648 170
1c8e4e2e
TQ
171/*
172 * Close one end of a pair of signalling fds
173 */
174void
175__gnat_close_signalling_fd (int sig) {
176 (void) close (sig);
177}
178#endif
759f1648 179
1c8e4e2e 180/*
4a214958
AC
181 * Handling of gethostbyname, gethostbyaddr, getservbyname and getservbyport
182 * =========================================================================
183 *
184 * This module exposes __gnat_getXXXbyYYY operations with the same signature
185 * as the reentrant variant getXXXbyYYY_r.
186 *
187 * On platforms where getXXXbyYYY is intrinsically reentrant, the provided user
188 * buffer argument is ignored.
1c8e4e2e 189 *
4a214958
AC
190 * When getXXXbyYYY is not reentrant but getXXXbyYYY_r exists, the latter is
191 * used, and the provided buffer argument must point to a valid, thread-local
192 * buffer (usually on the caller's stack).
193 *
194 * When getXXXbyYYY is not reentrant and no reentrant getXXXbyYYY_r variant
195 * is available, the non-reentrant getXXXbyYYY is called, the provided user
196 * buffer is ignored, and the caller is expected to take care of mutual
197 * exclusion.
1c8e4e2e
TQ
198 */
199
4a214958 200#ifdef HAVE_GETxxxBYyyy_R
1c8e4e2e 201int
4a214958 202__gnat_gethostbyname (const char *name,
1c8e4e2e
TQ
203 struct hostent *ret, char *buf, size_t buflen,
204 int *h_errnop)
205{
206 struct hostent *rh;
207 int ri;
208
06a1d02e 209#if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
1c8e4e2e
TQ
210 (void) gethostbyname_r (name, ret, buf, buflen, &rh, h_errnop);
211#else
212 rh = gethostbyname_r (name, ret, buf, buflen, h_errnop);
213#endif
214 ri = (rh == NULL) ? -1 : 0;
215 return ri;
216}
217
218int
4a214958 219__gnat_gethostbyaddr (const char *addr, int len, int type,
1c8e4e2e
TQ
220 struct hostent *ret, char *buf, size_t buflen,
221 int *h_errnop)
222{
223 struct hostent *rh;
224 int ri;
225
2ff555ff 226#if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
1c8e4e2e
TQ
227 (void) gethostbyaddr_r (addr, len, type, ret, buf, buflen, &rh, h_errnop);
228#else
229 rh = gethostbyaddr_r (addr, len, type, ret, buf, buflen, h_errnop);
230#endif
231 ri = (rh == NULL) ? -1 : 0;
232 return ri;
233}
234
235int
4a214958 236__gnat_getservbyname (const char *name, const char *proto,
1c8e4e2e
TQ
237 struct servent *ret, char *buf, size_t buflen)
238{
239 struct servent *rh;
240 int ri;
241
269b85b7 242#if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
1c8e4e2e
TQ
243 (void) getservbyname_r (name, proto, ret, buf, buflen, &rh);
244#else
245 rh = getservbyname_r (name, proto, ret, buf, buflen);
246#endif
247 ri = (rh == NULL) ? -1 : 0;
248 return ri;
249}
250
251int
4a214958 252__gnat_getservbyport (int port, const char *proto,
1c8e4e2e
TQ
253 struct servent *ret, char *buf, size_t buflen)
254{
255 struct servent *rh;
256 int ri;
257
269b85b7 258#if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
1c8e4e2e
TQ
259 (void) getservbyport_r (port, proto, ret, buf, buflen, &rh);
260#else
261 rh = getservbyport_r (port, proto, ret, buf, buflen);
262#endif
263 ri = (rh == NULL) ? -1 : 0;
264 return ri;
265}
4a214958
AC
266#elif defined (__vxworks)
267static char vxw_h_name[MAXHOSTNAMELEN + 1];
268static char *vxw_h_aliases[1] = { NULL };
269static int vxw_h_addr;
270static char *vxw_h_addr_list[2] = { (char*) &vxw_h_addr, NULL };
271
272int
273__gnat_gethostbyname (const char *name,
274 struct hostent *ret, char *buf, size_t buflen,
275 int *h_errnop)
276{
277 vxw_h_addr = hostGetByName (name);
278 if (vxw_h_addr == ERROR) {
279 *h_errnop = __gnat_get_h_errno ();
280 return -1;
281 }
282 ret->h_name = name;
283 ret->h_aliases = &vxw_h_aliases;
284 ret->h_addrtype = AF_INET;
285 ret->h_length = 4;
286 ret->h_addr_list = &vxw_h_addr_list;
287 return 0;
288}
289
290int
291__gnat_gethostbyaddr (const char *addr, int len, int type,
292 struct hostent *ret, char *buf, size_t buflen,
293 int *h_errnop)
294{
295 if (type != AF_INET) {
296 *h_errnop = EAFNOSUPPORT;
297 return -1;
298 }
299
300 if (addr == NULL || len != 4) {
301 *h_errnop = EINVAL;
302 return -1;
303 }
304
305 if (hostGetByAddr (*(int*)addr, &vxw_h_name) != OK) {
306 *h_errnop = __gnat_get_h_errno ();
307 return -1;
308 }
309
310 vxw_h_addr = addr;
311
312 ret->h_name = &vxw_h_name;
313 ret->h_aliases = &vxw_h_aliases;
314 ret->h_addrtype = AF_INET;
315 ret->h_length = 4;
316 ret->h_addr_list = &vxw_h_addr_list;
317}
318
319int
320__gnat_getservbyname (const char *name, const char *proto,
321 struct servent *ret, char *buf, size_t buflen)
322{
323 /* Not available under VxWorks */
324 return -1;
325}
326
327int
328__gnat_getservbyport (int port, const char *proto,
329 struct servent *ret, char *buf, size_t buflen)
330{
331 /* Not available under VxWorks */
332 return -1;
333}
334#else
335int
19ddfb31
EB
336__gnat_gethostbyname (const char *name, struct hostent *ret,
337 char *buf ATTRIBUTE_UNUSED, size_t buflen ATTRIBUTE_UNUSED,
4a214958
AC
338 int *h_errnop)
339{
340 struct hostent *rh;
341 rh = gethostbyname (name);
342 if (rh == NULL) {
343 *h_errnop = __gnat_get_h_errno ();
344 return -1;
345 }
346 *ret = *rh;
347 *h_errnop = 0;
348 return 0;
349}
350
351int
19ddfb31
EB
352__gnat_gethostbyaddr (const char *addr, int len, int type, struct hostent *ret,
353 char *buf ATTRIBUTE_UNUSED, size_t buflen ATTRIBUTE_UNUSED,
4a214958
AC
354 int *h_errnop)
355{
356 struct hostent *rh;
357 rh = gethostbyaddr (addr, len, type);
358 if (rh == NULL) {
359 *h_errnop = __gnat_get_h_errno ();
360 return -1;
361 }
362 *ret = *rh;
363 *h_errnop = 0;
364 return 0;
365}
366
367int
19ddfb31
EB
368__gnat_getservbyname (const char *name, const char *proto, struct servent *ret,
369 char *buf ATTRIBUTE_UNUSED, size_t buflen ATTRIBUTE_UNUSED)
4a214958
AC
370{
371 struct servent *rh;
372 rh = getservbyname (name, proto);
373 if (rh == NULL)
374 return -1;
375 *ret = *rh;
376 return 0;
377}
378
379int
19ddfb31
EB
380__gnat_getservbyport (int port, const char *proto, struct servent *ret,
381 char *buf ATTRIBUTE_UNUSED, size_t buflen ATTRIBUTE_UNUSED)
4a214958
AC
382{
383 struct servent *rh;
384 rh = getservbyport (port, proto);
385 if (rh == NULL)
386 return -1;
387 *ret = *rh;
388 return 0;
389}
3d3bf932 390#endif
759f1648 391
fbf5a39b
AC
392/* Find the largest socket in the socket set SET. This is needed for
393 `select'. LAST is the maximum value for the largest socket. This hint is
394 used to avoid scanning very large socket sets. On return, LAST is the
395 actual largest socket in the socket set. */
396
397void
9373164a 398__gnat_last_socket_in_set (fd_set *set, int *last)
fbf5a39b 399{
fbf5a39b
AC
400 int l;
401 l = -1;
402
3d3bf932 403#ifdef _WIN32
fbf5a39b 404 /* More efficient method for NT. */
19ddfb31 405 for (unsigned int s = 0; s < set->fd_count; s++)
fbf5a39b
AC
406 if ((int) set->fd_array[s] > l)
407 l = set->fd_array[s];
408
409#else
410
19ddfb31 411 for (int s = *last; s != -1; s--)
fbf5a39b
AC
412 if (FD_ISSET (s, set))
413 {
414 l = s;
415 break;
416 }
417#endif
418
419 *last = l;
420}
421
422/* Get last socket and remove it from the socket set SET. LAST is the
423 maximum value of the largest socket. This hint is used to avoid scanning
424 very large socket sets. On return, LAST is set to the actual largest
425 socket in the socket set. */
426
427void
9373164a 428__gnat_get_socket_from_set (fd_set *set, int *last, int *socket)
fbf5a39b
AC
429{
430 *socket = *last;
431 FD_CLR (*socket, set);
432 __gnat_last_socket_in_set (set, last);
433}
434
435/* Insert SOCKET in the socket set SET. */
436
437void
9373164a 438__gnat_insert_socket_in_set (fd_set *set, int socket)
fbf5a39b
AC
439{
440 FD_SET (socket, set);
441}
442
443/* Check whether a given SOCKET is in the socket set SET. */
444
445int
9373164a 446__gnat_is_socket_in_set (fd_set *set, int socket)
fbf5a39b
AC
447{
448 return FD_ISSET (socket, set);
449}
450
fbf5a39b
AC
451/* Remove SOCKET from the socket set SET. */
452
453void
9373164a 454__gnat_remove_socket_from_set (fd_set *set, int socket)
fbf5a39b
AC
455{
456 FD_CLR (socket, set);
457}
3e1fd98f 458
3dd9959c
AC
459/* Reset SET */
460void
461__gnat_reset_socket_set (fd_set *set)
462{
463 FD_ZERO (set);
464}
465
3e1fd98f
TQ
466/* Get the value of the last host error */
467
468int
469__gnat_get_h_errno (void) {
470#ifdef __vxworks
471 int vxw_errno = errno;
472
473 switch (vxw_errno) {
474 case 0:
475 return 0;
476
2ddc2000 477#ifdef S_hostLib_HOST_NOT_FOUND
06a16f58 478 case S_hostLib_HOST_NOT_FOUND:
2ddc2000
AC
479#endif
480 case S_hostLib_UNKNOWN_HOST:
3e1fd98f
TQ
481 return HOST_NOT_FOUND;
482
2ddc2000 483#ifdef S_hostLib_TRY_AGAIN
06a16f58 484 case S_hostLib_TRY_AGAIN:
3e1fd98f 485 return TRY_AGAIN;
2ddc2000 486#endif
3e1fd98f 487
2ddc2000 488#ifdef S_hostLib_NO_RECOVERY
06a16f58 489 case S_hostLib_NO_RECOVERY:
2ddc2000
AC
490#endif
491#ifdef S_hostLib_NETDB_INTERNAL
492 case S_hostLib_NETDB_INTERNAL:
493#endif
494 case S_hostLib_INVALID_PARAMETER:
3e1fd98f
TQ
495 return NO_RECOVERY;
496
3e1fd98f
TQ
497 default:
498 return -1;
499 }
1c8e4e2e 500
1c8e4e2e 501#elif defined (__rtems__)
04b5d587 502 /* At this stage in the tool build, no networking .h files are available.
1c8e4e2e
TQ
503 * Newlib does not provide networking .h files and RTEMS is not built yet.
504 * So we need to explicitly extern h_errno to access it.
04b5d587
JS
505 */
506 extern int h_errno;
507 return h_errno;
1c8e4e2e 508
3e1fd98f
TQ
509#else
510 return h_errno;
511#endif
512}
c80645ab 513
f26d5cd3
AC
514/* Wrapper for ioctl(2), which is a variadic function */
515
516int
6db566c3 517__gnat_socket_ioctl (int fd, IOCTL_Req_T req, int *arg) {
f26d5cd3 518#if defined (_WIN32)
19ddfb31 519 return ioctlsocket (fd, req, (unsigned long *)arg);
8cce3d75
AC
520#elif defined (__APPLE__)
521 /*
522 * On Darwin, req is an unsigned long, and we want to convert without sign
523 * extension to get the proper bit pattern in the case of a 64 bit kernel.
524 */
525 return ioctl (fd, (unsigned int) req, arg);
f26d5cd3
AC
526#else
527 return ioctl (fd, req, arg);
528#endif
529}
530
2907036d
TQ
531#ifndef HAVE_INET_PTON
532
9013065b
AC
533int
534__gnat_inet_pton (int af, const char *src, void *dst) {
535 switch (af) {
536#if defined (_WIN32) && defined (AF_INET6)
537 case AF_INET6:
538#endif
539 case AF_INET:
540 break;
541 default:
542 errno = EAFNOSUPPORT;
543 return -1;
544 }
545
2907036d 546#if defined (__vxworks)
9013065b 547 return (inet_aton (src, dst) == OK);
2907036d
TQ
548
549#elif defined (_WIN32)
9013065b
AC
550 struct sockaddr_storage ss;
551 int sslen = sizeof ss;
552 int rc;
553
554 ss.ss_family = af;
19ddfb31
EB
555 rc = WSAStringToAddressA ((char *)src, af, NULL, (struct sockaddr *)&ss,
556 &sslen);
d5063351 557 if (rc == 0) {
9013065b
AC
558 switch (af) {
559 case AF_INET:
560 *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
561 break;
562#ifdef AF_INET6
563 case AF_INET6:
564 *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
565 break;
566#endif
567 }
568 }
d5063351 569 return (rc == 0);
2907036d 570
e08add8e 571#elif defined (__hpux__)
2907036d
TQ
572 in_addr_t addr;
573 int rc = -1;
574
575 if (src == NULL || dst == NULL) {
576 errno = EINVAL;
577
578 } else if (!strcmp (src, "255.255.255.255")) {
579 addr = 0xffffffff;
580 rc = 1;
581
582 } else {
583 addr = inet_addr (src);
584 rc = (addr != 0xffffffff);
585 }
586 if (rc == 1) {
587 *(in_addr_t *)dst = addr;
588 }
589 return rc;
9013065b
AC
590#endif
591}
592#endif
593
759f1648
DA
594#ifndef HAVE_INET_NTOP
595
596const char *
597__gnat_inet_ntop(int af, const void *src, char *dst, socklen_t size)
598{
599#ifdef _WIN32
600 struct sockaddr_storage ss;
601 int sslen = sizeof ss;
602 memset(&ss, 0, sslen);
603 ss.ss_family = af;
604
605 switch (af) {
606 case AF_INET6:
607 ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
608 break;
609 case AF_INET:
610 ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
611 break;
612 default:
613 errno = EAFNOSUPPORT;
614 return NULL;
615 }
616
617 DWORD sz = size;
618
619 if (WSAAddressToStringA((struct sockaddr*)&ss, sslen, 0, dst, &sz) != 0) {
620 return NULL;
621 }
622 return dst;
623#else
624 return NULL;
625#endif
626}
627#endif
628
4a214958
AC
629/*
630 * Accessor functions for struct hostent.
631 */
632
633char * __gnat_hostent_h_name (struct hostent * h) {
634 return h->h_name;
635}
636
637char * __gnat_hostent_h_alias (struct hostent * h, int index) {
638 return h->h_aliases[index];
639}
640
641int __gnat_hostent_h_addrtype (struct hostent * h) {
642 return h->h_addrtype;
643}
644
645int __gnat_hostent_h_length (struct hostent * h) {
646 return h->h_length;
647}
648
649char * __gnat_hostent_h_addr (struct hostent * h, int index) {
650 return h->h_addr_list[index];
651}
652
1dfddbb4
AC
653/*
654 * Accessor functions for struct servent.
655 *
656 * These are needed because servent has different representations on different
657 * platforms, and we don't want to deal with that on the Ada side. For example,
658 * on Linux, we have (see /usr/include netdb.h):
659 *
660 * struct servent
661 * {
662 * char *s_name;
663 * char **s_aliases;
664 * int s_port;
665 * char *s_proto;
666 * };
667 *
668 * and on Windows (see mingw's socket.h):
669 *
670 * struct servent {
671 * char *s_name;
672 * char **s_aliases;
673 * #ifdef _WIN64
674 * char *s_proto;
675 * short s_port;
676 * #else
677 * short s_port;
678 * char *s_proto;
679 * #endif
680 * };
681 */
682
683char *
684__gnat_servent_s_name (struct servent * s)
685{
686 return s->s_name;
687}
688
4a214958
AC
689char *
690__gnat_servent_s_alias (struct servent * s, int index)
1dfddbb4 691{
4a214958 692 return s->s_aliases[index];
1dfddbb4
AC
693}
694
4a214958 695unsigned short
1dfddbb4
AC
696__gnat_servent_s_port (struct servent * s)
697{
698 return s->s_port;
699}
700
701char *
702__gnat_servent_s_proto (struct servent * s)
703{
704 return s->s_proto;
705}
706
759f1648
DA
707#if defined(AF_INET6) && !defined(__rtems__)
708
759f1648
DA
709int __gnat_getaddrinfo(
710 const char *node,
711 const char *service,
712 const struct addrinfo *hints,
713 struct addrinfo **res)
714{
715 return getaddrinfo(node, service, hints, res);
716}
717
718int __gnat_getnameinfo(
719 const struct sockaddr *sa, socklen_t salen,
720 char *host, size_t hostlen,
721 char *serv, size_t servlen, int flags)
722{
723 return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
724}
725
726void __gnat_freeaddrinfo(struct addrinfo *res) {
727 freeaddrinfo(res);
728}
729
730const char * __gnat_gai_strerror(int errcode) {
731#if defined(_WIN32) || defined(__vxworks)
732 // gai_strerror thread usafe on Windows and is not available on some vxWorks
733 // versions
734
735 switch (errcode) {
736 case EAI_AGAIN:
737 return "Temporary failure in name resolution.";
738 case EAI_BADFLAGS:
739 return "Invalid value for ai_flags.";
740 case EAI_FAIL:
741 return "Nonrecoverable failure in name resolution.";
742 case EAI_FAMILY:
743 return "The ai_family member is not supported.";
744 case EAI_MEMORY:
745 return "Memory allocation failure.";
746#ifdef EAI_NODATA
747 // Could be not defined under the vxWorks
748 case EAI_NODATA:
749 return "No address associated with nodename.";
750#endif
751#if EAI_NODATA != EAI_NONAME
752 /* with mingw64 runtime EAI_NODATA and EAI_NONAME have the same value.
753 This applies to both win32 and win64 */
754 case EAI_NONAME:
755 return "Neither nodename nor servname provided, or not known.";
756#endif
757 case EAI_SERVICE:
758 return "The servname parameter is not supported for ai_socktype.";
759 case EAI_SOCKTYPE:
760 return "The ai_socktype member is not supported.";
761#ifdef EAI_SYSTEM
762 // Could be not defined, at least on Windows
763 case EAI_SYSTEM:
764 return "System error returned in errno";
765#endif
766 default:
767 return "Unknown error.";
768 }
769#else
770 return gai_strerror(errcode);
771#endif
772}
773
774#else
775
776int __gnat_getaddrinfo(
777 const char *node,
778 const char *service,
779 const struct addrinfo *hints,
780 struct addrinfo **res)
781{
782 return -1;
783}
784
785int __gnat_getnameinfo(
786 const struct sockaddr *sa, socklen_t salen,
787 char *host, size_t hostlen,
788 char *serv, size_t servlen, int flags)
789{
790 return -1;
791}
792
793void __gnat_freeaddrinfo(struct addrinfo *res) {
794}
795
796const char * __gnat_gai_strerror(int errcode) {
797 return "getaddinfo functions family is not supported";
798}
799
800#endif
801
b7d5159e
DA
802int __gnat_minus_500ms() {
803#if defined (_WIN32)
e2b7399e
DA
804 // Windows Server 2019 and Windows 8.0 do not need 500 millisecond socket
805 // timeout correction.
806 if (IsWindowsServer()) {
807 OSVERSIONINFO osvi;
808 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
809 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
810 // Documentation proposes to use IsWindowsVersionOrGreater(10, 0, 17763)
6c8b9020 811 // but it does not compare by the build number (last parameter).
e2b7399e
DA
812 GetVersionEx(&osvi);
813 return osvi.dwMajorVersion < 10
6c8b9020
DA
814 || (osvi.dwMajorVersion == 10
815 && osvi.dwMinorVersion == 0
816 && osvi.dwBuildNumber < 17763);
e2b7399e
DA
817 } else {
818 return !IsWindows8OrGreater();
819 }
b7d5159e 820#else
e2b7399e 821 return 0;
b7d5159e
DA
822#endif
823}
824
c80645ab 825#endif /* defined(HAVE_SOCKETS) */