Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discoverer: Fix NPE when NetIf is not specified #124

Closed

Conversation

holgerfriedrich
Copy link
Contributor

The following code should work - if I read the javadoc correctly:

Discoverer discovererUdp = new Discoverer(0, false);
discovererUdp.startSearch(null, 5, true);
List<Result<SearchResponse>> responses = discovererUdp.getSearchResponses();
logger.warn("discovery {}", responses.toString());

However, toString() fails with

java.lang.NullPointerException: Cannot invoke "java.net.NetworkInterface.getName()" because "this.ni" is null

and during detection I see

java.lang.NullPointerException: Cannot invoke "java.net.NetworkInterface.equals(Object)" because the return value of "tuwien.auto.calimero.knxnetip.Discoverer$Result.getNetworkInterface()" is null
at tuwien.auto.calimero.knxnetip.Discoverer$Result.equals(Discoverer.java:225) ~[bundleFile:?]
at java.util.ArrayList.indexOfRange(ArrayList.java:299) ~[?:?]
at java.util.ArrayList.indexOf(ArrayList.java:286) ~[?:?]
at java.util.ArrayList.contains(ArrayList.java:275) ~[?:?]
at java.util.Collections$SynchronizedCollection.contains(Collections.java:2087) ~[?:?]
at tuwien.auto.calimero.knxnetip.Discoverer$ReceiverLoop.onReceive(Discoverer.java:868) [bundleFile:?]
at tuwien.auto.calimero.knxnetip.Discoverer$ReceiverLoop.receive(Discoverer.java:922) [bundleFile:?]
at tuwien.auto.calimero.internal.UdpSocketLooper.loop(UdpSocketLooper.java:134) [bundleFile:?]
at tuwien.auto.calimero.knxnetip.Discoverer$ReceiverLoop.run(Discoverer.java:840) [bundleFile:?]

Both is fixed by more restrictive null checks.

Or did I get the usage instructions wrong and a network interface should be supplied?

Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
@bmalinowsky
Copy link
Collaborator

It's a regression, it was implemented with MulticastSocket which always returns an interface; now with using a datagram channel it doesn't if not specifically set.

One could also assign Net.defaultNetif in ReceiverLoop ctor if the netif is null. I am not sure how important the old behavior is; one advantage might be that a user doesn't have to null check netif in Result.

@bmalinowsky
Copy link
Collaborator

Looking at the code, I converted Result to a record and fixed this issue at the same time.

As a side note, using startSearch(netif, timeout, wait) with netif null is mainly either for a host with a (stable) single interface (i.e., the default netif and routing table is straight forward), or if you specifically rely on the routing table. In case of discovery with unicast responses, this also requires an appropriate config of the localhost setting. So I would in general use startSearch(timeout, wait) which checks all usable interfaces.

@holgerfriedrich
Copy link
Contributor Author

@bmalinowsky thanks for the hint. I had implemented iterating over all network interfaces in the meantime to get it running with 2.5.1 release. Somehow I have overlooked the method startSearch with only 2 parameters. That's much cleaner now.

Regarding the PR - as you have fixed the root cause, this PR seems no longer necessary. Closing. And thanks for looking into it.

@holgerfriedrich holgerfriedrich deleted the pr-discoverer branch November 20, 2023 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants