OSDN Git Service

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