15

For my project I wanted to get a list of all available broadcast addresses so I could broadcast a request and my other application located on other computer in the unspecified network would respond and to get the list I (now using little modified version with contribution of Mike) came up with this:


private ArrayList<InetAddress> getBroadcastAddresses() {
        ArrayList<InetAddress> listOfBroadcasts = new ArrayList();
        Enumeration list;
        try {
            list = NetworkInterface.getNetworkInterfaces();

            while(list.hasMoreElements()) {
                NetworkInterface iface = (NetworkInterface) list.nextElement();

                if(iface == null) continue;

                if(!iface.isLoopback() && iface.isUp()) {
                    System.out.println("Found non-loopback, up interface:" + iface);

                    Iterator it = iface.getInterfaceAddresses().iterator();
                    while (it.hasNext()) {
                        InterfaceAddress address = (InterfaceAddress) it.next();

                        System.out.println("Found address: " + address);

                        if(address == null) continue;
                        InetAddress broadcast = address.getBroadcast();
                        if(broadcast != null) listOfBroadcasts.add(broadcast);
                    }
                }
            }
        } catch (SocketException ex) {
            return new ArrayList<InetAddress>();
        }

        return site;
}

It works quite well for reqular LAN however when it comes to the WiFi LAN it just skips the second while loop after one step because of having address equals null even though when I used System.out.println(interfaceItem) just to view what interfaces are being gone through it wrote wireless LAN's name and my IP corresponding to the network.

EDIT 1: This is the output where 172.16.1.104 is my IP in the wireless network. The problem appears ONLY on my notebook with Wifi. The output is from my notebook where I mostly use wireless and sometimes I use UTP to connect with my friend. There is also one network interface of VirtualBox on my notebook.

Could you tell me what's wrong with it? Thank you!

Note: So it turns out that this might be problem for my notebook in particular and the code works for everybody else in general, I love this kind of problem :-) Seems like a dead end to me but thank for help anyway :-)

Still love you! ;-)

Martin
  • 3,445
  • 4
  • 23
  • 21
  • Perhaps, it's OK to have only one iteration of inner loop, because your NIC have only one IP host address? – Victor Sorokin Feb 03 '11 at 15:28
  • I admit that it's needless to go through InterfaceAdresses since there, as you say, should be problably only one if any but that would work even now wouldn't it? – Martin Feb 03 '11 at 17:43
  • I know this example can't be tested easily for some of you simply because you don't have WiFi network to test it in but none the less it just doesn't make sense to me why it dosn't work for wireless. – Martin Feb 04 '11 at 08:31
  • I think you'll need to iterate through the List returned by getInterfaceAddresses, you might find that it has more than one element and they one you're interested in isn't 0. If you're seeing the correct result from toString() as you say, perhaps look in the OpenJDK code to see what it's actually doing there. – Danny Thomas Feb 04 '11 at 23:38
  • Originally I did iterate through the List of getInterfaceAddresses but that wouldn't work either since the loop stopped after only one pass which is no different than getting first item on the list IMHO, what do you think? – Martin Feb 05 '11 at 01:03
  • @Victor: In general, TCP can support multiple addresses on a NIC. I would not assume only one. – Lawrence Dol Feb 05 '11 at 01:29
  • No matter, it does not work the second way which it should, right? – Martin Feb 05 '11 at 01:49

1 Answers1

5

I think you'll need to iterate across all the addresses, and additionally check if the broadcast address is null as well.

Consider that you might have addresses that you aren't expecting assigned to the interface as well. On my Linux system, with your code the first address I see is an IPv6 address, with a null broadcast (since there is no such thing as an IPv6 broadcast - though you can use multicast to achieve the same effect).

You need to completely remove the 1st way section of code. When you continue; there you'll go to the next interface instead of considering the possibility that there are two addresses.

The other reason why you always want to iterate all the addresses that can have broadcasts is because you need to consider that you might have addresses on two networks assigned to an interface. For example, you might have an interface with both 192.168.0.1/24 and 172.16.0.1/24 assigned.

Also, consider using a Set to store the broadcast addresses to protect against the case where you might have two addresses on the same subnet assigned.

