| /* Copyright (C) 2003 Free Software Foundation | |
| 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> | |
| #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 | |
| #include <gcj/cni.h> | |
| #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 | |
| 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_AllocBytes (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; | |
| blen = 4; | |
| } | |
| #elif defined(HAVE_INET_ADDR) | |
| #if ! HAVE_IN_ADDR_T | |
| typedef jint in_addr_t; | |
| #endif | |
| in_addr_t laddr = inet_addr (hostname); | |
| if (laddr != (in_addr_t)(-1)) | |
| { | |
| bytes = (char*) &laddr; | |
| blen = 4; | |
| } | |
| #endif | |
| #if defined (HAVE_INET_PTON) && defined (HAVE_INET6) | |
| char inet6_addr[16]; | |
| if (len != 0 && inet_pton (AF_INET6, hostname, inet6_addr) > 0) | |
| { | |
| bytes = inet6_addr; | |
| blen = 16; | |
| } | |
| #endif | |
| if (blen == 0) | |
| return NULL; | |
| jbyteArray result = JvNewByteArray (blen); | |
| memcpy (elements (result), bytes, blen); | |
| return result; | |
| } | |
| jint | |
| java::net::InetAddress::getFamily (jbyteArray bytes) | |
| { | |
| int len = bytes->length; | |
| if (len == 4) | |
| return AF_INET; | |
| #ifdef HAVE_INET6 | |
| else if (len == 16) | |
| return AF_INET6; | |
| #endif /* HAVE_INET6 */ | |
| else | |
| JvFail ("unrecognized size"); | |
| } | |
| 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; | |
| #if HAVE_STRUCT_HOSTENT_DATA | |
| struct hostent_data fixed_buffer, *buffer_r = &fixed_buffer; | |
| #else | |
| #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. | |
| char fixed_buffer[1024]; | |
| #else | |
| char fixed_buffer[200]; | |
| #endif | |
| char *buffer_r = fixed_buffer; | |
| int size_r = sizeof (fixed_buffer); | |
| #endif | |
| #endif | |
| if (host != NULL) | |
| { | |
| char *hostname; | |
| char buf[100]; | |
| int len = JvGetStringUTFLength(host); | |
| if (len < 100) | |
| hostname = buf; | |
| else | |
| hostname = (char*) _Jv_AllocBytes (len+1); | |
| JvGetStringUTFRegion (host, 0, host->length(), hostname); | |
| buf[len] = '\0'; | |
| #ifdef HAVE_GETHOSTBYNAME_R | |
| while (true) | |
| { | |
| int ok; | |
| #if HAVE_STRUCT_HOSTENT_DATA | |
| ok = ! gethostbyname_r (hostname, &hent_r, buffer_r); | |
| #else | |
| int herr = 0; | |
| #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_AllocBytes (size_r); | |
| } | |
| else | |
| #endif /* HAVE_STRUCT_HOSTENT_DATA */ | |
| break; | |
| } | |
| #else | |
| // FIXME: this is insufficient if some other piece of code calls | |
| // this gethostbyname. | |
| JvSynchronize sync (java::net::InetAddress::loopbackAddress); | |
| hptr = gethostbyname (hostname); | |
| #endif /* HAVE_GETHOSTBYNAME_R */ | |
| } | |
| else | |
| { | |
| jbyteArray bytes = iaddr->addr; | |
| char *chars = (char*) elements (bytes); | |
| int len = bytes->length; | |
| int type; | |
| char *val; | |
| if (len == 4) | |
| { | |
| val = chars; | |
| type = iaddr->family = AF_INET; | |
| } | |
| #ifdef HAVE_INET6 | |
| else if (len == 16) | |
| { | |
| val = (char *) &chars; | |
| type = iaddr->family = AF_INET6; | |
| } | |
| #endif /* HAVE_INET6 */ | |
| else | |
| JvFail ("unrecognized size"); | |
| #ifdef HAVE_GETHOSTBYADDR_R | |
| while (true) | |
| { | |
| int ok; | |
| #if HAVE_STRUCT_HOSTENT_DATA | |
| ok = ! gethostbyaddr_r (val, len, type, &hent_r, buffer_r); | |
| #else | |
| int herr = 0; | |
| #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_AllocBytes (size_r); | |
| } | |
| else | |
| #endif /* HAVE_STRUCT_HOSTENT_DATA */ | |
| break; | |
| } | |
| #else /* HAVE_GETHOSTBYADDR_R */ | |
| // FIXME: this is insufficient if some other piece of code calls | |
| // this gethostbyaddr. | |
| JvSynchronize sync (java::net::InetAddress::loopbackAddress); | |
| hptr = gethostbyaddr (val, len, type); | |
| #endif /* HAVE_GETHOSTBYADDR_R */ | |
| } | |
| if (hptr != NULL) | |
| { | |
| if (!all) | |
| host = JvNewStringUTF (hptr->h_name); | |
| } | |
| if (hptr == NULL) | |
| { | |
| if (iaddr != NULL && iaddr->addr != NULL) | |
| { | |
| iaddr->hostName = iaddr->getHostAddress(); | |
| return NULL; | |
| } | |
| else | |
| throw 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); | |
| if (iaddrs[i]->hostName == NULL) | |
| iaddrs[i]->hostName = host; | |
| if (iaddrs[i]->addr == NULL) | |
| { | |
| char *bytes = hptr->h_addr_list[i]; | |
| iaddrs[i]->addr = JvNewByteArray (hptr->h_length); | |
| iaddrs[i]->family = getFamily (iaddrs[i]->addr); | |
| memcpy (elements (iaddrs[i]->addr), bytes, hptr->h_length); | |
| } | |
| } | |
| 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) | |
| return NULL; | |
| 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); | |
| } |