OSDN Git Service

2009-04-07 Robert Dewar <dewar@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-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_last_socket_in_set (fd_set *, int *);
61 extern void __gnat_get_socket_from_set (fd_set *, int *, int *);
62 extern void __gnat_insert_socket_in_set (fd_set *, int);
63 extern int __gnat_is_socket_in_set (fd_set *, int);
64 extern fd_set *__gnat_new_socket_set (fd_set *);
65 extern void __gnat_remove_socket_from_set (fd_set *, int);
66 extern void __gnat_reset_socket_set (fd_set *set);
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 /* Find the largest socket in the socket set SET. This is needed for
270    `select'.  LAST is the maximum value for the largest socket. This hint is
271    used to avoid scanning very large socket sets.  On return, LAST is the
272    actual largest socket in the socket set. */
273
274 void
275 __gnat_last_socket_in_set (fd_set *set, int *last)
276 {
277   int s;
278   int l;
279   l = -1;
280
281 #ifdef _WIN32
282   /* More efficient method for NT. */
283   for (s = 0; s < set->fd_count; s++)
284     if ((int) set->fd_array[s] > l)
285       l = set->fd_array[s];
286
287 #else
288
289   for (s = *last; s != -1; s--)
290     if (FD_ISSET (s, set))
291       {
292         l = s;
293         break;
294       }
295 #endif
296
297   *last = l;
298 }
299
300 /* Get last socket and remove it from the socket set SET.  LAST is the
301    maximum value of the largest socket.  This hint is used to avoid scanning
302    very large socket sets.  On return, LAST is set to the actual largest
303    socket in the socket set. */
304
305 void
306 __gnat_get_socket_from_set (fd_set *set, int *last, int *socket)
307 {
308   *socket = *last;
309   FD_CLR (*socket, set);
310   __gnat_last_socket_in_set (set, last);
311 }
312
313 /* Insert SOCKET in the socket set SET. */
314
315 void
316 __gnat_insert_socket_in_set (fd_set *set, int socket)
317 {
318   FD_SET (socket, set);
319 }
320
321 /* Check whether a given SOCKET is in the socket set SET. */
322
323 int
324 __gnat_is_socket_in_set (fd_set *set, int socket)
325 {
326   return FD_ISSET (socket, set);
327 }
328
329 /* Remove SOCKET from the socket set SET. */
330
331 void
332 __gnat_remove_socket_from_set (fd_set *set, int socket)
333 {
334   FD_CLR (socket, set);
335 }
336
337 /* Reset SET */
338 void
339 __gnat_reset_socket_set (fd_set *set)
340 {
341   FD_ZERO (set);
342 }
343
344 /* Get the value of the last host error */
345
346 int
347 __gnat_get_h_errno (void) {
348 #ifdef __vxworks
349   int vxw_errno = errno;
350
351   switch (vxw_errno) {
352     case 0:
353       return 0;
354
355     case S_resolvLib_HOST_NOT_FOUND:
356     case S_hostLib_UNKNOWN_HOST:
357       return HOST_NOT_FOUND;
358
359     case S_resolvLib_TRY_AGAIN:
360       return TRY_AGAIN;
361
362     case S_resolvLib_NO_RECOVERY:
363     case S_resolvLib_BUFFER_2_SMALL:
364     case S_resolvLib_INVALID_PARAMETER:
365     case S_resolvLib_INVALID_ADDRESS:
366     case S_hostLib_INVALID_PARAMETER:
367       return NO_RECOVERY;
368
369     case S_resolvLib_NO_DATA:
370       return NO_DATA;
371
372     default:
373       return -1;
374   }
375
376 #elif defined (VMS)
377   /* h_errno is defined as follows in OpenVMS' version of <netdb.h>.
378    * However this header file is not available when building the GNAT
379    * runtime library using GCC, so we are hardcoding the definition
380    * directly. Note that the returned address is thread-specific.
381    */
382   extern int *decc$h_errno_get_addr ();
383   return *decc$h_errno_get_addr ();
384
385 #elif defined (__rtems__)
386   /* At this stage in the tool build, no networking .h files are available.
387    * Newlib does not provide networking .h files and RTEMS is not built yet.
388    * So we need to explicitly extern h_errno to access it.
389    */
390   extern int h_errno;
391   return h_errno;
392
393 #else
394   return h_errno;
395 #endif
396 }
397
398 #else
399 #warning Sockets are not supported on this platform
400 #endif /* defined(HAVE_SOCKETS) */