2

My code is throwing a SocketException upon calling send() in DatagramChannel. The javadoc doesn't even mention that this is possible. I found a post somewhere advising the use of the IPv4 stack using "-Djava.net.preferIPv4Stack=true", this didn't help. All I want to do is send a non-blocking DNS request.

Exception in thread "main" java.net.SocketException: Invalid argument
    at sun.nio.ch.DatagramChannelImpl.send0(Native Method)
    at sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(DatagramChannelImpl.java:536)
    at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:513)
    at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:477)
    at Test.main(Test.java:31)

This is the relevant code:

public class Test {

    private static final byte[] request = hexStringToByteArray("674B010000010000000000000377777706676F6F676C6503636F6D0000010001");

    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                                 + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

    public static void main(final String[] args) throws IOException {

        String ip = InetAddress.getLocalHost().getHostAddress();
        int port = 1024 + (new Random()).nextInt(64507);

        DatagramChannel channel = DatagramChannel.open();
        channel.configureBlocking(false);
        channel.socket().bind(new InetSocketAddress(ip, port));
        int sent = channel.send(ByteBuffer.wrap(request), new InetSocketAddress(InetAddress.getByName("8.8.8.8"), 53));

    }
}

EDIT: Because it wasn't reproducible here are some versions:

jurgen@home:~/workspace/Resolver/bin$ java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
jurgen@home:~/workspace/Resolver/bin$ uname -a
Linux home 3.13.0-44-generic #73-Ubuntu SMP Tue Dec 16 00:22:43 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
jurgen@home:~/workspace/Resolver/bin$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.1 LTS
Release:    14.04
Codename:   trusty
jurgen@home:~/workspace/Resolver/bin$ java Test
Exception in thread "main" java.net.SocketException: Invalid argument
    at sun.nio.ch.DatagramChannelImpl.send0(Native Method)
    at sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(DatagramChannelImpl.java:536)
    at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:513)
    at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:477)
    at Test.main(Test.java:31)
jurgen
  • 325
  • 1
  • 11

1 Answers1

0

I think your problem is that you're explicitly binding the client's local socket to localhost by calling InetAddress.getLocalHost(). Instead of doing:

channel.bind(new InetSocketAddress(ip, port));

You should rather instantiate InetSocketAddress without specifying the IP part. The system will then bind the socket to all available interfaces (0.0.0.0):

channel.bind(new InetSocketAddress(port));

If you want to be explicit, you can also call like this:

channel.bind(new InetSocketAddress("*", port));

That solved the problem for me. The rationale is that the client socket must bind to the outgoing interface and not to the loopback.

Lucio Paiva
  • 19,015
  • 11
  • 82
  • 104
  • Sorry for the late response, you sent your reply while I was on vacation and I missed it. Your solution worked, annoying that I didn't see it :) – jurgen Feb 02 '16 at 09:27