/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <errno.h>
#include <strings.h>
#if defined(_ALLBSD_SOURCE) && defined(__OpenBSD__)
#endif
#include <stdlib.h>
#include <string.h>
#ifdef __solaris__
#include <fcntl.h>
#include <stropts.h>
#endif
#ifdef __linux__
#include <stdio.h>
#endif
#ifdef __linux__
#endif
#if defined(_ALLBSD_SOURCE)
#if defined(__APPLE__)
#include <net/ethernet.h>
#include <ifaddrs.h>
#endif
#endif
#include "jvm.h"
#include "jni_util.h"
#include "net_util.h"
typedef struct _netaddr {
short mask;
} netaddr;
typedef struct _netif {
char *name;
int index;
char virtual;
} netif;
/************************************************************************
* NetworkInterface
*/
#include "java_net_NetworkInterface.h"
/************************************************************************
* NetworkInterface
*/
/** Private methods declarations **/
#ifdef AF_INET6
#endif
static netif *addif(JNIEnv *env, int sock, const char * if_name, netif *ifs, struct sockaddr* ifr_addrP, int family, short prefix);
static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *name, struct sockaddr *brdcast_store);
static int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf);
#ifdef __solaris__
#ifndef SIOCGLIFHWADDR
#endif
#endif
/******************* Java entry points *****************************/
/*
* Class: java_net_NetworkInterface
* Method: init
* Signature: ()V
*/
}
/*
* Class: java_net_NetworkInterface
* Method: getByName0
*/
const char* name_utf;
return NULL;
}
/*
* Search the list of interface based on name
*/
break;
}
}
/* if found create a NetworkInterface */
}
/* release the UTF string and interface list */
return obj;
}
/*
* Class: java_net_NetworkInterface
* Method: getByIndex0
*/
if (index <= 0) {
return NULL;
}
return NULL;
}
/*
* Search the list of interface based on index
*/
break;
}
}
/* if found create a NetworkInterface */
}
return obj;
}
/*
* Class: java_net_NetworkInterface
* Method: getByInetAddress0
* Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
*/
#ifdef AF_INET6
#else
#endif
return NULL;
}
/*
* Iterate through each address on the interface
*/
break;
}
}
#ifdef AF_INET6
int i;
i = 0;
while (i < 16) {
break;
}
i++;
}
if (i >= 16) {
break;
}
}
#endif
}
if (match) {
break;
}
}
if (match) {
break;
}
}
/* if found create a NetworkInterface */
if (match) {;
}
return obj;
}
/*
* Class: java_net_NetworkInterface
* Method: getAll
* Signature: ()[Ljava/net/NetworkInterface;
*/
return NULL;
}
/* count the interface */
ifCount = 0;
ifCount++;
}
/* allocate a NetworkInterface array */
return NULL;
}
/*
* Iterate through the interfaces, create a NetworkInterface instance
* for each array element and populate the object.
*/
arr_index = 0;
return NULL;
}
/* put the NetworkInterface into the array */
}
return netIFArr;
}
/*
* Class: java_net_NetworkInterface
* Method: isUp0
*/
JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0(JNIEnv *env, jclass cls, jstring name, jint index) {
}
/*
* Class: java_net_NetworkInterface
* Method: isP2P0
*/
JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0(JNIEnv *env, jclass cls, jstring name, jint index) {
}
/*
* Class: java_net_NetworkInterface
* Method: isLoopback0
*/
JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0(JNIEnv *env, jclass cls, jstring name, jint index) {
}
/*
* Class: java_net_NetworkInterface
* Method: supportsMulticast0
*/
JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0(JNIEnv *env, jclass cls, jstring name, jint index) {
}
/*
* Class: java_net_NetworkInterface
* Method: getMacAddr0
*/
JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0(JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) {
int len;
int sock;
const char* name_utf;
return JNI_FALSE;
}
} else {
}
if (len > 0) {
/* we may have memory to free at the end of this */
goto fexit;
}
}
/* release the UTF string and interface list */
return ret;
}
/*
* Class: java_net_NetworkInterface
* Method: getMTU0
*/
JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) {
int sock;
const char* name_utf;
return JNI_FALSE;
}
return ret;
}
/*** Private methods definitions ****/
const char* name_utf;
int flags = 0;
return -1;
}
if (ret < 0) {
return -1;
}
return flags;
}
/*
* Create a NetworkInterface object, populate the name and index, and
* populate the InetAddress array based on the IP addresses for this
* interface.
*/
/*
* Create a NetworkInterface object and populate it
*/
return NULL;
}
/*
* Count the number of address on this interface
*/
addr_count = 0;
addr_count++;
}
/*
* Create the array of InetAddresses
*/
return NULL;
}
return NULL;
}
addr_index = 0;
bind_index = 0;
if (iaObj) {
}
if (ibObj) {
if (ia2Obj) {
}
}
}
}
#ifdef AF_INET6
int scope=0;
if (iaObj) {
return NULL;
}
if (scope != 0) { /* zero is default value, no need to set */
}
}
if (ibObj) {
}
}
#endif
return NULL;
}
}
/*
* See if there is any virtual interface attached to this one.
*/
child_count = 0;
while (childP) {
child_count++;
}
return NULL;
}
/*
* Create the NetworkInterface instances for the sub-interfaces as
* well.
*/
child_index = 0;
while(childP) {
return NULL;
}
}
/* return the NetworkInterface */
return netifObj;
}
/*
* Enumerates all interfaces
*/
int sock;
/*
* Enumerate IPv4 addresses
*/
return NULL;
}
return NULL;
}
/* return partial list if exception occure in the middle of process ???*/
/*
* If IPv6 is available then enumerate IPv6 addresses.
*/
#ifdef AF_INET6
/* User can disable ipv6 expicitly by -Djava.net.preferIPv4Stack=true,
* so we have to call ipv6_available()
*/
if (ipv6_available()) {
return NULL;
}
return NULL;
}
}
#endif
return ifs;
}
do{ \
return ifs; /* return untouched list */ \
} \
} while(0)
/*
* Free an interface list (including any attached addresses)
*/
}
/*
* Don't forget to free the sub-interfaces.
*/
}
}
}
short prefix)
{
#ifdef LIFNAMSIZ
#else
#endif
char *name_colonP;
int mask;
int isVirtual = 0;
int addr_size;
int flags = 0;
/*
* If the interface name is a logical interface then we
* remove the unit number so that we have the physical
* interface (eg: hme0:1 -> hme0). NetworkInterface
* currently doesn't have any concept of physical vs.
* logical interfaces.
*/
*vname = 0;
/*
* Create and populate the netaddr node. If allocation fails
* return an un-updated list.
*/
/*Allocate for addr and brdcast at once*/
#ifdef AF_INET6
#else
addr_size = sizeof(struct sockaddr_in);
#endif
/*
* Deal with brodcast addr & subnet mask
*/
}
}
/**
* Deal with virtual interface with colon notaion e.g. eth0:1
*/
if (name_colonP != NULL) {
/**
* This is a virtual interface. If we are able to access the parent
* we need to create a new entry if it doesn't exist yet *and* update
* the 'parent' interface with the new records.
*/
*name_colonP = 0;
// failed to access parent interface do not create parent.
// We are a virtual interface with no parent.
isVirtual = 1;
*name_colonP = ':';
}
else{
// Got access to parent, so create it if necessary.
// Save original name to vname and truncate name by ':'
}
}
/*
* Check if this is a "new" interface. Use the interface
* name for matching because index isn't supported on
* Solaris 2.6 & 7.
*/
break;
}
}
/*
* If "new" then create an netif structure and
* insert it onto the list.
*/
}
/*
* Finally insert the address on the interface
*/
/**
* Let's deal with the virtual interface now.
*/
if (vname[0]) {
break;
}
}
/* Need to duplicate the addr entry? */
}
}
}
}
return ifs;
}
/* Open socket for further ioct calls
*/
int sock;
/*
* If EPROTONOSUPPORT is returned it means we don't have
* support for this proto so don't throw an exception.
*/
if (errno != EPROTONOSUPPORT) {
}
return -1;
}
return sock;
}
/** Linux **/
#ifdef __linux__
/* Open socket for further ioct calls, try v4 socket first and
* if it falls return v6 socket
*/
#ifdef AF_INET6
int sock;
if (errno == EPROTONOSUPPORT){
NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
return -1;
}
}
else{ // errno is not NOSUPPORT
NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
return -1;
}
}
/* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type
of address of an interface */
return sock;
}
#else
}
#endif
char *buf;
int numifs;
unsigned i;
/* need to do a dummy SIOCGIFCONF to determine the buffer size.
* SIOCGIFCOUNT doesn't work
*/
return ifs;
}
return ifs;
}
/*
* Iterate through each interface
*/
/*
* Add to the list
*/
ifs = addif(env, sock, ifreqP->ifr_name, ifs, (struct sockaddr *) & (ifreqP->ifr_addr), AF_INET, 0);
/*
* If an exception occurred then free the list
*/
return NULL;
}
}
/*
* Free socket and buffer
*/
return ifs;
}
/*
* Enumerates and returns all IPv6 interfaces on Linux
*/
#ifdef AF_INET6
FILE *f;
while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
/*
* If an exception occurred then return the list as is.
*/
fclose(f);
return ifs;
}
}
fclose(f);
}
return ifs;
}
#endif
/*
* Try to get the interface index
* (Not supported on Solaris 2.6 or 7)
*/
return -1;
}
return if2.ifr_ifindex;
}
/**
* Returns the IPv4 broadcast address of a named interface, if it exists.
* Returns 0 if it doesn't have one.
*/
static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
/* Let's make sure the interface does have a broadcast address */
return ret;
}
/* It does, let's retrieve it*/
return ret;
}
ret = brdcast_store;
}
return ret;
}
/**
* Returns the IPv4 subnet prefix length (aka subnet mask) for the named
* interface, if it has one, otherwise return -1.
*/
unsigned int mask;
short ret;
return -1;
}
ret = 0;
while (mask) {
mask <<= 1;
ret++;
}
return ret;
}
/**
* Get the Hardware address (usually MAC address) for the named interface.
* return puts the data in buf, and returns the length, in byte, of the
* MAC address. Returns -1 if there is no hardware address on that interface.
*/
static int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf) {
int i;
return -1;
}
/*
* All bytes to 0 means no hardware address.
*/
for (i = 0; i < IFHWADDRLEN; i++) {
if (buf[i] != 0)
return IFHWADDRLEN;
}
return -1;
}
return -1;
}
}
return -1;
}
} else {
}
return 0;
}
#endif
/** Solaris **/
#ifdef __solaris__
/* Open socket for further ioct calls, try v4 socket first and
* if it falls return v6 socket
*/
#ifdef AF_INET6
if (errno == EPROTONOSUPPORT){
NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
return -1;
}
alreadyV6=1;
}
else{ // errno is not NOSUPPORT
NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
return -1;
}
}
/**
* Solaris requires that we have IPv6 socket to query an
* interface without IPv4 address - check it here
* POSIX 1 require the kernell to return ENOTTY if the call is
* unappropriate for device e.g. NETMASK for device having IPv6
* only address but not all devices follows the standart so
* fallback on any error. It's not an ecology friendly but more
* reliable.
*/
if (! alreadyV6 ){
NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
return -1;
}
}
}
return sock;
}
#else
}
#endif
/*
* Enumerates and returns all IPv4 interfaces
* (linux verison)
*/
}
#ifdef AF_INET6
}
#endif
/*
Enumerates and returns all interfaces on Solaris
use the same code for IPv4 and IPv6
*/
int n;
char *buf;
unsigned bufsize;
/*
* Get the interface count
*/
numifs.lifn_flags = 0;
return ifs;
}
/*
* Enumerate the interface configurations
*/
ifc.lifc_flags = 0;
return ifs;
}
/*
* Iterate through each interface
*/
/*
* Ignore either IPv4 or IPv6 addresses
*/
continue;
}
#ifdef AF_INET6
}
#endif
/* add to the list */
ifs = addif(env, sock,ifr->lifr_name, ifs, (struct sockaddr *)&(ifr->lifr_addr),family, (short) ifr->lifr_addrlen);
/*
* If an exception occurred we return immediately
*/
return ifs;
}
}
return ifs;
}
/*
* Try to get the interface index
* (Not supported on Solaris 2.6 or 7)
*/
return -1;
}
return if2.lifr_index;
}
/**
* Returns the IPv4 broadcast address of a named interface, if it exists.
* Returns 0 if it doesn't have one.
*/
static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
/* Let's make sure the interface does have a broadcast address */
return ret;
}
/* It does, let's retrieve it*/
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFBRDADDR failed");
return ret;
}
ret = brdcast_store;
}
return ret;
}
/**
* Returns the IPv4 subnet prefix length (aka subnet mask) for the named
* interface, if it has one, otherwise return -1.
*/
unsigned int mask;
short ret;
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFNETMASK failed");
return -1;
}
ret = 0;
while (mask) {
mask <<= 1;
ret++;
}
return ret;
}
/**
* Solaris specific DLPI code to get hardware address from a device.
* Unfortunately, at least up to Solaris X, you have to have special
* privileges (i.e. be root).
*/
int fd;
int flags = 0;
/**
* Device is in /dev
*/
/*
* Can't open it. We probably are missing the privilege.
* We'll have to try something else
*/
return 0;
}
return -1;
}
return -1;
}
return -1;
}
return dlpaack->dl_addr_length;
}
/**
* Get the Hardware address (usually MAC address) for the named interface.
* return puts the data in buf, and returns the length, in byte, of the
* MAC address. Returns -1 if there is no hardware address on that interface.
*/
static int getMacAddress(JNIEnv *env, int sock, const char *ifname, const struct in_addr* addr, unsigned char *buf) {
int len, i;
/* First, try the new (S11) SIOCGLIFHWADDR ioctl(). If that fails
* try the old way.
*/
}
/**
* On Solaris we have to use DLPI, but it will only work if we have
* privileged access (i.e. root). If that fails, we try a lookup
* in the ARP table, which requires an IPv4 address.
*/
/*DLPI failed - trying to do arp lookup*/
/**
* No IPv4 address for that interface, so can't do an ARP lookup.
*/
return -1;
}
return -1;
}
}
/*
* All bytes to 0 means no hardware address.
*/
for (i = 0; i < len; i++) {
if (buf[i] != 0)
return len;
}
return -1;
}
return -1;
}
}
return -1;
}
return 0;
}
#endif
/** BSD **/
#ifdef _ALLBSD_SOURCE
/* Open socket for further ioct calls, try v4 socket first and
* if it falls return v6 socket
*/
#ifdef AF_INET6
int sock;
if (errno == EPROTONOSUPPORT){
NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
return -1;
}
}
else{ // errno is not NOSUPPORT
NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
return -1;
}
}
return sock;
}
#else
}
#endif
/*
* Enumerates and returns all IPv4 interfaces
*/
if (getifaddrs(&origifa) != 0) {
"getifaddrs() function failed");
return ifs;
}
/*
* Skip non-AF_INET entries.
*/
continue;
/*
* Add to the list.
*/
/*
* If an exception occurred then free the list.
*/
return NULL;
}
}
/*
* Free socket and buffer
*/
return ifs;
}
/*
* Enumerates and returns all IPv6 interfaces on Linux
*/
#ifdef AF_INET6
/*
* Determines the prefix on BSD for IPv6 interfaces.
*/
static
break;
return (plen);
break;
return (0);
byte++;
return (0);
return (plen);
}
/*
* Enumerates and returns all IPv6 interfaces on BSD
*/
if (getifaddrs(&origifa) != 0) {
"getifaddrs() function failed");
return ifs;
}
/*
* Skip non-AF_INET6 entries.
*/
continue;
"ioctl SIOCGIFNETMASK_IN6 failed");
return NULL;
}
/* Add to the list. */
/* If an exception occurred then free the list. */
return NULL;
}
}
/*
* Free socket and ifaddrs buffer
*/
return ifs;
}
#endif
#ifdef __FreeBSD__
/*
* Try to get the interface index
* (Not supported on Solaris 2.6 or 7)
*/
return -1;
}
#else
/*
* Try to get the interface index using BSD specific if_nametoindex
*/
#endif
}
/**
* Returns the IPv4 broadcast address of a named interface, if it exists.
* Returns 0 if it doesn't have one.
*/
static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
/* Let's make sure the interface does have a broadcast address */
return ret;
}
/* It does, let's retrieve it*/
return ret;
}
ret = brdcast_store;
}
return ret;
}
/**
* Returns the IPv4 subnet prefix length (aka subnet mask) for the named
* interface, if it has one, otherwise return -1.
*/
unsigned int mask;
short ret;
return -1;
}
ret = 0;
while (mask) {
mask <<= 1;
ret++;
}
return ret;
}
/**
* Get the Hardware address (usually MAC address) for the named interface.
* return puts the data in buf, and returns the length, in byte, of the
* MAC address. Returns -1 if there is no hardware address on that interface.
*/
static int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf) {
int i;
/* Grab the interface list */
if (!getifaddrs(&ifa0)) {
/* Cycle through the interfaces */
/* Link layer contains the MAC address */
/* Check the address is the correct length */
return ETHER_ADDR_LEN;
}
}
}
}
return -1;
}
return -1;
}
}
return -1;
}
} else {
}
return 0;
}
#endif