tags:

views:

293

answers:

3

I'm writing a UDP server, which is a first for me; I've only done a bit of TCP communications. And I'm having trouble figuring out exactly how to distinguish which user is which, since UDP deals only with packets rather than connections and I therefore cannot tell exactly who I'm communicating with.

Here is pseudocode of my current server loop:

DatagramPacket p;
socket.receive(p); // now p contains the user's IP and port, and the data
int key = getKey(p);
if(key == 0) { // connection request
    key = makeKey(p);
    clients.add(key, p.ip);
    send(p.ip, p.port, key); // give the user his key
} else { // user has a key
    // verify key belongs to that IP address
    // lookup the user's session data based on the key
    // react to the packet in the context of the session
}

When designing this, I kept in mind these points:

  • Multiple users may exist on the same IP address, due to the presence of routers, therefore users must have a separate identification key.
  • Packets can be spoofed, so the key should be checked against its original IP address and ignored if a different IP tries to use the key.
  • The outbound port on the client side might change among packets.

Is that third assumption correct, or can I simply assume that one user = one IP+port combination? Is this commonly done, or should I continue to create a special key like I am currently doing?

I'm not completely clear on how TCP negotiates a connection so if you think I should model it off of TCP then please link me to a good tutorial or something on TCP's SYN/SYNACK/ACK mess.

Also note, I do have a provision to resend a key, if an IP sends a 0 and that IP already has a pending key; I omitted it to keep the snippet simple. I understand that UDP is not guaranteed to arrive, and I plan to add reliability to the main packet handling code later as well.

+3  A: 

UDP packet headers have a source port, which is generally used as the reply port. If not used, it should be zero, and then it is up to the higher level protocol to figure out how to coordinate request-response activity with multiple clients.

Marcelo Cantos
+1  A: 

Your questions are just the tip of the iceburg WRT laundry list of issues you need to be aware of when using UDP. You should expect NAT routers to fail to provide any meaningful forwarding of a UDP protocol you design. TCP works because the routers understand the TCP state machine and store connection state of each session so they know how to forward it. They will have no idea how your custom UDP protocol works. NAT devices include specific protocol handlers for well known UDP applications.

If a sender is bound to a source port and or interface the senders source ports remain constant until unbound.

With UDP you can bind both peers to a known source port for (dst) incoming and or (src) outgoing messages. For client/server applications you typically want the client to bind to a dynamic source port so that multiple clients can co-exist on a single client system. The server can then respond to the client using the dynamic source port provided via the src port from request used as destination port in the response. Using a known port for peers allows you to configure UDP forwarding in NAT devices.

ex client/server with server on known port 3000

client binds to a random port (1234) but knows server is listening on port 3000. client (src 1234) -> server (dst 3000) server (dst 1234) -> client (src 3000) ...

If a computer has multiple interfaces you should expect to either need to explicitly bind a listener or sender to a specific IP address or be able to handle requests and responses from a peer being sent and recieved from a random IP based on the whims of the computers routing table. If you choose to bind requests to a specific interface then you need to be cognizant of the routing table if messages from a multi-homed system need to transit a different local interface for delivery. For example if you bind a UDP socket to 127.0.0.1 you obviously can't use it to send to any Internet routable IP Addresss.

In terms of protocol design its common to frame a session id and sequence fields in the UDP payload so that peers can keep track of sessions and individual exchanges.

There are a whole host of fragmentation, NAT coexistance, security and congestion issues you need to be aware of to successfully design a robust UDP protocol. I advise against it unless absolutely necessary.

Einstein
+2  A: 
* The outbound port on the client side might change among packets.

Is that third assumption correct

Not if the client keeps using the same outbound socket. Sending the first datagram will cause a local bind, so the socket will be on a fixed local port from then one.

EJP
This is how typical UDP protocols work. A single client is expected to keep using the same port during a single "transaction" or "session".
caf
Exactly my point.
EJP