OSDN Git Service

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