Finally, since using broadcast addresses will restrict you to talking only to hosts that have an IP address in the same subnet, you might miss hosts that are not configured properly with the same subnet/netmask. So you might want to consider using multicast for this; you could use the IPv4 (or IPv6) all nodes multicast addresses to reach all hosts on the subnet, regardless of the configured address. (224.0.0.1 and FF01::1, respectively)

Edit: You also have a bug on the 2nd way, related to your use of the iterator. Since you're getting a new .iterator() each time around the for loop, you're lucky there isn't an infinite loop here. I changed your code to this, and it works for me:

$ cat Broadcasts.java 
import java.net.*;
import java.util.*;

public class Broadcasts
{
    public static void main(String[] args)
    {
        HashSet<InetAddress> listOfBroadcasts = new HashSet<InetAddress>();
        Enumeration list;
        try {
            list = NetworkInterface.getNetworkInterfaces();

            while(list.hasMoreElements()) {
                NetworkInterface iface = (NetworkInterface) list.nextElement();

                if(iface == null) continue;

                if(!iface.isLoopback() && iface.isUp()) {
                    //System.out.println("Found non-loopback, up interface:" + iface);

                    Iterator it = iface.getInterfaceAddresses().iterator();
                    while (it.hasNext()) {
                        InterfaceAddress address = (InterfaceAddress) it.next();
                        //System.out.println("Found address: " + address);
                        if(address == null) continue;
                        InetAddress broadcast = address.getBroadcast();
                        if(broadcast != null) 
                        {
                            System.out.println("Found broadcast: " + broadcast);
                            listOfBroadcasts.add(broadcast);
                        }
                    }
                }
            }
        } catch (SocketException ex) {
            System.err.println("Error while getting network interfaces");
            ex.printStackTrace();
        }

        // return listOfBroadcasts;
    }
}

Another problem you may run into is the try/catch around basically the entire function, which would cause this code to stop if it hit something unexpected. It would be better to surround possible failure points with a try/catch and do something sane (like skip the interface or address), but I didn't look at which methods can throw exceptions.

Edit 2: I misread your code; your iterator was fine. ;-) The problem (which I pointed out earlier) was that your 1st way is short-circuiting your 2nd way; since it hits the continue; statement, if the first address is null you don't even try to loop through them all.

In any case, run with those println statements and post the results if you're still having trouble.

Edit 3: OK, I give up. ;-) Based on the output you posted, it looks like you are running into a bug in the NetworkInterface class.

I don't know if it would help to turn off the preferIPv4Stack option, but you should test that. I searched around a little bit for bug reports that describe this behavior and could not find any.

Since you're on Linux, you could always take the fallback approach of shelling out and calling something like:

/sbin/ip addr | perl -ne 'print "$1\n" if $_  =~ /inet.* brd ([0-9\.]*)/'

... which should return you a list of broadcast addresses.

Edit 4: I just noticed in the JavaDoc for NetworkInterface there is a getSubInterfaces() call. Maybe you need to call this in order to make sure you get all the addresses? (it might help to post the output of /sbin/ip addr and /sbin/ifconfig)

Edit 5: Regarding the just-added bounty. (This question is over a year old!) Could someone please run the code in my answer above (edited to make it easy to copy/paste/run) and tell me if it works? If it doesn't, please edit the question and note the exact errors/problems.

