OSDN Git Service

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