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