mpontillo
  • 13,559
  • 7
  • 62
  • 90
  • I did use the second approach originally and right now I am trying to make it work as well but the strange thing is that when I reach the Wifi NetworkInterface instance, its list of InterfaceAddresses returned by its getInterfaceAddresses() method shows a size of 1 but when it gets to for loop, iterates and retrives apparently the only object on the list, the object it gets is null even though the toString() method of interfaceItem returns only but one IP address which is correct. That's what bugs me... – Martin Feb 09 '11 at 13:54
  • @Martin, well, I saw at least one bug in your code. See my fixed version. Please uncomment the `System.out` calls I added and post the results if you're still having trouble. – mpontillo Feb 09 '11 at 17:30
  • your code seems to me pretty much like mine only using while instead of for loop, no matter, results are still the same, when I hit wireless NetworkInterface and goes through the second while it finds one address which is null, then doesn't continue as it.hasNext() returns false and gets back to the first while loop – Martin Feb 09 '11 at 21:36
  • @Martin, Yeah, I realized that, but there is no reason why it should stop after the first address unless you didn't remove your `1st way`. Can you uncomment the System.out.println() calls in my code and edit your question with the results? – mpontillo Feb 09 '11 at 21:37
  • I noticed you haven't modified your catch { } block. Are you sure it's not throwing a NullPointerException because it picks up an IPv6 address and its broadcast is null? – mpontillo Feb 10 '11 at 02:11
  • @Martin, I see you are now checking the broadcqast address for null - but it could be some other exception? – mpontillo Feb 10 '11 at 02:39
  • I catch SocketException, in that case the algorithm would stop and return an empty list, if there were other exceptions they would be thrown as well but there aren't any – Martin Feb 10 '11 at 06:46
  • @Martin, I don't know what to tell you. This same code works fine on both my Windows and Linux system. You need to update your question with more details (the exact output, if possible). The only remaining possibility I can think of is that the address is somehow marked deprecated or otherwise not *really* configured (since your wired connection is enabled as well?) and it is not being returned. What combinations did you try: wired & wireless, wired only, wireless only? – mpontillo Feb 10 '11 at 06:54
  • and do you use wireless? I suppose you do, but I am asking anyway. – Martin Feb 10 '11 at 08:14
  • @Martin, I tried it with my wireless & wireless connected, and also wired only. – mpontillo Feb 10 '11 at 08:15
  • I don't know if this can affect the problem but long before this method is called in code I set the system property "java.net.preferIPv4Stack" to true. – Martin Feb 10 '11 at 17:46
  • how do you know I am on Linux? I am running Windows 7 and turning java.net.preferIPv4Stack off causes all broadcasts that I get from the algorythm are 255.255.255.255 which I found one another forum that preferIPv4Stack would take care of this and it did remarkably well. – Martin Feb 10 '11 at 20:57
  • Ah, yeah - sorry, I was mistaken. I saw names in your output like 'eth0', which you don't usually see on Windows. There goes that idea... well, are wired & wireless on the same physical network? The OS might be disallowing this. Do you get the same result with *only* wireless connected? – mpontillo Feb 10 '11 at 21:17
  • I checked getSubInterfaces() method and returned Enumeration is always empty for all interfaces :-( – Martin Feb 10 '11 at 21:22
  • what do you mean whether wired and wireless are on the same phisical network? – Martin Feb 10 '11 at 21:28
  • I am having trouble on my notebook with Windows 7 64bit, I use Wifi all the time to connect to Internet or my home wireless network, I never use cable unless I play with my friend which is from time to time so 99 % of the time the wireless is up and running and only active network, not counting those other empty interfaces which I don't know where they come from but anyway, wireless is on that list along with all of those, why it just doesn't extract the interface address as it should and it does for all other interfaces I have on my PC that I have tested with no problem at all – Martin Feb 10 '11 at 21:36
  • In other words, if I have a wireless router at `192.168.0.1` that serves up `192.168.0.0/24`, and I have a wired & wireless connection to it simultaneously, I would have two identical broadcast addresses, `192.168.0.255`. I found at least one thread that states that Windows 7 disables the wireless if it detects an active wired connection: http://social.answers.microsoft.com/Forums/en-US/w7network/thread/33b959fc-0c3e-4bb0-85a0-cc2d969fb4bc -- not sure if this would only happen if it was on the same subnet, or if it would happen if you had connected to two completely different networks. – mpontillo Feb 10 '11 at 21:38
  • That is really weird but as I said I use wireless 99 % of the time when there is no wire involved and the wireless doesn't seem to be disabled due to detected wired network. It works just like any other network (file sharing works, internet is available) so I assume that is not disabled. – Martin Feb 11 '11 at 06:02
  • @mike disabling 2 different interfaces in 2 different nets would be extremely dumb, although microsoft can always surprise you (but still) – bestsss Feb 11 '11 at 22:08