OSDN Git Service

* java/net/natInetAddress.cc (lookup): On glibc2.0 systems, make
[pf3gnuchains/gcc-fork.git] / libjava / java / net / natInetAddress.cc
1 // natClass.cc - Implementation of java.lang.Class native methods.
2
3 /* Copyright (C) 1998, 1999  Cygnus Solutions
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 HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <string.h>
17 #include <errno.h>
18
19 #include <sys/param.h>
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_SOCKET_H
22 #include <sys/socket.h>
23 #endif
24 #ifdef HAVE_NETINET_IN_H
25 #include <netinet/in.h>
26 #endif
27 #ifdef HAVE_ARPA_INET_H
28 #include <arpa/inet.h>
29 #endif
30 #ifdef HAVE_NETDB_H
31 #include <netdb.h>
32 #endif
33
34 #include <cni.h>
35 #include <jvm.h>
36 #include <java/net/InetAddress.h>
37 #include <java/net/UnknownHostException.h>
38 #include <java/lang/SecurityException.h>
39
40 #if defined(HAVE_UNAME) && ! defined(HAVE_GETHOSTNAME)
41 #include <sys/utsname.h>
42 #endif
43
44 #ifndef HAVE_GETHOSTNAME_DECL
45 extern "C" int gethostname (char *name, int namelen);
46 #endif
47
48 jbyteArray
49 java::net::InetAddress::aton (jstring host)
50 {
51   char *hostname;
52   char buf[100];
53   int len = JvGetStringUTFLength(host);
54   if (len < 100)
55     hostname = buf;
56   else
57     hostname = (char*) _Jv_AllocBytesChecked (len+1);
58   JvGetStringUTFRegion (host, 0, host->length(), hostname);
59   buf[len] = '\0';
60   char* bytes = NULL;
61   int blen = 0;
62 #ifdef HAVE_INET_ATON
63   struct in_addr laddr;
64   if (inet_aton (hostname, &laddr))
65     {
66       bytes = (char*) &laddr;
67       len = 4;
68     }
69 #elif defined(HAVE_INET_ADDR)
70   in_addr_t laddr = inet_addr (hostname);
71   if (laddr != (in_addr_t)(-1))
72     {
73       bytes = (char*) &laddr;
74       len = 4;
75     }
76 #endif
77 #ifdef HAVE_INET_PTON
78   char inet6_addr[16];
79   if (len == 0 && inet_pton (AF_INET6, hostname, inet6_addr) > 0)
80     {
81       bytes = inet6_addr;
82       len = 16;
83     }
84 #endif
85   if (blen == 0)
86     return NULL;
87   jbyteArray result = JvNewByteArray (len);
88   memcpy (elements (result), bytes, blen);
89   return result;
90 }
91
92
93 JArray<java::net::InetAddress*> *
94 java::net::InetAddress::lookup (jstring host, java::net::InetAddress* iaddr,
95                                 jboolean all)
96 {
97   struct hostent *hptr = NULL;
98 #if defined (HAVE_GETHOSTBYNAME_R) || defined (HAVE_GETHOSTBYADDR_R)
99   struct hostent hent_r;
100 #if defined (__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 0
101   // glibc 2.0.7 has a bug where gethostbyname_r won't return an error
102   // if the buffer is too small.  So in this case we size the buffer
103   // the same way that glibc does.  This is fixed in glibc 2.1.
104   char fixed_buffer[1024];
105 #else
106   char fixed_buffer[200];
107 #endif
108   char *buffer_r = fixed_buffer;
109   int size_r = sizeof (fixed_buffer);
110 #endif
111
112   if (host != NULL)
113     {
114       char *hostname;
115       char buf[100];
116       int len = JvGetStringUTFLength(host);
117       if (len < 100)
118         hostname = buf;
119       else
120         hostname = (char*) _Jv_AllocBytesChecked (len+1);
121       JvGetStringUTFRegion (host, 0, host->length(), hostname);
122       buf[len] = '\0';
123 #ifdef HAVE_GETHOSTBYNAME_R
124       int herr = ERANGE;
125       while (hptr == NULL && herr == ERANGE)
126         {
127           int ok;
128 #ifdef GETHOSTBYNAME_R_RETURNS_INT
129           ok = ! gethostbyname_r (hostname, &hent_r, buffer_r, size_r,
130                                   &hptr, &herr);
131 #else
132           hptr = gethostbyname_r (hostname, &hent_r, buffer_r, size_r, &herr);
133           ok = hptr != NULL;
134 #endif /* GETHOSTNAME_R_RETURNS_INT */
135           if (! ok && herr == ERANGE)
136             {
137               size_r *= 2;
138               buffer_r = (char *) _Jv_AllocBytesChecked (size_r);
139             }
140         }
141 #else
142       // FIXME: this is insufficient if some other piece of code calls
143       // this gethostbyname.
144       JvSynchronize sync (java::net::InetAddress::localhostAddress);
145       hptr = gethostbyname (hostname);
146 #endif /* HAVE_GETHOSTBYNAME_R */
147     }
148   else
149     {
150       jbyteArray bytes = iaddr->address;
151       char *chars = (char*) elements (bytes);
152       int len = bytes->length;
153       int type;
154       char *val;
155       if (len == 4)
156         {
157           val = chars;
158           type = AF_INET;
159         }
160 #ifdef HAVE_INET6
161       else if (len == 16)
162         {
163           val = (char *) &chars;
164           type = AF_INET6;
165         }
166 #endif /* HAVE_INET6 */
167       else
168         JvFail ("unrecognized size");
169
170 #ifdef HAVE_GETHOSTBYADDR_R
171       int herr = ERANGE;
172       while (hptr == NULL && herr == ERANGE)
173         {
174           int ok;
175 #ifdef GETHOSTBYADDR_R_RETURNS_INT
176           ok = ! gethostbyaddr_r (val, len, type, &hent_r,
177                                   buffer_r, size_r, &hptr, &herr);
178 #else
179           hptr = gethostbyaddr_r (val, len, type, &hent_r,
180                                   buffer_r, size_r, &herr);
181           ok = hptr != NULL;
182 #endif /* GETHOSTBYADDR_R_RETURNS_INT */
183           if (! ok && herr == ERANGE)
184             {
185               size_r *= 2;
186               buffer_r = (char *) _Jv_AllocBytesChecked (size_r);
187             }
188         }
189 #else /* HAVE_GETHOSTBYADDR_R */
190       // FIXME: this is insufficient if some other piece of code calls
191       // this gethostbyaddr.
192       JvSynchronize sync (java::net::InetAddress::localhostAddress);
193       hptr = gethostbyaddr (val, len, type);
194 #endif /* HAVE_GETHOSTBYADDR_R */
195     }
196   if (hptr != NULL)
197     {
198       host = JvNewStringUTF (hptr->h_name);
199       java::lang::SecurityException *ex = checkConnect (host);
200       if (ex != NULL)
201         {
202           if (iaddr == NULL || iaddr->address == NULL)
203             JvThrow (ex);
204           hptr = NULL;
205         }
206     }
207   if (hptr == NULL)
208     {
209       if (iaddr != NULL && iaddr->address != NULL)
210         {
211           iaddr->hostname = iaddr->getHostAddress();
212           return NULL;
213         }
214       else
215         JvThrow (new java::net::UnknownHostException(host));
216     }
217   int count;
218   if (all)
219     {
220       char** ptr = hptr->h_addr_list;
221       count = 0;
222       while (*ptr++)  count++;
223     }
224   else
225     count = 1;
226   JArray<java::net::InetAddress*> *result;
227   java::net::InetAddress** iaddrs;
228   if (all)
229     {
230       result = java::net::InetAddress::allocArray (count);
231       iaddrs = elements (result);
232     }
233   else
234     {
235       result = NULL;
236       iaddrs = &iaddr;
237     }
238
239   for (int i = 0;  i < count;  i++)
240     {
241       if (iaddrs[i] == NULL)
242         iaddrs[i] = new java::net::InetAddress (NULL, NULL);
243       if (i == 0)
244         iaddrs[0]->hostname = host;
245       if (iaddrs[i]->address == NULL)
246         {
247           char *bytes = hptr->h_addr_list[i];
248           iaddr->address = JvNewByteArray (hptr->h_length);
249           memcpy (elements (iaddr->address), bytes, hptr->h_length);
250         }
251     }
252   return result;
253 }
254
255 jstring
256 java::net::InetAddress::getLocalHostname ()
257 {
258   char *chars;
259 #ifdef HAVE_GETHOSTNAME
260   char buffer[MAXHOSTNAMELEN];
261   if (gethostname (buffer, MAXHOSTNAMELEN))
262     return NULL;
263   chars = buffer;
264 #elif HAVE_UNAME
265   struct utsname stuff;
266   if (uname (&stuff) != 0)
267     return NULL:
268   chars = stuff.nodename;
269 #else
270   return NULL;
271 #endif
272   // It is admittedly non-optimal to convert the hostname to Unicode
273   // only to convert it back in getByName, but simplicity wins.  Note
274   // that unless there is a SecurityManager, we only get called once
275   // anyway, thanks to the InetAddress.localhost cache.
276   return JvNewStringUTF (chars);
277 }