0
votes

So i'm setting up a VoIP software and my connection thread to another peer has a UDP socket (to send audio) and a tcp socket for signaling/text. Now, to bypass firewalls and NAT, i need to use a TCP Hole punching technique, meaning i need to try and connect from this side of the call, which will open up holes in the firewall and NAT, and then i await a connection on the same port and the other peer should be able to connect to me.

    try {
        // UDP Socket
        DatagramSocket callSocket = new DatagramSocket(null);
        callSocket.setReuseAddress(true);
        callSocket.bind(new InetSocketAddress(myIP, 0));

        //Send/receive a few packets on callSocket

        // Addresses to use
        InetSocketAddress myAddress = new InetSocketAddress(myIP, callSocket.getLocalPort());
        InetSocketAddress targetAddress = new InetSocketAddress(InetAddress.getByName("192.168.1.1"), 6800);

        // TCP Hole Punch
        Socket tcpSocket = new Socket();
        tcpSocket.setReuseAddress(true);
        tcpSocket.bind(myAddress);
        try {
            tcpSocket.connect(targetAddress, 50);
            // this never connects. it's just meant to open a hole in a firewall
        } catch (SocketTimeoutException ignore) {
            System.out.println("Timeout!");
        }
        tcpSocket.close();

        // Open up TCP socket
        ServerSocket tcpTempSocket = new ServerSocket();
        tcpTempSocket.setReuseAddress(true);
        tcpTempSocket.bind(myAddress);

        // accept connection and do stuff
    } catch (Exception ex) {
        ex.printStackTrace();
    }

When i get to the 3rd and final bind, i get the "Bind Exception: Address already in use". I googled it up and read that the previous socket could still be hanging on something and wasn't closing, etc.

EDIT: this only happens in some computers. On others, it binds everything without an issue

EDIT: using "netstat", i can see that the connection is being hung up on "SYN_SENT" state on the computer where the bind goes wrong

Anyone have any tips on why this happens or how to i go around it?

1
Close the TCP socket correctly. Just calling close is not sufficient. You need to shutdown the sending side, then continue trying to receive until you get a normal close, and then you can call close on your side.David Schwartz
In windows, you can check which port is already being used in the control panel using pid.Prince
@DavidSchwartz no connection is actually established at that connect. It's just meant to open up firewall exceptions to allow incoming traffic. Meaning i can't shutdown the sending side and no "close"s will ever be received.BlueMoon93
A connection is indeed established by that connect(). That's what connect() does. You can indeed shut it down, read from it, receive EOS, etc. Try it.user207421
When you call close without attempting a graceful shutdown, the TCP stack attempts to terminate the connection attempt. Until it finishes, you cannot bind to the same address again -- think about it -- what would happen if it allowed the bind and you attempt to make an outbound connection to the same IP and port? How would it know which connection attempt packets it received referred to? You are forcing the very condition you don't want.David Schwartz

1 Answers

0
votes

Ok, so. The answer is... You can't go around it. This is an OS feature, which makes tcp connections get hung up on this port. On some computers it may take 5seconds to clear. On others, it may take over 2minutes.

Now, what i've done to get around this was... well, the only thing i could think of. When the program starts, it checks whether it supports tcp hole punching, or other ways of bypassing firewalls. The peers, when establishing the call, will trade parameters based on what they can do and, from a given priority list, choose a method they both support.

In my case, on my computer, TCP Hole Punch works. In my mum's laptop it doesn't, and i resorted to other techniques (UDP Hole Punch, UPnP, SOCKS, etc etc)