111
|
1 /****************************************************************************
|
|
2 * *
|
|
3 * GNAT COMPILER COMPONENTS *
|
|
4 * *
|
|
5 * S O C K E T *
|
|
6 * *
|
|
7 * C Implementation File *
|
|
8 * *
|
145
|
9 * Copyright (C) 2003-2019, Free Software Foundation, Inc. *
|
111
|
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- *
|
|
13 * ware Foundation; either version 3, or (at your option) any later ver- *
|
|
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 *
|
|
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/>. *
|
|
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
|
|
32 /* This file provides a portable binding to the sockets API */
|
|
33
|
131
|
34 #define ATTRIBUTE_UNUSED __attribute__((unused))
|
|
35
|
111
|
36 /* Ensure access to errno is thread safe. */
|
145
|
37 #ifndef _REENTRANT
|
111
|
38 #define _REENTRANT
|
145
|
39 #endif
|
111
|
40 #define _THREAD_SAFE
|
|
41
|
|
42 #include "gsocket.h"
|
|
43
|
|
44 #if defined (__FreeBSD__) || defined (__DragonFly__) \
|
|
45 || defined (__NetBSD__) || defined (__OpenBSD__)
|
|
46 typedef unsigned int IOCTL_Req_T;
|
|
47 #else
|
|
48 typedef int IOCTL_Req_T;
|
|
49 #endif
|
|
50
|
|
51 #if defined(HAVE_SOCKETS)
|
|
52
|
|
53 /* Include all the necessary system-specific headers and define the
|
|
54 * necessary macros (shared with gen-oscons).
|
|
55 */
|
|
56
|
|
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
|
|
62 #include "raise.h"
|
|
63 /* Required for __gnat_malloc() */
|
|
64
|
|
65 #include <string.h>
|
|
66 /* Required for memcpy() */
|
|
67
|
|
68 extern void __gnat_disable_sigpipe (int fd);
|
|
69 extern void __gnat_disable_all_sigpipes (void);
|
|
70 extern int __gnat_create_signalling_fds (int *fds);
|
|
71 extern int __gnat_read_signalling_fd (int rsig);
|
|
72 extern int __gnat_write_signalling_fd (int wsig);
|
|
73 extern void __gnat_close_signalling_fd (int sig);
|
|
74 extern void __gnat_last_socket_in_set (fd_set *, int *);
|
|
75 extern void __gnat_get_socket_from_set (fd_set *, int *, int *);
|
|
76 extern void __gnat_insert_socket_in_set (fd_set *, int);
|
|
77 extern int __gnat_is_socket_in_set (fd_set *, int);
|
|
78 extern fd_set *__gnat_new_socket_set (fd_set *);
|
|
79 extern void __gnat_remove_socket_from_set (fd_set *, int);
|
|
80 extern void __gnat_reset_socket_set (fd_set *);
|
|
81 extern int __gnat_get_h_errno (void);
|
|
82 extern int __gnat_socket_ioctl (int, IOCTL_Req_T, int *);
|
|
83
|
|
84 extern char * __gnat_servent_s_name (struct servent *);
|
|
85 extern char * __gnat_servent_s_alias (struct servent *, int index);
|
|
86 extern unsigned short __gnat_servent_s_port (struct servent *);
|
|
87 extern char * __gnat_servent_s_proto (struct servent *);
|
|
88
|
|
89 extern char * __gnat_hostent_h_name (struct hostent *);
|
|
90 extern char * __gnat_hostent_h_alias (struct hostent *, int);
|
|
91 extern int __gnat_hostent_h_addrtype (struct hostent *);
|
|
92 extern int __gnat_hostent_h_length (struct hostent *);
|
|
93 extern char * __gnat_hostent_h_addr (struct hostent *, int);
|
|
94
|
145
|
95 extern int __gnat_getaddrinfo(
|
|
96 const char *node,
|
|
97 const char *service,
|
|
98 const struct addrinfo *hints,
|
|
99 struct addrinfo **res);
|
|
100 int __gnat_getnameinfo(
|
|
101 const struct sockaddr *sa, socklen_t salen,
|
|
102 char *host, size_t hostlen,
|
|
103 char *serv, size_t servlen, int flags);
|
|
104 extern void __gnat_freeaddrinfo(struct addrinfo *res);
|
|
105 extern const char * __gnat_gai_strerror(int errcode);
|
|
106
|
111
|
107 #ifndef HAVE_INET_PTON
|
|
108 extern int __gnat_inet_pton (int, const char *, void *);
|
|
109 #endif
|
145
|
110
|
|
111 #ifndef HAVE_INET_NTOP
|
|
112 extern const char *
|
|
113 __gnat_inet_ntop(int, const void *, char *, socklen_t);
|
|
114 #endif
|
|
115
|
111
|
116 /* Disable the sending of SIGPIPE for writes on a broken stream */
|
|
117
|
|
118 void
|
131
|
119 __gnat_disable_sigpipe (int fd ATTRIBUTE_UNUSED)
|
111
|
120 {
|
|
121 #ifdef SO_NOSIGPIPE
|
|
122 int val = 1;
|
|
123 (void) setsockopt (fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof val);
|
|
124 #endif
|
|
125 }
|
|
126
|
|
127 void
|
|
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 }
|
145
|
134
|
111
|
135 #if defined (_WIN32) || defined (__vxworks)
|
|
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 */
|
|
146 int
|
|
147 __gnat_create_signalling_fds (int *fds) {
|
|
148 return pipe (fds);
|
|
149 }
|
145
|
150
|
111
|
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 */
|
|
155 int
|
|
156 __gnat_read_signalling_fd (int rsig) {
|
|
157 char c;
|
|
158 return read (rsig, &c, 1);
|
|
159 }
|
145
|
160
|
111
|
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 */
|
|
165 int
|
|
166 __gnat_write_signalling_fd (int wsig) {
|
|
167 char c = 0;
|
|
168 return write (wsig, &c, 1);
|
|
169 }
|
145
|
170
|
111
|
171 /*
|
|
172 * Close one end of a pair of signalling fds
|
|
173 */
|
|
174 void
|
|
175 __gnat_close_signalling_fd (int sig) {
|
|
176 (void) close (sig);
|
|
177 }
|
|
178 #endif
|
145
|
179
|
111
|
180 /*
|
|
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.
|
|
189 *
|
|
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.
|
|
198 */
|
|
199
|
|
200 #ifdef HAVE_GETxxxBYyyy_R
|
|
201 int
|
|
202 __gnat_gethostbyname (const char *name,
|
|
203 struct hostent *ret, char *buf, size_t buflen,
|
|
204 int *h_errnop)
|
|
205 {
|
|
206 struct hostent *rh;
|
|
207 int ri;
|
|
208
|
|
209 #if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
|
|
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
|
|
218 int
|
|
219 __gnat_gethostbyaddr (const char *addr, int len, int type,
|
|
220 struct hostent *ret, char *buf, size_t buflen,
|
|
221 int *h_errnop)
|
|
222 {
|
|
223 struct hostent *rh;
|
|
224 int ri;
|
|
225
|
|
226 #if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
|
|
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
|
|
235 int
|
|
236 __gnat_getservbyname (const char *name, const char *proto,
|
|
237 struct servent *ret, char *buf, size_t buflen)
|
|
238 {
|
|
239 struct servent *rh;
|
|
240 int ri;
|
|
241
|
|
242 #if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
|
|
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
|
|
251 int
|
|
252 __gnat_getservbyport (int port, const char *proto,
|
|
253 struct servent *ret, char *buf, size_t buflen)
|
|
254 {
|
|
255 struct servent *rh;
|
|
256 int ri;
|
|
257
|
|
258 #if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
|
|
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 }
|
|
266 #elif defined (__vxworks)
|
|
267 static char vxw_h_name[MAXHOSTNAMELEN + 1];
|
|
268 static char *vxw_h_aliases[1] = { NULL };
|
|
269 static int vxw_h_addr;
|
|
270 static char *vxw_h_addr_list[2] = { (char*) &vxw_h_addr, NULL };
|
|
271
|
|
272 int
|
|
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
|
|
290 int
|
|
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
|
|
319 int
|
|
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
|
|
327 int
|
|
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
|
|
335 int
|
|
336 __gnat_gethostbyname (const char *name,
|
|
337 struct hostent *ret, char *buf, size_t buflen,
|
|
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
|
|
351 int
|
|
352 __gnat_gethostbyaddr (const char *addr, int len, int type,
|
|
353 struct hostent *ret, char *buf, size_t buflen,
|
|
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
|
|
367 int
|
|
368 __gnat_getservbyname (const char *name, const char *proto,
|
|
369 struct servent *ret, char *buf, size_t buflen)
|
|
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
|
|
379 int
|
|
380 __gnat_getservbyport (int port, const char *proto,
|
|
381 struct servent *ret, char *buf, size_t buflen)
|
|
382 {
|
|
383 struct servent *rh;
|
|
384 rh = getservbyport (port, proto);
|
|
385 if (rh == NULL)
|
|
386 return -1;
|
|
387 *ret = *rh;
|
|
388 return 0;
|
|
389 }
|
|
390 #endif
|
145
|
391
|
111
|
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
|
|
397 void
|
|
398 __gnat_last_socket_in_set (fd_set *set, int *last)
|
|
399 {
|
|
400 int s;
|
|
401 int l;
|
|
402 l = -1;
|
|
403
|
|
404 #ifdef _WIN32
|
|
405 /* More efficient method for NT. */
|
|
406 for (s = 0; s < set->fd_count; s++)
|
|
407 if ((int) set->fd_array[s] > l)
|
|
408 l = set->fd_array[s];
|
|
409
|
|
410 #else
|
|
411
|
|
412 for (s = *last; s != -1; s--)
|
|
413 if (FD_ISSET (s, set))
|
|
414 {
|
|
415 l = s;
|
|
416 break;
|
|
417 }
|
|
418 #endif
|
|
419
|
|
420 *last = l;
|
|
421 }
|
|
422
|
|
423 /* Get last socket and remove it from the socket set SET. LAST is the
|
|
424 maximum value of the largest socket. This hint is used to avoid scanning
|
|
425 very large socket sets. On return, LAST is set to the actual largest
|
|
426 socket in the socket set. */
|
|
427
|
|
428 void
|
|
429 __gnat_get_socket_from_set (fd_set *set, int *last, int *socket)
|
|
430 {
|
|
431 *socket = *last;
|
|
432 FD_CLR (*socket, set);
|
|
433 __gnat_last_socket_in_set (set, last);
|
|
434 }
|
|
435
|
|
436 /* Insert SOCKET in the socket set SET. */
|
|
437
|
|
438 void
|
|
439 __gnat_insert_socket_in_set (fd_set *set, int socket)
|
|
440 {
|
|
441 FD_SET (socket, set);
|
|
442 }
|
|
443
|
|
444 /* Check whether a given SOCKET is in the socket set SET. */
|
|
445
|
|
446 int
|
|
447 __gnat_is_socket_in_set (fd_set *set, int socket)
|
|
448 {
|
|
449 return FD_ISSET (socket, set);
|
|
450 }
|
|
451
|
|
452 /* Remove SOCKET from the socket set SET. */
|
|
453
|
|
454 void
|
|
455 __gnat_remove_socket_from_set (fd_set *set, int socket)
|
|
456 {
|
|
457 FD_CLR (socket, set);
|
|
458 }
|
|
459
|
|
460 /* Reset SET */
|
|
461 void
|
|
462 __gnat_reset_socket_set (fd_set *set)
|
|
463 {
|
|
464 FD_ZERO (set);
|
|
465 }
|
|
466
|
|
467 /* Get the value of the last host error */
|
|
468
|
|
469 int
|
|
470 __gnat_get_h_errno (void) {
|
|
471 #ifdef __vxworks
|
|
472 int vxw_errno = errno;
|
|
473
|
|
474 switch (vxw_errno) {
|
|
475 case 0:
|
|
476 return 0;
|
|
477
|
|
478 #ifdef S_hostLib_HOST_NOT_FOUND
|
|
479 case S_hostLib_HOST_NOT_FOUND:
|
|
480 #endif
|
|
481 case S_hostLib_UNKNOWN_HOST:
|
|
482 return HOST_NOT_FOUND;
|
|
483
|
|
484 #ifdef S_hostLib_TRY_AGAIN
|
|
485 case S_hostLib_TRY_AGAIN:
|
|
486 return TRY_AGAIN;
|
|
487 #endif
|
|
488
|
|
489 #ifdef S_hostLib_NO_RECOVERY
|
|
490 case S_hostLib_NO_RECOVERY:
|
|
491 #endif
|
|
492 #ifdef S_hostLib_NETDB_INTERNAL
|
|
493 case S_hostLib_NETDB_INTERNAL:
|
|
494 #endif
|
|
495 case S_hostLib_INVALID_PARAMETER:
|
|
496 return NO_RECOVERY;
|
|
497
|
|
498 default:
|
|
499 return -1;
|
|
500 }
|
|
501
|
|
502 #elif defined (__rtems__)
|
|
503 /* At this stage in the tool build, no networking .h files are available.
|
|
504 * Newlib does not provide networking .h files and RTEMS is not built yet.
|
|
505 * So we need to explicitly extern h_errno to access it.
|
|
506 */
|
|
507 extern int h_errno;
|
|
508 return h_errno;
|
|
509
|
|
510 #else
|
|
511 return h_errno;
|
|
512 #endif
|
|
513 }
|
|
514
|
|
515 /* Wrapper for ioctl(2), which is a variadic function */
|
|
516
|
|
517 int
|
|
518 __gnat_socket_ioctl (int fd, IOCTL_Req_T req, int *arg) {
|
|
519 #if defined (_WIN32)
|
|
520 return ioctlsocket (fd, req, arg);
|
|
521 #elif defined (__APPLE__)
|
|
522 /*
|
|
523 * On Darwin, req is an unsigned long, and we want to convert without sign
|
|
524 * extension to get the proper bit pattern in the case of a 64 bit kernel.
|
|
525 */
|
|
526 return ioctl (fd, (unsigned int) req, arg);
|
|
527 #else
|
|
528 return ioctl (fd, req, arg);
|
|
529 #endif
|
|
530 }
|
|
531
|
|
532 #ifndef HAVE_INET_PTON
|
|
533
|
|
534 int
|
|
535 __gnat_inet_pton (int af, const char *src, void *dst) {
|
|
536 switch (af) {
|
|
537 #if defined (_WIN32) && defined (AF_INET6)
|
|
538 case AF_INET6:
|
|
539 #endif
|
|
540 case AF_INET:
|
|
541 break;
|
|
542 default:
|
|
543 errno = EAFNOSUPPORT;
|
|
544 return -1;
|
|
545 }
|
|
546
|
|
547 #if defined (__vxworks)
|
|
548 return (inet_aton (src, dst) == OK);
|
|
549
|
|
550 #elif defined (_WIN32)
|
|
551 struct sockaddr_storage ss;
|
|
552 int sslen = sizeof ss;
|
|
553 int rc;
|
|
554
|
|
555 ss.ss_family = af;
|
|
556 rc = WSAStringToAddressA (src, af, NULL, (struct sockaddr *)&ss, &sslen);
|
|
557 if (rc == 0) {
|
|
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 }
|
|
569 return (rc == 0);
|
|
570
|
|
571 #elif defined (__hpux__)
|
|
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;
|
|
590 #endif
|
|
591 }
|
|
592 #endif
|
|
593
|
145
|
594 #ifndef HAVE_INET_NTOP
|
|
595
|
|
596 const 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
|
111
|
629 /*
|
|
630 * Accessor functions for struct hostent.
|
|
631 */
|
|
632
|
|
633 char * __gnat_hostent_h_name (struct hostent * h) {
|
|
634 return h->h_name;
|
|
635 }
|
|
636
|
|
637 char * __gnat_hostent_h_alias (struct hostent * h, int index) {
|
|
638 return h->h_aliases[index];
|
|
639 }
|
|
640
|
|
641 int __gnat_hostent_h_addrtype (struct hostent * h) {
|
|
642 return h->h_addrtype;
|
|
643 }
|
|
644
|
|
645 int __gnat_hostent_h_length (struct hostent * h) {
|
|
646 return h->h_length;
|
|
647 }
|
|
648
|
|
649 char * __gnat_hostent_h_addr (struct hostent * h, int index) {
|
|
650 return h->h_addr_list[index];
|
|
651 }
|
|
652
|
|
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
|
|
683 char *
|
|
684 __gnat_servent_s_name (struct servent * s)
|
|
685 {
|
|
686 return s->s_name;
|
|
687 }
|
|
688
|
|
689 char *
|
|
690 __gnat_servent_s_alias (struct servent * s, int index)
|
|
691 {
|
|
692 return s->s_aliases[index];
|
|
693 }
|
|
694
|
|
695 unsigned short
|
|
696 __gnat_servent_s_port (struct servent * s)
|
|
697 {
|
|
698 return s->s_port;
|
|
699 }
|
|
700
|
|
701 char *
|
|
702 __gnat_servent_s_proto (struct servent * s)
|
|
703 {
|
|
704 return s->s_proto;
|
|
705 }
|
|
706
|
145
|
707 #if defined(AF_INET6) && !defined(__rtems__)
|
|
708
|
|
709 int __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
|
|
718 int __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
|
|
726 void __gnat_freeaddrinfo(struct addrinfo *res) {
|
|
727 freeaddrinfo(res);
|
|
728 }
|
|
729
|
|
730 const 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
|
|
776 int __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
|
|
785 int __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
|
|
793 void __gnat_freeaddrinfo(struct addrinfo *res) {
|
|
794 }
|
|
795
|
|
796 const char * __gnat_gai_strerror(int errcode) {
|
|
797 return "getaddinfo functions family is not supported";
|
|
798 }
|
|
799
|
|
800 #endif
|
|
801
|
|
802 int __gnat_minus_500ms() {
|
|
803 #if defined (_WIN32)
|
|
804 // Windows Server 2019 and Windows 8.0 do not need 500 millisecond socket
|
|
805 // timeout correction.
|
|
806 return !(IsWindows8OrGreater() && !IsWindowsServer()
|
|
807 || IsWindowsVersionOrGreater(10, 0, 17763));
|
|
808 #else
|
|
809 return 0;
|
|
810 #endif
|
|
811 }
|
|
812
|
111
|
813 #endif /* defined(HAVE_SOCKETS) */
|