OSDN Git Service

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