natInetAddress.cc 7.57 KB
Newer Older
Warren Levy committed
1
// natInetAddress.cc
Tom Tromey committed
2

3
/* Copyright (C) 1998, 1999, 2000  Free Software Foundation
Tom Tromey committed
4 5 6 7 8 9 10 11 12

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */

#include <config.h>

Tom Tromey committed
13 14 15 16 17 18 19 20 21 22 23
#ifdef USE_WINSOCK

#include <windows.h>
#include <winsock.h>

#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN	64
#endif /* MAXHOSTNAMELEN */

#else

Tom Tromey committed
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <errno.h>

#include <sys/param.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif

Tom Tromey committed
45 46
#endif /* USE_WINSOCK */

Tom Tromey committed
47
#include <gcj/cni.h>
Tom Tromey committed
48 49 50 51 52 53 54 55 56 57 58 59 60
#include <jvm.h>
#include <java/net/InetAddress.h>
#include <java/net/UnknownHostException.h>
#include <java/lang/SecurityException.h>

#if defined(HAVE_UNAME) && ! defined(HAVE_GETHOSTNAME)
#include <sys/utsname.h>
#endif

#ifndef HAVE_GETHOSTNAME_DECL
extern "C" int gethostname (char *name, int namelen);
#endif

Tom Tromey committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
#ifdef DISABLE_JAVA_NET

jbyteArray
java::net::InetAddress::aton (jstring)
{
  return NULL;
}

JArray<java::net::InetAddress*> *
java::net::InetAddress::lookup (jstring, java::net::InetAddress *, jboolean)
{
  return NULL;
}

jstring
java::net::InetAddress::getLocalHostname ()
{
  return NULL;
}

#else /* DISABLE_JAVA_NET */

Tom Tromey committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
jbyteArray
java::net::InetAddress::aton (jstring host)
{
  char *hostname;
  char buf[100];
  int len = JvGetStringUTFLength(host);
  if (len < 100)
    hostname = buf;
  else
    hostname = (char*) _Jv_AllocBytesChecked (len+1);
  JvGetStringUTFRegion (host, 0, host->length(), hostname);
  buf[len] = '\0';
  char* bytes = NULL;
  int blen = 0;
#ifdef HAVE_INET_ATON
  struct in_addr laddr;
  if (inet_aton (hostname, &laddr))
    {
      bytes = (char*) &laddr;
102
      blen = 4;
Tom Tromey committed
103 104
    }
#elif defined(HAVE_INET_ADDR)
105 106 107
#if ! HAVE_IN_ADDR_T
  typedef jint in_addr_t;
#endif
Tom Tromey committed
108 109 110 111
  in_addr_t laddr = inet_addr (hostname);
  if (laddr != (in_addr_t)(-1))
    {
      bytes = (char*) &laddr;
112
      blen = 4;
Tom Tromey committed
113 114 115 116 117 118 119
    }
#endif
#ifdef HAVE_INET_PTON
  char inet6_addr[16];
  if (len == 0 && inet_pton (AF_INET6, hostname, inet6_addr) > 0)
    {
      bytes = inet6_addr;
120
      blen = 16;
Tom Tromey committed
121 122 123 124
    }
#endif
  if (blen == 0)
    return NULL;
125
  jbyteArray result = JvNewByteArray (blen);
Tom Tromey committed
126 127 128 129 130 131 132 133 134 135 136 137
  memcpy (elements (result), bytes, blen);
  return result;
}


