OSDN Git Service

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