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