[Development] Multiclient UDP server

Samuel Stirtzel s.stirtzel at googlemail.com
Wed Aug 23 11:32:11 CEST 2017


2017-08-18 22:37 GMT+02:00 Thiago Macieira <thiago.macieira at intel.com>:
> Related to the DTLS discussion, but I'll try to keep this free from crypto for
> now.
>
> The question is how to write a multi-client server operating on UDP, not TCP.
> It would be nice to understand SCTP case too (and maybe DCCP in the future).

Hi Thiago,
maybe I can provide some feedback.

This response is based on the information provided by the following RFCs:
Stream Control Transmission Protocol: https://tools.ietf.org/html/rfc4960
DTLS Version 1.2: https://tools.ietf.org/html/rfc6347
The Constrained Application Protocol: https://tools.ietf.org/html/rfc7252
UDP Usage Guidelines: https://tools.ietf.org/html/rfc8085


> B) multiple UDP sockets
>
> This is similar to TCP. Whenever a new client is detected, we create a new UDP
> socket and put it in connected mode with that particular client. Once you do
> that, this socket will only receive datagrams from that client, whereas the
> unconnected socket will not.
>
> Pros: scalability, since you can move the QUdpSocket to another thread; the
> connected datagram socket has another advantage that it can relay ICMP errors
> like "port unreachable" to the upper level, whereas the unconnected one won't.
> I also believe the connected mode socket can do Path MTU calculation.
>
> Cons: more resources, but more importantly, there's a race condition: the
> unconnected socket which you received the initial packet from the new client
> on may have queued more datagrams. Those datagrams can be:
>  - from the same client
>  - from other clients
>
> So we are in a catch-22 situation: if you connect() this socket and create a
> new unconnected one, any packets from other clients will not be seen. If you
> create a new socket and connect() it, you may miss any packets from the same
> client. I think that for both CoAP and DTLS, we'd opt for connect()ing the new
> socket, since the client wouldn't be sending new commands until it receives a
> reply from us. That reply resolves the problem of race condition.
>

Yes connect()ing the new socket is the only sane way.
The old socket could recvfrom() the data and forward it until the new
socket takes over.

There still will be a time window where a race condition could result
in duplicated datagrams.
However, according to rfc8085 UDP based protocols should be resilient
to datagram duplication.
Both DTLS and CoAP, just for the sake of an example, can handle
duplicated datagrams gracefully.


For SCTP the sctp_peeloff() call results into net/sctp/socket.c
sctp_sock_migrate() and it should just work.
It also migrates messages in the old socket's receive queue that are
for the peeled off association to the new socket's receive queue.


-- 
Regards
Samuel



More information about the Development mailing list