OSDN Git Service

2007-08-08 Samuel Thibault <samuel.thibault@ens-lyon.org>
[pf3gnuchains/gcc-fork.git] / libjava / java / net / natVMInetAddressPosix.cc
1 /* Copyright (C) 2003, 2006  Free Software Foundation
2
3    This file is part of libgcj.
4
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
7 details.  */
8
9 #include <config.h>
10
11 #ifdef HAVE_UNISTD_H
12 #include <unistd.h>
13 #endif
14 #include <string.h>
15 #include <errno.h>
16
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #ifdef HAVE_SYS_SOCKET_H
20 #include <sys/socket.h>
21 #endif
22 #ifdef HAVE_NETINET_IN_H
23 #include <netinet/in.h>
24 #endif
25 #ifdef HAVE_ARPA_INET_H
26 #include <arpa/inet.h>
27 #endif
28 #ifdef HAVE_NETDB_H
29 #include <netdb.h>
30 #endif
31
32 #include <gcj/cni.h>
33 #include <jvm.h>
34 #include <java/net/VMInetAddress.h>
35 #include <java/net/UnknownHostException.h>
36
37 #if defined(HAVE_UNAME) && ! defined(HAVE_GETHOSTNAME)
38 #include <sys/utsname.h>
39 #endif
40
41 #ifndef HAVE_GETHOSTNAME_DECL
42 extern "C" int gethostname (char *name, int namelen);
43 #endif
44
45 jstring
46 java::net::VMInetAddress::getLocalHostname ()
47 {
48   char *chars;
49 #ifdef HAVE_GETHOSTNAME
50 #ifdef MAXHOSTNAMELEN
51   char buffer[MAXHOSTNAMELEN];
52   if (gethostname (buffer, MAXHOSTNAMELEN))
53     return NULL;
54   chars = buffer;
55 #else
56   size_t size = 256;
57   while (1) {
58     char buffer[size];
59     if (!gethostname (buffer, size-1))
60       {
61         buffer[size-1] = 0;
62         return JvNewStringUTF (buffer);
63       }
64     else if (errno != ENAMETOOLONG)
65       return NULL;
66     size *= 2;
67   }
68 #endif
69 #elif HAVE_UNAME
70   struct utsname stuff;
71   if (uname (&stuff) != 0)
72     return NULL;
73   chars = stuff.nodename;
74 #else
75   return NULL;
76 #endif
77   // It is admittedly non-optimal to convert the hostname to Unicode
78   // only to convert it back in getByName, but simplicity wins.
79   return JvNewStringUTF (chars);
80 }
81
82 jbyteArray
83 java::net::VMInetAddress::lookupInaddrAny ()
84 {
85 #if ! HAVE_IN_ADDR_T
86   typedef jint in_addr_t;
87 #endif
88   in_addr_t laddr = INADDR_ANY;
89   char *bytes = (char *) &laddr;
90   int blen = sizeof (laddr);
91   jbyteArray result = JvNewByteArray (blen);
92   memcpy (elements (result), bytes, blen);
93   return result;
94 }
95
96 jstring
97 java::net::VMInetAddress::getHostByAddr (jbyteArray addr)
98 {
99   struct hostent *hptr = NULL;
100 #ifdef HAVE_GETHOSTBYADDR_R
101   struct hostent hent_r;
102 #if HAVE_STRUCT_HOSTENT_DATA
103   struct hostent_data fixed_buffer, *buffer_r = &fixed_buffer;
104 #else
105 #ifdef __GLIBC__
106   // FIXME: in glibc, gethostbyname_r returns NETDB_INTERNAL to herr and
107   // ERANGE to errno if the buffer size is too small, rather than what is 
108   // expected here. We work around this by setting a bigger buffer size and 
109   // hoping that it is big enough.
110   char fixed_buffer[1024];
111 #else
112   char fixed_buffer[200];
113 #endif /* __GLIBC__ */
114   char *buffer_r = fixed_buffer;
115   int size_r = sizeof (fixed_buffer);
116 #endif /* HAVE_STRUCT_HOSTENT_DATA */
117 #endif /* HAVE_GETHOSTBYADDR_R */
118
119   char *bytes = (char*) elements (addr);
120   int len = addr->length;
121   int type;
122   char *val;
123   if (len == 4)
124     {
125       val = bytes;
126       type = AF_INET;
127     }
128 #ifdef HAVE_INET6
129   else if (len == 16)
130     {
131       val = (char *) &bytes;
132       type = AF_INET6;
133     }
134 #endif /* HAVE_INET6 */
135   else
136     JvFail ("unrecognized size");
137
138 #ifdef HAVE_GETHOSTBYADDR_R
139   while (true)
140     {
141       int ok;
142 #if HAVE_STRUCT_HOSTENT_DATA
143       ok = ! gethostbyaddr_r (val, len, type, &hent_r, buffer_r);
144 #else
145       int herr = 0;
146 #ifdef GETHOSTBYADDR_R_RETURNS_INT
147       ok = ! gethostbyaddr_r (val, len, type, &hent_r,
148                               buffer_r, size_r, &hptr, &herr);
149 #else
150       hptr = gethostbyaddr_r (val, len, type, &hent_r,
151                               buffer_r, size_r, &herr);
152       ok = hptr != NULL;
153 #endif /* GETHOSTBYADDR_R_RETURNS_INT */
154       if (! ok && herr == ERANGE)
155         {
156           size_r *= 2;
157           buffer_r = (char *) _Jv_AllocBytes (size_r);
158         }
159       else 
160 #endif /* HAVE_STRUCT_HOSTENT_DATA */
161         break;
162     }
163 #else /* HAVE_GETHOSTBYADDR_R */
164   // FIXME: this is insufficient if some other piece of code calls
165   // this gethostbyaddr.
166   JvSynchronize sync (&java::net::VMInetAddress::class$);
167   hptr = gethostbyaddr (val, len, type);
168 #endif /* HAVE_GETHOSTBYADDR_R */
169
170   if (hptr == NULL)
171     throw new java::net::UnknownHostException ();
172
173   return JvNewStringUTF (hptr->h_name);
174 }
175
176 JArray<jbyteArray> *
177 java::net::VMInetAddress::getHostByName (jstring host)
178 {
179   struct hostent *hptr = NULL;
180 #ifdef HAVE_GETHOSTBYNAME_R
181   struct hostent hent_r;
182 #if HAVE_STRUCT_HOSTENT_DATA
183   struct hostent_data fixed_buffer, *buffer_r = &fixed_buffer;
184 #else
185 #ifdef __GLIBC__
186   // FIXME: in glibc, gethostbyname_r returns NETDB_INTERNAL to herr and
187   // ERANGE to errno if the buffer size is too small, rather than what is 
188   // expected here. We work around this by setting a bigger buffer size and 
189   // hoping that it is big enough.
190   char fixed_buffer[1024];
191 #else
192   char fixed_buffer[200];
193 #endif /* __GLIBC__ */
194   char *buffer_r = fixed_buffer;
195   int size_r = sizeof (fixed_buffer);
196 #endif /* HAVE_STRUCT_HOSTENT_DATA */
197 #endif /* HAVE_GETHOSTBYNAME_R */
198
199   char *hostname;
200   char buf[100];
201   int len = JvGetStringUTFLength(host);
202   if (len < 100)
203     hostname = buf;
204   else
205     hostname = (char *) _Jv_AllocBytes (len + 1);
206   JvGetStringUTFRegion (host, 0, host->length(), hostname);
207   buf[len] = '\0';
208 #ifdef HAVE_GETHOSTBYNAME_R
209   while (true)
210     {
211       int ok;
212 #if HAVE_STRUCT_HOSTENT_DATA
213       ok = ! gethostbyname_r (hostname, &hent_r, buffer_r);
214 #else
215       int herr = 0;
216 #ifdef GETHOSTBYNAME_R_RETURNS_INT
217       ok = ! gethostbyname_r (hostname, &hent_r, buffer_r, size_r,
218                               &hptr, &herr);
219 #else
220       hptr = gethostbyname_r (hostname, &hent_r, buffer_r, size_r, &herr);
221       ok = hptr != NULL;
222 #endif /* GETHOSTNAME_R_RETURNS_INT */
223       if (! ok && herr == ERANGE)
224         {
225           size_r *= 2;
226           buffer_r = (char *) _Jv_AllocBytes (size_r);
227         }
228       else
229 #endif /* HAVE_STRUCT_HOSTENT_DATA */
230         break;
231     }
232 #else /* HAVE_GETHOSTBYNAME_R */
233   // FIXME: this is insufficient if some other piece of code calls
234   // this gethostbyname.
235   JvSynchronize sync (&java::net::VMInetAddress::class$);
236   hptr = gethostbyname (hostname);
237 #endif /* HAVE_GETHOSTBYNAME_R */
238
239   if (hptr == NULL)
240     throw new java::net::UnknownHostException (host);
241
242   int count = 0;
243   char ** ptr = hptr->h_addr_list;
244   while (*ptr++)  count++;
245
246   JArray<jbyteArray> *result =
247     (JArray<jbyteArray> *) _Jv_NewObjectArray (
248       count, _Jv_GetArrayClass(JvPrimClass(byte), NULL), NULL);
249   jbyteArray* addrs = elements (result);
250
251   for (int i = 0; i < count; i++)
252     {
253       addrs[i] = JvNewByteArray (hptr->h_length);
254       memcpy (elements (addrs[i]), hptr->h_addr_list[i], hptr->h_length);
255     }
256   return result;
257 }
258
259 jbyteArray
260 java::net::VMInetAddress::aton (jstring host)
261 {
262   char *hostname;
263   char buf[100];
264   int len = JvGetStringUTFLength(host);
265   if (len < 100)
266     hostname = buf;
267   else
268     hostname = (char *) _Jv_AllocBytes (len+1);
269   JvGetStringUTFRegion (host, 0, host->length(), hostname);
270   buf[len] = '\0';
271   char *bytes = NULL;
272   int blen = 0;
273 #ifdef HAVE_INET_ATON
274   struct in_addr laddr;
275   if (inet_aton (hostname, &laddr))
276     {
277       bytes = (char *) &laddr;
278       blen = 4;
279     }
280 #elif defined(HAVE_INET_ADDR)
281 #if ! HAVE_IN_ADDR_T
282   typedef jint in_addr_t;
283 #endif
284   in_addr_t laddr = inet_addr (hostname);
285   if (laddr != (in_addr_t)(-1))
286     {
287       bytes = (char *) &laddr;
288       blen = 4;
289     }
290 #endif
291 #if defined (HAVE_INET_PTON) && defined (HAVE_INET6)
292   char inet6_addr[16];
293   if (len != 0 && inet_pton (AF_INET6, hostname, inet6_addr) > 0)
294     {
295       bytes = inet6_addr;
296       blen = 16;
297     }
298 #endif
299   if (blen == 0)
300     return NULL;
301   jbyteArray result = JvNewByteArray (blen);
302   memcpy (elements (result), bytes, blen);
303   return result;
304 }