/* 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 #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #include #include #include #include #include #if defined(HAVE_UNAME) && ! defined(HAVE_GETHOSTNAME) #include #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::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 *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); }