Frank
Frank

Reputation: 53

TCP ports in Erlang

I'm using Erlang to code a bittorrent client. I have been stuck for 4 days now on the same problem.

I'm sending the handshake to all the peers with each peer having its own ip:port.

I use gen_tcp:connect to connect.

The problem is that I can't get their reply. I have done a lot of research and used some programs to monitor my inbound/outbound connections.

The peers get the data and send the reply back to the port that I used to send them the handshake.

Code wise: get_tcp:connect picks a port and uses that port to send the data to a peer. The peer replies back on that port. However, as you know in Erlang you need to use gen_tcp:listen to pick up the reply connection and you need to specify a port. In my case the port that I should be listening on is the port that gen_tcp:connect returned.

I can get this port number using inet:port but the error is always the same: port in use. I understand why I get the error, it's simply because the port I'm trying to listen on is already being used by gen_tcp:connect. I tried to close the Socket to free the port but nothing.

So my question is: is it possible in Erlang to somehow connect to a peer and send data to it to port then listen on that same port for a reply. If not then I must somehow be able to tell the peer to send me the data back on a port I choose.

Any ideas from all the Erlang gurus are welcome. Thanks,

//Frank.

Upvotes: 4

Views: 2069

Answers (2)

I GIVE CRAP ANSWERS
I GIVE CRAP ANSWERS

Reputation: 18879

Bittorrent has two ways peers can connect to each other:

  • Your client initiates the connect to the peer, this is gen_tcp:connect. The connection once established is bi-directional and this sole connection is what you use for all communication.

  • The peer connects back to your client. This is the gen_tcp:listen path followed by gen_tcp:accept. Again, a bi-directional connection is established which you then use.

You see the port-in-use probably because you are trying to create a connection "on top" of the connection you already have. It might be worthwhile to read up a bit on TCP connections.

A viable solution path is to begin by assuming you only connect to others and ignore inbound connections. Run against a test client which does accept connections inbound and everything will work. You can then add inbound connections to your code when one way works. Note that the handshake is similar, but there are some slight differences. The connector sends the info_hash to the connectee first for instance (so the connectee can look up the infohash among the torrents it is currently serving).

Upvotes: 1

Peer Stritzinger
Peer Stritzinger

Reputation: 8372

Something sounds wrong here, let me summarize what you are trying to do:

  • You are using TCP connections not UDP

  • A TCP connection looks like this:

    Erlang side: IP1:Port1   <---->  Peer side IP2:Port2
    
  • IP2:Port2 is the port you pass to gen_tcp:connect, IP1 is just the IP of the interface on your local machine and Port1 is probably a ephemeral port chosen by the TCP Stack on your machine.

  • If the peer replies back on the same connection you will just get the data as

    {tcp, Socket, Data}
    

    messages as the port owner (process who calle connect probably). Except when you are using passive mode: then you have to call gen_tcp:recv og get the data.

  • If you are calling gen_tcp:listen instead you try to open another connection going back. There are protocols that do this kind of stuff e.g. FTP but you have to use another port number (usually call listen, then get the port number and send these over the existing connection to the client who can the connect to the existing port). But almost all newer protocols don't do this anymore since its kind of messy and needs stateful firewalls. Even FTP is avoiding it nowadays. So I strongly suspect you don't want to do this.

Upvotes: 6

Related Questions