OSDN Git Service

2009-07-27 Emmanuel Briot <briot@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / socket.c
1 /****************************************************************************
2  *                                                                          *
3  *                         GNAT COMPILER COMPONENTS                         *
4  *                                                                          *
5  *                               S O C K E T                                *
6  *                                                                          *
7  *                          C Implementation File                           *
8  *                                                                          *
9  *          Copyright (C) 2003-2009, 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 #ifdef VMS
36 /*
37  * For VMS, gsocket.h can't include sockets-related DEC C header files
38  * when building the runtime (because these files are in DEC C archives,
39  * not accessable to GCC). So, we generate a separate header file along
40  * with s-oscons.ads and include it here.
41  */
42 # include "s-oscons.h"
43 #endif
44
45 #if defined(HAVE_SOCKETS)
46
47 /* Include all the necessary system-specific headers and define the
48  * necessary macros (shared with gen-oscons).
49  */
50
51 #if !defined(SO_NOSIGPIPE) && !defined (MSG_NOSIGNAL)
52 #include <signal.h>
53 #endif
54 /* Required if we will be calling signal() in __gnat_disable_all_sigpipes() */
55
56 #include "raise.h"
57 /* Required for __gnat_malloc() */
58
59 #include <string.h>
60 /* Required for memcpy() */
61
62 extern void __gnat_disable_sigpipe (int fd);
63 extern void __gnat_disable_all_sigpipes (void);
64 extern int  __gnat_create_signalling_fds (int *fds);
65 extern int  __gnat_read_signalling_fd (int rsig);
66 extern int  __gnat_write_signalling_fd (int wsig);
67 extern void  __gnat_close_signalling_fd (int sig);
68 extern void __gnat_last_socket_in_set (fd_set *, int *);
69 extern void __gnat_get_socket_from_set (fd_set *, int *, int *);
70 extern void __gnat_insert_socket_in_set (fd_set *, int);
71 extern int __gnat_is_socket_in_set (fd_set *, int);
72 extern fd_set *__gnat_new_socket_set (fd_set *);
73 extern void __gnat_remove_socket_from_set (fd_set *, int);
74 extern void __gnat_reset_socket_set (fd_set *);
75 extern int  __gnat_get_h_errno (void);
76 extern int  __gnat_socket_ioctl (int, int, int *);
77 #if defined (__vxworks) || defined (_WIN32)
78 extern int  __gnat_inet_pton (int, const char *, void *);
79 #endif
80 \f
81 /* Disable the sending of SIGPIPE for writes on a broken stream */
82
83 void
84 __gnat_disable_sigpipe (int fd)
85 {
86 #ifdef SO_NOSIGPIPE
87   int val = 1;
88   (void) setsockopt (fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof val);
89 #endif
90 }
91
92 void
93 __gnat_disable_all_sigpipes (void)
94 {
95 #if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) && defined(SIGPIPE)
96   (void) signal (SIGPIPE, SIG_IGN);
97 #endif
98 }
99 \f
100 #if defined (_WIN32) || defined (__vxworks) || defined (VMS)
101 /*
102  * Signalling FDs operations are implemented in Ada for these platforms
103  * (see subunit GNAT.Sockets.Thin.Signalling_Fds).
104  */
105 #else
106 /*
107  * Create a pair of connected file descriptors fds[0] and fds[1] used for
108  * signalling by a Selector object. fds[0] is the read end, and fds[1] the
109  * write end.
110  */
111 int
112 __gnat_create_signalling_fds (int *fds) {
113   return pipe (fds);
114 }
115 \f
116 /*
117  * Read one byte of data from rsig, the read end of a pair of signalling fds
118  * created by __gnat_create_signalling_fds.
119  */
120 int
121 __gnat_read_signalling_fd (int rsig) {
122   char c;
123   return read (rsig, &c, 1);
124 }
125 \f
126 /*
127  * Write one byte of data to wsig, the write end of a pair of signalling fds
128  * created by __gnat_create_signalling_fds.
129  */
130 int
131 __gnat_write_signalling_fd (int wsig) {
132   char c = 0;
133   return write (wsig, &c, 1);
134 }
135 \f
136 /*
137  * Close one end of a pair of signalling fds
138  */
139 void
140 __gnat_close_signalling_fd (int sig) {
141   (void) close (sig);
142 }
143 #endif
144 \f
145 /*
146  * GetXXXbyYYY wrappers
147  * These functions are used by the default implementation of g-socthi,
148  * and also by the Windows version.
149  *
150  * They can be used for any platform that either provides an intrinsically
151  * task safe implementation of getXXXbyYYY, or a reentrant variant
152  * getXXXbyYYY_r. Otherwise, a task safe wrapper, including proper mutual
153  * exclusion if appropriate, must be implemented in the target specific
154  * version of g-socthi.
155  */
156
157 #ifdef HAVE_THREAD_SAFE_GETxxxBYyyy
158 int
159 __gnat_safe_gethostbyname (const char *name,
160   struct hostent *ret, char *buf, size_t buflen,
161   int *h_errnop)
162 {
163   struct hostent *rh;
164   rh = gethostbyname (name);
165   if (rh == NULL) {
166     *h_errnop = h_errno;
167     return -1;
168   }
169   *ret = *rh;
170   *h_errnop = 0;
171   return 0;
172 }
173
174 int
175 __gnat_safe_gethostbyaddr (const char *addr, int len, int type,
176   struct hostent *ret, char *buf, size_t buflen,
177   int *h_errnop)
178 {
179   struct hostent *rh;
180   rh = gethostbyaddr (addr, len, type);
181   if (rh == NULL) {
182     *h_errnop = h_errno;
183     return -1;
184   }
185   *ret = *rh;
186   *h_errnop = 0;
187   return 0;
188 }
189
190 int
191 __gnat_safe_getservbyname (const char *name, const char *proto,
192   struct servent *ret, char *buf, size_t buflen)
193 {
194   struct servent *rh;
195   rh = getservbyname (name, proto);
196   if (rh == NULL)
197     return -1;
198   *ret = *rh;
199   return 0;
200 }
201
202 int
203 __gnat_safe_getservbyport (int port, const char *proto,
204   struct servent *ret, char *buf, size_t buflen)
205 {
206   struct servent *rh;
207   rh = getservbyport (port, proto);
208   if (rh == NULL)
209     return -1;
210   *ret = *rh;
211   return 0;
212 }
213 #elif HAVE_GETxxxBYyyy_R
214 int
215 __gnat_safe_gethostbyname (const char *name,
216   struct hostent *ret, char *buf, size_t buflen,
217   int *h_errnop)
218 {
219   struct hostent *rh;
220   int ri;
221
222 #if defined(__linux__) || defined(__GLIBC__)
223   (void) gethostbyname_r (name, ret, buf, buflen, &rh, h_errnop);
224 #else
225   rh = gethostbyname_r (name, ret, buf, buflen, h_errnop);
226 #endif
227   ri = (rh == NULL) ? -1 : 0;
228   return ri;
229 }
230
231 int
232 __gnat_safe_gethostbyaddr (const char *addr, int len, int type,
233   struct hostent *ret, char *buf, size_t buflen,
234   int *h_errnop)
235 {
236   struct hostent *rh;
237   int ri;
238
239 #if defined(__linux__) || defined(__GLIBC__)
240   (void) gethostbyaddr_r (addr, len, type, ret, buf, buflen, &rh, h_errnop);
241 #else
242   rh = gethostbyaddr_r (addr, len, type, ret, buf, buflen, h_errnop);
243 #endif
244   ri = (rh == NULL) ? -1 : 0;
245   return ri;
246 }
247
248 int
249 __gnat_safe_getservbyname (const char *name, const char *proto,
250   struct servent *ret, char *buf, size_t buflen)
251 {
252   struct servent *rh;
253   int ri;
254
255 #if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
256   (void) getservbyname_r (name, proto, ret, buf, buflen, &rh);
257 #else
258   rh = getservbyname_r (name, proto, ret, buf, buflen);
259 #endif
260   ri = (rh == NULL) ? -1 : 0;
261   return ri;
262 }
263
264 int
265 __gnat_safe_getservbyport (int port, const char *proto,
266   struct servent *ret, char *buf, size_t buflen)
267 {
268   struct servent *rh;
269   int ri;
270
271 #if defined(__linux__) || defined(__GLIBC__) || defined(__rtems__)
272   (void) getservbyport_r (port, proto, ret, buf, buflen, &rh);
273 #else
274   rh = getservbyport_r (port, proto, ret, buf, buflen);
275 #endif
276   ri = (rh == NULL) ? -1 : 0;
277   return ri;
278 }
279 #endif
280 \f
281 /* Find the largest socket in the socket set SET. This is needed for
282    `select'.  LAST is the maximum value for the largest socket. This hint is
283    used to avoid scanning very large socket sets.  On return, LAST is the
284    actual largest socket in the socket set. */
285
286 void
287 __gnat_last_socket_in_set (fd_set *set, int *last)
288 {
289   int s;
290   int l;
291   l = -1;
292
293 #ifdef _WIN32
294   /* More efficient method for NT. */
295   for (s = 0; s < set->fd_count; s++)
296     if ((int) set->fd_array[s] > l)
297       l = set->fd_array[s];
298
299 #else
300
301   for (s = *last; s != -1; s--)
302     if (FD_ISSET (s, set))
303       {
304         l = s;
305         break;
306       }
307 #endif
308
309   *last = l;
310 }
311
312 /* Get last socket and remove it from the socket set SET.  LAST is the
313    maximum value of the largest socket.  This hint is used to avoid scanning
314    very large socket sets.  On return, LAST is set to the actual largest
315    socket in the socket set. */
316
317 void
318 __gnat_get_socket_from_set (fd_set *set, int *last, int *socket)
319 {
320   *socket = *last;
321   FD_CLR (*socket, set);
322   __gnat_last_socket_in_set (set, last);
323 }
324
325 /* Insert SOCKET in the socket set SET. */
326
327 void
328 __gnat_insert_socket_in_set (fd_set *set, int socket)
329 {
330   FD_SET (socket, set);
331 }
332
333 /* Check whether a given SOCKET is in the socket set SET. */
334
335 int
336 __gnat_is_socket_in_set (fd_set *set, int socket)
337 {
338   return FD_ISSET (socket, set);
339 }
340
341 /* Remove SOCKET from the socket set SET. */
342
343 void
344 __gnat_remove_socket_from_set (fd_set *set, int socket)
345 {
346   FD_CLR (socket, set);
347 }
348
349 /* Reset SET */
350 void
351 __gnat_reset_socket_set (fd_set *set)
352 {
353   FD_ZERO (set);
354 }
355
356 /* Get the value of the last host error */
357
358 int
359 __gnat_get_h_errno (void) {
360 #ifdef __vxworks
361   int vxw_errno = errno;
362
363   switch (vxw_errno) {
364     case 0:
365       return 0;
366
367 #ifdef S_hostLib_HOST_NOT_FOUND
368     case S_hostLib_HOST_NOT_FOUND:
369 #endif
370     case S_hostLib_UNKNOWN_HOST:
371       return HOST_NOT_FOUND;
372
373 #ifdef S_hostLib_TRY_AGAIN
374     case S_hostLib_TRY_AGAIN:
375       return TRY_AGAIN;
376 #endif
377
378 #ifdef S_hostLib_NO_RECOVERY
379     case S_hostLib_NO_RECOVERY:
380 #endif
381 #ifdef S_hostLib_NETDB_INTERNAL
382     case S_hostLib_NETDB_INTERNAL:
383 #endif
384     case S_hostLib_INVALID_PARAMETER:
385       return NO_RECOVERY;
386
387     default:
388       return -1;
389   }
390
391 #elif defined (VMS)
392   /* h_errno is defined as follows in OpenVMS' version of <netdb.h>.
393    * However this header file is not available when building the GNAT
394    * runtime library using GCC, so we are hardcoding the definition
395    * directly. Note that the returned address is thread-specific.
396    */
397   extern int *decc$h_errno_get_addr ();
398   return *decc$h_errno_get_addr ();
399
400 #elif defined (__rtems__)
401   /* At this stage in the tool build, no networking .h files are available.
402    * Newlib does not provide networking .h files and RTEMS is not built yet.
403    * So we need to explicitly extern h_errno to access it.
404    */
405   extern int h_errno;
406   return h_errno;
407
408 #else
409   return h_errno;
410 #endif
411 }
412
413 /* Wrapper for ioctl(2), which is a variadic function */
414
415 int
416 __gnat_socket_ioctl (int fd, int req, int *arg) {
417 #if defined (_WIN32)
418   return ioctlsocket (fd, req, arg);
419 #else
420   return ioctl (fd, req, arg);
421 #endif
422 }
423
424 #ifndef HAVE_INET_PTON
425
426 #ifdef VMS
427 # define in_addr_t int
428 # define inet_addr decc$inet_addr
429 #endif
430
431 int
432 __gnat_inet_pton (int af, const char *src, void *dst) {
433   switch (af) {
434 #if defined (_WIN32) && defined (AF_INET6)
435     case AF_INET6:
436 #endif
437     case AF_INET:
438       break;
439     default:
440       errno = EAFNOSUPPORT;
441       return -1;
442   }
443
444 #if defined (__vxworks)
445   return (inet_aton (src, dst) == OK);
446
447 #elif defined (_WIN32)
448   struct sockaddr_storage ss;
449   int sslen = sizeof ss;
450   int rc;
451
452   ss.ss_family = af;
453   rc = WSAStringToAddressA (src, af, NULL, (struct sockaddr *)&ss, &sslen);
454   if (rc == 0) {
455     switch (af) {
456       case AF_INET:
457         *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
458         break;
459 #ifdef AF_INET6
460       case AF_INET6:
461         *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
462         break;
463 #endif
464     }
465   }
466   return (rc == 0);
467
468 #elif defined (__hpux__) || defined (VMS)
469   in_addr_t addr;
470   int rc = -1;
471
472   if (src == NULL || dst == NULL) {
473     errno = EINVAL;
474
475   } else if (!strcmp (src, "255.255.255.255")) {
476     addr = 0xffffffff;
477     rc = 1;
478
479   } else {
480     addr = inet_addr (src);
481     rc = (addr != 0xffffffff);
482   }
483   if (rc == 1) {
484     *(in_addr_t *)dst = addr;
485   }
486   return rc;
487 #endif
488 }
489 #endif
490
491 #else
492 # warning Sockets are not supported on this platform
493 #endif /* defined(HAVE_SOCKETS) */