111
|
1 /****************************************************************************
|
|
2 * *
|
|
3 * GNAT COMPILER COMPONENTS *
|
|
4 * *
|
|
5 * S O C K E T *
|
|
6 * *
|
|
7 * C Implementation File *
|
|
8 * *
|
131
|
9 * Copyright (C) 2003-2018, 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. */
|
|
37 #define _REENTRANT
|
|
38 #define _THREAD_SAFE
|
|
39
|
|
40 #include "gsocket.h"
|
|
41
|
|
42 #if defined (__FreeBSD__) || defined (__DragonFly__) \
|
|
43 || defined (__NetBSD__) || defined (__OpenBSD__)
|
|
44 typedef unsigned int IOCTL_Req_T;
|
|
45 #else
|
|
46 typedef int IOCTL_Req_T;
|
|
47 #endif
|
|
48
|
|
49 #if defined(HAVE_SOCKETS)
|
|
50
|
|
51 /* Include all the necessary system-specific headers and define the
|
|
52 * necessary macros (shared with gen-oscons).
|
|
53 */
|
|
54
|
|
55 #if !defined(SO_NOSIGPIPE) && !defined (MSG_NOSIGNAL)
|
|
56 #include <signal.h>
|
|
57 #endif
|
|
58 /* Required if we will be calling signal() in __gnat_disable_all_sigpipes() */
|
|
59
|
|
60 #include "raise.h"
|
|
61 /* Required for __gnat_malloc() */
|
|
62
|
|
63 #include <string.h>
|
|
64 /* Required for memcpy() */
|
|
65
|
|
66 extern void __gnat_disable_sigpipe (int fd);
|
|
67 extern void __gnat_disable_all_sigpipes (void);
|
|
68 extern int __gnat_create_signalling_fds (int *fds);
|
|
69 extern int __gnat_read_signalling_fd (int rsig);
|
|
70 extern int __gnat_write_signalling_fd (int wsig);
|
|
71 extern void __gnat_close_signalling_fd (int sig);
|
|
72 extern void __gnat_last_socket_in_set (fd_set *, int *);
|
|
73 extern void __gnat_get_socket_from_set (fd_set *, int *, int *);
|
|
74 extern void __gnat_insert_socket_in_set (fd_set *, int);
|
|
75 extern int __gnat_is_socket_in_set (fd_set *, int);
|
|
76 extern fd_set *__gnat_new_socket_set (fd_set *);
|
|
77 extern void __gnat_remove_socket_from_set (fd_set *, int);
|
|
78 extern void __gnat_reset_socket_set (fd_set *);
|
|
79 extern int __gnat_get_h_errno (void);
|
|
80 extern int __gnat_socket_ioctl (int, IOCTL_Req_T, int *);
|
|
81
|
|
82 extern char * __gnat_servent_s_name (struct servent *);
|
|
83 extern char * __gnat_servent_s_alias (struct servent *, int index);
|
|
84 extern unsigned short __gnat_servent_s_port (struct servent *);
|
|
85 extern char * __gnat_servent_s_proto (struct servent *);
|
|
86
|
|
87 extern char * __gnat_hostent_h_name (struct hostent *);
|
|
88 extern char * __gnat_hostent_h_alias (struct hostent *, int);
|
|
89 extern int __gnat_hostent_h_addrtype (struct hostent *);
|
|
90 extern int __gnat_hostent_h_length (struct hostent *);
|
|
91 extern char * __gnat_hostent_h_addr (struct hostent *, int);
|
|
92
|
|
93 #ifndef HAVE_INET_PTON
|
|
94 extern int __gnat_inet_pton (int, const char *, void *);
|
|
95 #endif
|
|
96
|
|
97 /* Disable the sending of SIGPIPE for writes on a broken stream */
|
|
98
|
|
99 void
|
131
|
100 __gnat_disable_sigpipe (int fd ATTRIBUTE_UNUSED)
|
111
|
101 {
|
|
102 #ifdef SO_NOSIGPIPE
|
|
103 int val = 1;
|
|
104 (void) setsockopt (fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof val);
|
|
105 #endif
|
|
106 }
|
|
107
|
|
108 void
|
|
109 __gnat_disable_all_sigpipes (void)
|
|
110 {
|
|
111 #if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) && defined(SIGPIPE)
|
|
112 (void) signal (SIGPIPE, SIG_IGN);
|
|
113 #endif
|
|
114 }
|
|
115
|
|
116 #if defined (_WIN32) || defined (__vxworks)
|
|
117 /*
|
|
118 * Signalling FDs operations are implemented in Ada for these platforms
|
|
119 * (see subunit GNAT.Sockets.Thin.Signalling_Fds).
|
|
120 */
|
|
121 #else
|
|
122 /*
|
|
123 * Create a pair of connected file descriptors fds[0] and fds[1] used for
|
|
124 * signalling by a Selector object. fds[0] is the read end, and fds[1] the
|
|
125 * write end.
|
|
126 */
|
|
127 int
|
|
128 __gnat_create_signalling_fds (int *fds) {
|
|
129 return pipe (fds);
|
|
130 }
|
|
131
|
|
132 /*
|
|
133 * Read one byte of data from rsig, the read end of a pair of signalling fds
|
|
134 * created by __gnat_create_signalling_fds.
|
|
135 */
|
|
136 int
|
|
137 __gnat_read_signalling_fd (int rsig) {
|
|
138 char c;
|
|
139 return read (rsig, &c, 1);
|
|
140 }
|
|
141
|
|
142 /*
|
|
143 * Write one byte of data to wsig, the write end of a pair of signalling fds
|
|
144 * created by __gnat_create_signalling_fds.
|
|
145 */
|
|
146 int
|
|
147 __gnat_write_signalling_fd (int wsig) {
|
|
148 char c = 0;
|
|
149 return write (wsig, &c, 1);
|
|
150 }
|
|
151
|
|
152 /*
|
|
153 * Close one end of a pair of signalling fds
|
|
154 */
|
|
155 void
|
|
156 __gnat_close_signalling_fd (int sig) {
|
|
157 (void) close (sig);
|
|
158 }
|
|
159 #endif
|
|
160
|
|
161 /*
|
|
162 * Handling of gethostbyname, gethostbyaddr, getservbyname and getservbyport
|
|
163 * =========================================================================
|
|
164 *
|
|
165 * This module exposes __gnat_getXXXbyYYY operations with the same signature
|
|
166 * as the reentrant variant getXXXbyYYY_r.
|
|
167 *
|
|
168 * On platforms where getXXXbyYYY is intrinsically reentrant, the provided user
|
|
169 * buffer argument is ignored.
|
|
170 *
|
|
171 * When getXXXbyYYY is not reentrant but getXXXbyYYY_r exists, the latter is
|
|
172 * used, and the provided buffer argument must point to a valid, thread-local
|
|
173 * buffer (usually on the caller's stack).
|
|
174 *
|
|
175 * When getXXXbyYYY is not reentrant and no reentrant getXXXbyYYY_r variant
|
|
176 * is available, the non-reentrant getXXXbyYYY is called, the provided user
|
|
177 * buffer is ignored, and the caller is expected to take care of mutual
|
|
178 * exclusion.
|
|
179 */
|
|
180
|
|
181 #ifdef HAVE_GETxxxBYyyy_R
|
|
182 int
|
|
183 __gnat_gethostbyname (const char *name,
|
|
184 struct hostent *ret, char *buf, size_t buflen,
|
|
185 int *h_errnop)
|
|
186 {
|
|
187 struct hostent *rh;
|
|
188 int ri;
|
|
189
|
|
190 #if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
|
|
191 (void) gethostbyname_r (name, ret, buf, buflen, &rh, h_errnop);
|
|
192 #else
|
|
193 rh = gethostbyname_r (name, ret, buf, buflen, h_errnop);
|
|
194 #endif
|
|
195 ri = (rh == NULL) ? -1 : 0;
|
|
196 return ri;
|
|
197 }
|
|
198
|
|
199 int
|
|
200 __gnat_gethostbyaddr (const char *addr, int len, int type,
|
|
201 struct hostent *ret, char *buf, size_t buflen,
|
|
202 int *h_errnop)
|
|
203 {
|
|
204 struct hostent *rh;
|
|
205 int ri;
|
|
206
|
|
207 #if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
|
|
208 (void) gethostbyaddr_r (addr, len, type, ret, buf, buflen, &rh, h_errnop);
|
|
209 #else
|
|
210 rh = gethostbyaddr_r (addr, len, type, ret, buf, buflen, h_errnop);
|
|
211 #endif
|
|
212 ri = (rh == NULL) ? -1 : 0;
|
|
213 return ri;
|
|
214 }
|
|
215
|
|
216 int
|
|
217 __gnat_getservbyname (const char *name, const char *proto,
|
|
218 struct servent *ret, char *buf, size_t buflen)
|
|
219 {
|
|
220 struct servent *rh;
|
|
221 int ri;
|
|
222
|
|
223 #if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
|
|
224 (void) getservbyname_r (name, proto, ret, buf, buflen, &rh);
|
|
225 #else
|
|
226 rh = getservbyname_r (name, proto, ret, buf, buflen);
|
|
227 #endif
|
|
228 ri = (rh == NULL) ? -1 : 0;
|
|
229 return ri;
|
|
230 }
|
|
231
|
|
232 int
|
|
233 __gnat_getservbyport (int port, const char *proto,
|
|
234 struct servent *ret, char *buf, size_t buflen)
|
|
235 {
|
|
236 struct servent *rh;
|
|
237 int ri;
|
|
238
|
|
239 #if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
|
|
240 (void) getservbyport_r (port, proto, ret, buf, buflen, &rh);
|
|
241 #else
|
|
242 rh = getservbyport_r (port, proto, ret, buf, buflen);
|
|
243 #endif
|
|
244 ri = (rh == NULL) ? -1 : 0;
|
|
245 return ri;
|
|
246 }
|
|
247 #elif defined (__vxworks)
|
|
248 static char vxw_h_name[MAXHOSTNAMELEN + 1];
|
|
249 static char *vxw_h_aliases[1] = { NULL };
|
|
250 static int vxw_h_addr;
|
|
251 static char *vxw_h_addr_list[2] = { (char*) &vxw_h_addr, NULL };
|
|
252
|
|
253 int
|
|
254 __gnat_gethostbyname (const char *name,
|
|
255 struct hostent *ret, char *buf, size_t buflen,
|
|
256 int *h_errnop)
|
|
257 {
|
|
258 vxw_h_addr = hostGetByName (name);
|
|
259 if (vxw_h_addr == ERROR) {
|
|
260 *h_errnop = __gnat_get_h_errno ();
|
|
261 return -1;
|
|
262 }
|
|
263 ret->h_name = name;
|
|
264 ret->h_aliases = &vxw_h_aliases;
|
|
265 ret->h_addrtype = AF_INET;
|
|
266 ret->h_length = 4;
|
|
267 ret->h_addr_list = &vxw_h_addr_list;
|
|
268 return 0;
|
|
269 }
|
|
270
|
|
271 int
|
|
272 __gnat_gethostbyaddr (const char *addr, int len, int type,
|
|
273 struct hostent *ret, char *buf, size_t buflen,
|
|
274 int *h_errnop)
|
|
275 {
|
|
276 if (type != AF_INET) {
|
|
277 *h_errnop = EAFNOSUPPORT;
|
|
278 return -1;
|
|
279 }
|
|
280
|
|
281 if (addr == NULL || len != 4) {
|
|
282 *h_errnop = EINVAL;
|
|
283 return -1;
|
|
284 }
|
|
285
|
|
286 if (hostGetByAddr (*(int*)addr, &vxw_h_name) != OK) {
|
|
287 *h_errnop = __gnat_get_h_errno ();
|
|
288 return -1;
|
|
289 }
|
|
290
|
|
291 vxw_h_addr = addr;
|
|
292
|
|
293 ret->h_name = &vxw_h_name;
|
|
294 ret->h_aliases = &vxw_h_aliases;
|
|
295 ret->h_addrtype = AF_INET;
|
|
296 ret->h_length = 4;
|
|
297 ret->h_addr_list = &vxw_h_addr_list;
|
|
298 }
|
|
299
|
|
300 int
|
|
301 __gnat_getservbyname (const char *name, const char *proto,
|
|
302 struct servent *ret, char *buf, size_t buflen)
|
|
303 {
|
|
304 /* Not available under VxWorks */
|
|
305 return -1;
|
|
306 }
|
|
307
|
|
308 int
|
|
309 __gnat_getservbyport (int port, const char *proto,
|
|
310 struct servent *ret, char *buf, size_t buflen)
|
|
311 {
|
|
312 /* Not available under VxWorks */
|
|
313 return -1;
|
|
314 }
|
|
315 #else
|
|
316 int
|
|
317 __gnat_gethostbyname (const char *name,
|
|
318 struct hostent *ret, char *buf, size_t buflen,
|
|
319 int *h_errnop)
|
|
320 {
|
|
321 struct hostent *rh;
|
|
322 rh = gethostbyname (name);
|
|
323 if (rh == NULL) {
|
|
324 *h_errnop = __gnat_get_h_errno ();
|
|
325 return -1;
|
|
326 }
|
|
327 *ret = *rh;
|
|
328 *h_errnop = 0;
|
|
329 return 0;
|
|
330 }
|
|
331
|
|
332 int
|
|
333 __gnat_gethostbyaddr (const char *addr, int len, int type,
|
|
334 struct hostent *ret, char *buf, size_t buflen,
|
|
335 int *h_errnop)
|
|
336 {
|
|
337 struct hostent *rh;
|
|
338 rh = gethostbyaddr (addr, len, type);
|
|
339 if (rh == NULL) {
|
|
340 *h_errnop = __gnat_get_h_errno ();
|
|
341 return -1;
|
|
342 }
|
|
343 *ret = *rh;
|
|
344 *h_errnop = 0;
|
|
345 return 0;
|
|
346 }
|
|
347
|
|
348 int
|
|
349 __gnat_getservbyname (const char *name, const char *proto,
|
|
350 struct servent *ret, char *buf, size_t buflen)
|
|
351 {
|
|
352 struct servent *rh;
|
|
353 rh = getservbyname (name, proto);
|
|
354 if (rh == NULL)
|
|
355 return -1;
|
|
356 *ret = *rh;
|
|
357 return 0;
|
|
358 }
|
|
359
|
|
360 int
|
|
361 __gnat_getservbyport (int port, const char *proto,
|
|
362 struct servent *ret, char *buf, size_t buflen)
|
|
363 {
|
|
364 struct servent *rh;
|
|
365 rh = getservbyport (port, proto);
|
|
366 if (rh == NULL)
|
|
367 return -1;
|
|
368 *ret = *rh;
|
|
369 return 0;
|
|
370 }
|
|
371 #endif
|
|
372
|
|
373 /* Find the largest socket in the socket set SET. This is needed for
|
|
374 `select'. LAST is the maximum value for the largest socket. This hint is
|
|
375 used to avoid scanning very large socket sets. On return, LAST is the
|
|
376 actual largest socket in the socket set. */
|
|
377
|
|
378 void
|
|
379 __gnat_last_socket_in_set (fd_set *set, int *last)
|
|
380 {
|
|
381 int s;
|
|
382 int l;
|
|
383 l = -1;
|
|
384
|
|
385 #ifdef _WIN32
|
|
386 /* More efficient method for NT. */
|
|
387 for (s = 0; s < set->fd_count; s++)
|
|
388 if ((int) set->fd_array[s] > l)
|
|
389 l = set->fd_array[s];
|
|
390
|
|
391 #else
|
|
392
|
|
393 for (s = *last; s != -1; s--)
|
|
394 if (FD_ISSET (s, set))
|
|
395 {
|
|
396 l = s;
|
|
397 break;
|
|
398 }
|
|
399 #endif
|
|
400
|
|
401 *last = l;
|
|
402 }
|
|
403
|
|
404 /* Get last socket and remove it from the socket set SET. LAST is the
|
|
405 maximum value of the largest socket. This hint is used to avoid scanning
|
|
406 very large socket sets. On return, LAST is set to the actual largest
|
|
407 socket in the socket set. */
|
|
408
|
|
409 void
|
|
410 __gnat_get_socket_from_set (fd_set *set, int *last, int *socket)
|
|
411 {
|
|
412 *socket = *last;
|
|
413 FD_CLR (*socket, set);
|
|
414 __gnat_last_socket_in_set (set, last);
|
|
415 }
|
|
416
|
|
417 /* Insert SOCKET in the socket set SET. */
|
|
418
|
|
419 void
|
|
420 __gnat_insert_socket_in_set (fd_set *set, int socket)
|
|
421 {
|
|
422 FD_SET (socket, set);
|
|
423 }
|
|
424
|
|
425 /* Check whether a given SOCKET is in the socket set SET. */
|
|
426
|
|
427 int
|
|
428 __gnat_is_socket_in_set (fd_set *set, int socket)
|
|
429 {
|
|
430 return FD_ISSET (socket, set);
|
|
431 }
|
|
432
|
|
433 /* Remove SOCKET from the socket set SET. */
|
|
434
|
|
435 void
|
|
436 __gnat_remove_socket_from_set (fd_set *set, int socket)
|
|
437 {
|
|
438 FD_CLR (socket, set);
|
|
439 }
|
|
440
|
|
441 /* Reset SET */
|
|
442 void
|
|
443 __gnat_reset_socket_set (fd_set *set)
|
|
444 {
|
|
445 FD_ZERO (set);
|
|
446 }
|
|
447
|
|
448 /* Get the value of the last host error */
|
|
449
|
|
450 int
|
|
451 __gnat_get_h_errno (void) {
|
|
452 #ifdef __vxworks
|
|
453 int vxw_errno = errno;
|
|
454
|
|
455 switch (vxw_errno) {
|
|
456 case 0:
|
|
457 return 0;
|
|
458
|
|
459 #ifdef S_hostLib_HOST_NOT_FOUND
|
|
460 case S_hostLib_HOST_NOT_FOUND:
|
|
461 #endif
|
|
462 case S_hostLib_UNKNOWN_HOST:
|
|
463 return HOST_NOT_FOUND;
|
|
464
|
|
465 #ifdef S_hostLib_TRY_AGAIN
|
|
466 case S_hostLib_TRY_AGAIN:
|
|
467 return TRY_AGAIN;
|
|
468 #endif
|
|
469
|
|
470 #ifdef S_hostLib_NO_RECOVERY
|
|
471 case S_hostLib_NO_RECOVERY:
|
|
472 #endif
|
|
473 #ifdef S_hostLib_NETDB_INTERNAL
|
|
474 case S_hostLib_NETDB_INTERNAL:
|
|
475 #endif
|
|
476 case S_hostLib_INVALID_PARAMETER:
|
|
477 return NO_RECOVERY;
|
|
478
|
|
479 default:
|
|
480 return -1;
|
|
481 }
|
|
482
|
|
483 #elif defined (__rtems__)
|
|
484 /* At this stage in the tool build, no networking .h files are available.
|
|
485 * Newlib does not provide networking .h files and RTEMS is not built yet.
|
|
486 * So we need to explicitly extern h_errno to access it.
|
|
487 */
|
|
488 extern int h_errno;
|
|
489 return h_errno;
|
|
490
|
|
491 #else
|
|
492 return h_errno;
|
|
493 #endif
|
|
494 }
|
|
495
|
|
496 /* Wrapper for ioctl(2), which is a variadic function */
|
|
497
|
|
498 int
|
|
499 __gnat_socket_ioctl (int fd, IOCTL_Req_T req, int *arg) {
|
|
500 #if defined (_WIN32)
|
|
501 return ioctlsocket (fd, req, arg);
|
|
502 #elif defined (__APPLE__)
|
|
503 /*
|
|
504 * On Darwin, req is an unsigned long, and we want to convert without sign
|
|
505 * extension to get the proper bit pattern in the case of a 64 bit kernel.
|
|
506 */
|
|
507 return ioctl (fd, (unsigned int) req, arg);
|
|
508 #else
|
|
509 return ioctl (fd, req, arg);
|
|
510 #endif
|
|
511 }
|
|
512
|
|
513 #ifndef HAVE_INET_PTON
|
|
514
|
|
515 int
|
|
516 __gnat_inet_pton (int af, const char *src, void *dst) {
|
|
517 switch (af) {
|
|
518 #if defined (_WIN32) && defined (AF_INET6)
|
|
519 case AF_INET6:
|
|
520 #endif
|
|
521 case AF_INET:
|
|
522 break;
|
|
523 default:
|
|
524 errno = EAFNOSUPPORT;
|
|
525 return -1;
|
|
526 }
|
|
527
|
|
528 #if defined (__vxworks)
|
|
529 return (inet_aton (src, dst) == OK);
|
|
530
|
|
531 #elif defined (_WIN32)
|
|
532 struct sockaddr_storage ss;
|
|
533 int sslen = sizeof ss;
|
|
534 int rc;
|
|
535
|
|
536 ss.ss_family = af;
|
|
537 rc = WSAStringToAddressA (src, af, NULL, (struct sockaddr *)&ss, &sslen);
|
|
538 if (rc == 0) {
|
|
539 switch (af) {
|
|
540 case AF_INET:
|
|
541 *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
|
|
542 break;
|
|
543 #ifdef AF_INET6
|
|
544 case AF_INET6:
|
|
545 *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
|
|
546 break;
|
|
547 #endif
|
|
548 }
|
|
549 }
|
|
550 return (rc == 0);
|
|
551
|
|
552 #elif defined (__hpux__)
|
|
553 in_addr_t addr;
|
|
554 int rc = -1;
|
|
555
|
|
556 if (src == NULL || dst == NULL) {
|
|
557 errno = EINVAL;
|
|
558
|
|
559 } else if (!strcmp (src, "255.255.255.255")) {
|
|
560 addr = 0xffffffff;
|
|
561 rc = 1;
|
|
562
|
|
563 } else {
|
|
564 addr = inet_addr (src);
|
|
565 rc = (addr != 0xffffffff);
|
|
566 }
|
|
567 if (rc == 1) {
|
|
568 *(in_addr_t *)dst = addr;
|
|
569 }
|
|
570 return rc;
|
|
571 #endif
|
|
572 }
|
|
573 #endif
|
|
574
|
|
575 /*
|
|
576 * Accessor functions for struct hostent.
|
|
577 */
|
|
578
|
|
579 char * __gnat_hostent_h_name (struct hostent * h) {
|
|
580 return h->h_name;
|
|
581 }
|
|
582
|
|
583 char * __gnat_hostent_h_alias (struct hostent * h, int index) {
|
|
584 return h->h_aliases[index];
|
|
585 }
|
|
586
|
|
587 int __gnat_hostent_h_addrtype (struct hostent * h) {
|
|
588 return h->h_addrtype;
|
|
589 }
|
|
590
|
|
591 int __gnat_hostent_h_length (struct hostent * h) {
|
|
592 return h->h_length;
|
|
593 }
|
|
594
|
|
595 char * __gnat_hostent_h_addr (struct hostent * h, int index) {
|
|
596 return h->h_addr_list[index];
|
|
597 }
|
|
598
|
|
599 /*
|
|
600 * Accessor functions for struct servent.
|
|
601 *
|
|
602 * These are needed because servent has different representations on different
|
|
603 * platforms, and we don't want to deal with that on the Ada side. For example,
|
|
604 * on Linux, we have (see /usr/include netdb.h):
|
|
605 *
|
|
606 * struct servent
|
|
607 * {
|
|
608 * char *s_name;
|
|
609 * char **s_aliases;
|
|
610 * int s_port;
|
|
611 * char *s_proto;
|
|
612 * };
|
|
613 *
|
|
614 * and on Windows (see mingw's socket.h):
|
|
615 *
|
|
616 * struct servent {
|
|
617 * char *s_name;
|
|
618 * char **s_aliases;
|
|
619 * #ifdef _WIN64
|
|
620 * char *s_proto;
|
|
621 * short s_port;
|
|
622 * #else
|
|
623 * short s_port;
|
|
624 * char *s_proto;
|
|
625 * #endif
|
|
626 * };
|
|
627 */
|
|
628
|
|
629 char *
|
|
630 __gnat_servent_s_name (struct servent * s)
|
|
631 {
|
|
632 return s->s_name;
|
|
633 }
|
|
634
|
|
635 char *
|
|
636 __gnat_servent_s_alias (struct servent * s, int index)
|
|
637 {
|
|
638 return s->s_aliases[index];
|
|
639 }
|
|
640
|
|
641 unsigned short
|
|
642 __gnat_servent_s_port (struct servent * s)
|
|
643 {
|
|
644 return s->s_port;
|
|
645 }
|
|
646
|
|
647 char *
|
|
648 __gnat_servent_s_proto (struct servent * s)
|
|
649 {
|
|
650 return s->s_proto;
|
|
651 }
|
|
652
|
|
653 #endif /* defined(HAVE_SOCKETS) */
|