Hole-punching

This application implements UDP Hole Punching (http://en.wikipedia.org/wiki/UDP_hole_punching).  The application allows cooperating clients to locate each other and to communicate directly.  It consists of two parts: a server, which runs continuously on a public Internet host (currently home.contextshift.co.uk:60218); and a client that runs on computers that may (but need not) be behind behind a firewall.

Terms

Serverthe punch server.
Clienta punch client.
Supplicantthe initiator of a punch request to the server.
Correspondentsthe parties to a client-to-client connection.
Summary
Hole-punchingThis application implements UDP Hole Punching (http://en.wikipedia.org/wiki/UDP_hole_punching).
The Server:The Punch Server process is defined mainly in punch.c.
ClientsThe Client is defined mainly in punch-client.c.

The Server:

The Punch Server process is defined mainly in punch.c.

The application provides an open, anonymous service to users wishing to locate one-another and to communicate.  It serves only for client rendezvous, with all subsequent data transfers taking place between clients (peer-to-peer).

The Server forks (parent exits) to put itself into the background and then forks again; the child runs the punch service whilst the parent waits for child death on failure and re-forks to keep the service running.

Two ports are opened, one for TCP connections and one for UDP.  Clients attach initially to the TCP port and maintain this connection for the duration of their session.  Client traffic on its server connection, defined in Message Formats, consists of:

  • initial connection and introduction;
  • subsequent group membership updates sent from the server to the client;
  • requests from the client for a full list of group members;
  • punch requests, described in Clients below.

As all of these involve small amounts of traffic/data, the server does not fork to serve each client - the overhead seems unnecessary.

The server maintains a double-linked-list of groups, creating new groups upon request.  List entries contain the group name and password and the number of members attached.  The first member of a group specifies its password, if any.  When the last member leaves the group, the member count reaches zero and the group is deleted from the list.  Permanent groups with fixed passwords are defined manually by adding an entry (a file) in the groups directory.  The server checks this directory for changes and creates any newly defined groups before creating any dynamic group.  Permanent groups have their member count initialized to 1 instead of zero to prevent deleteion.

A double-linked-list of clients is maintained.  Each entry, created when a client attaches to the server TCP socket, contains:

  • the IP address of the client (unused);
  • the connection ID assigned to the client (for use in punching);
  • the socket file descriptor of the connection;
  • the client’s group and name - used for identification;
  • the email data - this is just reported to other group members for identification.

A new entry initially contains just the connection ID, socket and IP address.  The remaining fields are filled-in when the client introduces itself with a mandatory ‘intro’ message.

Logging

The server can log actions to a log file or to stdout.  The log file is defined on the command line.

Permanent groups

Groups are normally created on request.  Permanent groups can be created by creating a group directory that holds a file for each permanent group.  The file holds the group password (and may be empty if no password is required).  The group directory is defined on the command line.

Clients

The Client is defined mainly in punch-client.c.

The application supports a single client, which identifies itself to the server using a user name and a group name.  User/group name-pairs must be unique.  Group names are self-selected - ie. a number of users can agree on any desired group name, as long as it does not already exist.  Group names are dynamic: they are created upon first use and deleted when their member count falls to zero.  There is no facility for listing existing groups, so group naming and membership must be pre-agreed (between users).  When a group is first created (by the first member joining) a password may be specified.  Each user may optionally specify an associated email address or other extra identification information.

For details of name and password sizes and rules, see Message Formats.

Each client maintains a TCP connection to the Server.  The client receives a unique identifier (ID) when the connection is first created and identifies itself to the Server (with user/group/password and email address) across this TCP connection.  It receives update massages as other clients join and leave the group and can request a list of all group members; the client itself will be included in the list received.

The client presents a prompt to the user showing the user/group name in use.  It allows conversations to be started with other group members to exercise the hole-punching mechanism.

The commands available at the prompts are -

  • ? lists online group members;
  • /bell toggles the bell (announcing incoming communication);
  • /exit or ctrl-d exits;
  • /user starts a conversation with the user named ‘user’.
  • /close closes conversations.  With no parameters, all conversations are closed.  If user names are specified (e.g.  /close wrm,pcr) conversations with the listed users are closed;
  • /status sets the user status (eg “/status busy”);
  • /rtt toggles printing of round-trip ping times.
  • /help shows this information.

Once corresponding, any non-command text typed is sent to all correspondents.  If corresponding with several users, prefix text with ‘@name ‘ to send to just one

For a client to punch a hole and start a conversation with another group member, both ends must open UDP ports and both must be made aware of the corresponding address (IP address and port number) of the other end.  The Server facilitates this address exchange.

  • The supplicant client opens a UDP port and sends its connection ID and the name of its desired correspondent group member to the Server.
  • The Server uses the ID to associate the sending UDP port with the correct client (user/group) and forwards the request to the specified client (using its TCP connection), along with the UDP address of the supplicant.
  • The correspondent client responds to the request by opening its own UDP port and sending a similar message, in this case a confirmation, to the Server.  As it already knows the address of the supplicant (from the request message) it can also ping the address to open a port in its local firewall/NAT.  This ping might not get to the supplicant but will open a channel through the local firewall for a later supplicant ping.
  • The Server uses the ID in the confirmation message to associate the sending UDP port with the client (the supplicant) and forwards the request to that client (again using its TCP connection), along with the UDP address of the correspondent.
  • The supplicant now has the address of its correspondent (from the confirmation message) and can ping the address to open a port in its local firewall/NAT.  Because the correspondent has already pinged the supplicant, there is a hole in its firewall and the suppicant ping probably gets through to the correspondent.
  • At this point the connection is open.  Clients can now communicate through their UDP sockets without involvement of the Server.
  • Clients ping one-another periodically when not exchanging data to keep the channel open.

For details of messages and their formats, see Message Formats.

The formats of all prescribed message exchanged between participants.
The Client is defined mainly in punch-client.c.
Close