JArray<java::net::InetAddress*> *
java::net::InetAddress::lookup (jstring host, java::net::InetAddress* iaddr,
				jboolean all)
{
  struct hostent *hptr = NULL;
#if defined (HAVE_GETHOSTBYNAME_R) || defined (HAVE_GETHOSTBYADDR_R)
  struct hostent hent_r;
138 139 140
#if HAVE_STRUCT_HOSTENT_DATA
  struct hostent_data fixed_buffer, *buffer_r = &fixed_buffer;
#else
141 142 143 144 145
#if defined (__GLIBC__) 
  // FIXME: in glibc, gethostbyname_r returns NETDB_INTERNAL to herr and
  // ERANGE to errno if the buffer size is too small, rather than what is 
  // expected here. We work around this by setting a bigger buffer size and 
  // hoping that it is big enough.
146 147
  char fixed_buffer[1024];
#else
Tom Tromey committed
148
  char fixed_buffer[200];
149
#endif
Tom Tromey committed
150 151 152
  char *buffer_r = fixed_buffer;
  int size_r = sizeof (fixed_buffer);
#endif
153
#endif
Tom Tromey committed
154 155 156 157 158 159 160 161 162 163 164 165 166

  if (host != NULL)
    {
      char *hostname;
      char buf[100];
      int len = JvGetStringUTFLength(host);
      if (len < 100)
	hostname = buf;
      else
	hostname = (char*) _Jv_AllocBytesChecked (len+1);
      JvGetStringUTFRegion (host, 0, host->length(), hostname);
      buf[len] = '\0';
#ifdef HAVE_GETHOSTBYNAME_R
167
      while (true)
Tom Tromey committed
168 169
	{
	  int ok;
170 171 172 173
#if HAVE_STRUCT_HOSTENT_DATA
	  ok = ! gethostbyname_r (hostname, &hent_r, buffer_r);
#else
	  int herr = 0;
Tom Tromey committed
174 175 176 177 178 179 180 181 182 183 184 185
#ifdef GETHOSTBYNAME_R_RETURNS_INT
	  ok = ! gethostbyname_r (hostname, &hent_r, buffer_r, size_r,
				  &hptr, &herr);
#else
	  hptr = gethostbyname_r (hostname, &hent_r, buffer_r, size_r, &herr);
	  ok = hptr != NULL;
#endif /* GETHOSTNAME_R_RETURNS_INT */
	  if (! ok && herr == ERANGE)
	    {
	      size_r *= 2;
	      buffer_r = (char *) _Jv_AllocBytesChecked (size_r);
	    }
186
	  else
187
#endif /* HAVE_STRUCT_HOSTENT_DATA */
188
	    break;
Tom Tromey committed
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	}
#else
      // FIXME: this is insufficient if some other piece of code calls
      // this gethostbyname.
      JvSynchronize sync (java::net::InetAddress::localhostAddress);
      hptr = gethostbyname (hostname);
#endif /* HAVE_GETHOSTBYNAME_R */
    }
  else
    {
      jbyteArray bytes = iaddr->address;
      char *chars = (char*) elements (bytes);
      int len = bytes->length;
      int type;
      char *val;
      if (len == 4)
	{
	  val = chars;
	  type = AF_INET;
	}
#ifdef HAVE_INET6
      else if (len == 16)
	{
	  val = (char *) &chars;
213
	  type = AF_INET6;
Tom Tromey committed
214 215 216 217 218 219
	}
#endif /* HAVE_INET6 */
      else
	JvFail ("unrecognized size");

#ifdef HAVE_GETHOSTBYADDR_R
220
      while (true)
Tom Tromey committed
221 222
	{
	  int ok;
223 224 225 226
#if HAVE_STRUCT_HOSTENT_DATA
	  ok = ! gethostbyaddr_r (val, len, type, &hent_r, buffer_r);
#else
	  int herr = 0;
Tom Tromey committed
227 228 229 230 231 232 233 234 235 236 237 238 239
#ifdef GETHOSTBYADDR_R_RETURNS_INT
	  ok = ! gethostbyaddr_r (val, len, type, &hent_r,
				  buffer_r, size_r, &hptr, &herr);
#else
	  hptr = gethostbyaddr_r (val, len, type, &hent_r,
				  buffer_r, size_r, &herr);
	  ok = hptr != NULL;
#endif /* GETHOSTBYADDR_R_RETURNS_INT */
	  if (! ok && herr == ERANGE)
	    {
	      size_r *= 2;
	      buffer_r = (char *) _Jv_AllocBytesChecked (size_r);
	    }
240
	  else 
241
#endif /* HAVE_STRUCT_HOSTENT_DATA */
242
	    break;
Tom Tromey committed
243 244 245 246 247 248 249 250 251
	}
#else /* HAVE_GETHOSTBYADDR_R */
      // FIXME: this is insufficient if some other piece of code calls
      // this gethostbyaddr.
      JvSynchronize sync (java::net::InetAddress::localhostAddress);
      hptr = gethostbyaddr (val, len, type);
#endif /* HAVE_GETHOSTBYADDR_R */
    }
  if (hptr != NULL)
252 253
    {
      if (!all)
254
        host = JvNewStringUTF (hptr->h_name);
Tom Tromey committed
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
      java::lang::SecurityException *ex = checkConnect (host);
      if (ex != NULL)
	{
	  if (iaddr == NULL || iaddr->address == NULL)
	    JvThrow (ex);
	  hptr = NULL;
	}
    }
  if (hptr == NULL)
    {
      if (iaddr != NULL && iaddr->address != NULL)
	{
	  iaddr->hostname = iaddr->getHostAddress();
	  return NULL;
	}
      else
	JvThrow (new java::net::UnknownHostException(host));
    }
  int count;
  if (all)
    {
      char** ptr = hptr->h_addr_list;
      count = 0;
      while (*ptr++)  count++;
    }
  else
    count = 1;
  JArray<java::net::InetAddress*> *result;
  java::net::InetAddress** iaddrs;
  if (all)
    {
      result = java::net::InetAddress::allocArray (count);
      iaddrs = elements (result);
    }
  else
    {
      result = NULL;
      iaddrs = &iaddr;
    }

  for (int i = 0;  i < count;  i++)
    {
      if (iaddrs[i] == NULL)
	iaddrs[i] = new java::net::InetAddress (NULL, NULL);
299 300
      if (iaddrs[i]->hostname == NULL)
        iaddrs[i]->hostname = host;
Tom Tromey committed
301 302 303
      if (iaddrs[i]->address == NULL)
	{
	  char *bytes = hptr->h_addr_list[i];
304 305
	  iaddrs[i]->address = JvNewByteArray (hptr->h_length);
	  memcpy (elements (iaddrs[i]->address), bytes, hptr->h_length);
Tom Tromey committed
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
	}
    }
  return result;
}

jstring
java::net::InetAddress::getLocalHostname ()
{
  char *chars;
#ifdef HAVE_GETHOSTNAME
  char buffer[MAXHOSTNAMELEN];
  if (gethostname (buffer, MAXHOSTNAMELEN))
    return NULL;
  chars = buffer;
#elif HAVE_UNAME
  struct utsname stuff;
  if (uname (&stuff) != 0)
323
    return NULL;
Tom Tromey committed
324 325 326 327 328 329 330 331 332 333
  chars = stuff.nodename;
#else
  return NULL;
#endif
  // It is admittedly non-optimal to convert the hostname to Unicode
  // only to convert it back in getByName, but simplicity wins.  Note
  // that unless there is a SecurityManager, we only get called once
  // anyway, thanks to the InetAddress.localhost cache.
  return JvNewStringUTF (chars);
}
Tom Tromey committed
334 335

#endif /* DISABLE_JAVA_NET */