]>
Commit | Line | Data |
---|---|---|
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 |
46 | typedef unsigned int IOCTL_Req_T; |
47 | #else | |
48 | typedef 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 | 68 | extern void __gnat_disable_sigpipe (int fd); |
3d3bf932 TQ |
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); | |
1c8e4e2e | 73 | extern void __gnat_close_signalling_fd (int sig); |
9373164a KC |
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); | |
9013065b | 80 | extern void __gnat_reset_socket_set (fd_set *); |
3d3bf932 | 81 | extern int __gnat_get_h_errno (void); |
6db566c3 | 82 | extern int __gnat_socket_ioctl (int, IOCTL_Req_T, int *); |
4a214958 | 83 | |
1dfddbb4 | 84 | extern char * __gnat_servent_s_name (struct servent *); |
4a214958 AC |
85 | extern char * __gnat_servent_s_alias (struct servent *, int index); |
86 | extern unsigned short __gnat_servent_s_port (struct servent *); | |
1dfddbb4 | 87 | extern char * __gnat_servent_s_proto (struct servent *); |
4a214958 AC |
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 | ||
759f1648 DA |
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 | ||
3a13e785 | 107 | #ifndef HAVE_INET_PTON |
9013065b AC |
108 | extern int __gnat_inet_pton (int, const char *, void *); |
109 | #endif | |
759f1648 DA |
110 | |
111 | #ifndef HAVE_INET_NTOP | |
112 | extern 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 | 118 | void |
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 |
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 | } | |
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 | */ | |
146 | int | |
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 | */ | |
155 | int | |
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 | */ | |
165 | int | |
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 | */ | |
174 | void | |
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 | 201 | int |
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 | ||
218 | int | |
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 | ||
235 | int | |
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 | ||
251 | int | |
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) |
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 | |
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 | ||
351 | int | |
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 | ||
367 | int | |
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 | ||
379 | int | |
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 | ||
397 | void | |
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 | ||
427 | void | |
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 | ||
437 | void | |
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 | ||
445 | int | |
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 | ||
453 | void | |
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 */ |
460 | void | |
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 | ||
468 | int | |
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 | ||
516 | int | |
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 |
533 | int |
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 | ||
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 | ||
4a214958 AC |
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 | ||
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 | ||
683 | char * | |
684 | __gnat_servent_s_name (struct servent * s) | |
685 | { | |
686 | return s->s_name; | |
687 | } | |
688 | ||
4a214958 AC |
689 | char * |
690 | __gnat_servent_s_alias (struct servent * s, int index) | |
1dfddbb4 | 691 | { |
4a214958 | 692 | return s->s_aliases[index]; |
1dfddbb4 AC |
693 | } |
694 | ||
4a214958 | 695 | unsigned short |
1dfddbb4 AC |
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 | ||
759f1648 DA |
707 | #if defined(AF_INET6) && !defined(__rtems__) |
708 | ||
759f1648 DA |
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 | ||
b7d5159e DA |
802 | int __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) */ |