I have a somewhat weird requirement to be able to listen to a number of network interfaces from Java on a Linux machine and determine if one of them receives UDP packets of a certain type. The output data which I need is the IP address of the interface in question. Is there any way to do this in Java?
Listening on the wildcard address (new DatagramSocket(port)) doesn't help because while I do get the broadcast packets, I can't determine the local IP address of the interface they came through. Listening to broadcasts while being bound to a certain interface (new DatagramSocket(port, address)) doesn't receive the packets at all. This case deserves a code example which shows what I'm trying to do:
Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface ni = (NetworkInterface) interfaces.nextElement();
Enumeration addresses = ni.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = (InetAddress)addresses.nextElement();
if (address.isLoopbackAddress() || address instanceof Inet6Address)
continue; //Not interested in loopback or ipv6 this time, thanks
DatagramSocket socket = new DatagramSocket(PORT, address);
//Try to read the broadcast messages from socket here
}
}
I also tried to to initialize the socket with the broadcast address constructed based on the beginning of the real IP of the interface and the rest according to the correct netmask:
byte [] mask = { (byte)255, 0, 0, 0 };
byte[] addrBytes = InetAddress.getByName("126.5.6.7").getAddress();
for (int i=0; i < 4; i++) {
addrBytes[i] |= ((byte)0xFF) ^ mask[i];
}
InetAddress bcastAddr = InetAddress.getByAddress(addrBytes);
That just throws a BindException when constructing the DatagramSocket.
EDIT: BindException (java.net.BindException: Cannot assign requested address) from calling DatagramSocket's constructor with a broadcast-address (e.g. 126.255.255.255) only comes with the latest Ubuntu 9.04 (probably not Ubuntu, but kernel-version specific issue though). With Ubuntu 8.10 this worked, as well as with the Red Hat release (RHEL 4.x) I am dealing with.
Apparently not receiving the packets while bound to a certain local IP is the correct behaviour, although in windows this works. I need to get it working on Linux (RHEL and Ubuntu). With low-level C-code there is a workaround setsockopt(SO_BINDTODEVICE) which I can't find in the Java-APIs. This doesn't exactly make me burst with optimism though :-)