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