latysheff/node-sctp

SCTP over UDP

Closed this issue · 18 comments

ibc commented

node-sctp can run as level 4 protocol and can also work on top of UDP+DTLS (becoming WebRTC compliant). This is great.

Now, is it possible to run node-sctp directly on top of UDP (without requiring DTLS)? Use case:

We are planning to add DataChannel support in our WebRTC SFU mediasoup. Of course we need DTLS+SCTP support, but we plan to do it at C++ level. However, we want to also enable the ability for the Node.js application to communicate with the C++ worker via UDP and send/receive SCTP packets on it (those messages could then be exchanged with WebRTC endpoints using their DataChannel connections and so on).

I hope it should be easy to allow node-sctp to exchange messages by providing a Node.js UDP socket as transport. Is it possible?

NOTE: Of course I've read #2

Please check latest commit. Probably it will work for plain UDP now.

ibc commented

Thanks. I've tested the udp.js example and, indeed, it sends data over UDP to the given destination (the host/port in the updTransport object). However I've don't have yet my C++ SCTP side done, so cannot test much more, but it seems to work.

Thanks a lot :)

ibc commented

Just in case, you may want to also support connected UDP sockets (which are supported by Node UDP). But be careful: nodejs/node#28126 :)

Basically, if the UDP socket is connected, udpTransport should not require port and ip. Maybe it could be just connected: true, so node-sctp will not include port and ip arguments when it calls to udpTransport.send().

Thanks for the hint, connected UDP sockets should be supported too. And this behaviour was actually default (because DTLS is connected by nature), but not tested. I'll review the approach.

By the way, glad to see your interest, I'm familiar with your projects, and even use some of them!

ibc commented

Thanks @latysheff. Would it be possible to contact you in private (via email for instance)?

Sure. Same nickname on gmail.

Added more on UDP in new commit. Examples include scripts to listen and to connect (both old-style and v12 style).

Next task - support unexpected restart of association.

ibc commented

I'll gonna test this extensively on next days. However, since it's implemented, can this issue be closed?

Actually, no. Re-INIT connection is not working for now. Will fix it when have chance.

ibc commented

Can you please describe a bit what the Re-INIT connection is? So, it just fails in UDP connected mode? Or also in disconnected mode?

Doesn't matter, it is an internal issue. If you connect from the same port, server thinks you are inside existing association, and can't properly handle new INIT chunk.

Just run UDP examples with debug and you'll see messages like:
rfc4960 "5.2.2. Unexpected INIT ..

ibc commented

ok, will see it when I do my tests. Thanks.

ibc commented

I do not share the same UDP port at all for SCTP packets, so I'm not experimenting such a pending problem. Other than that and the PPID serious issue #5, SCTP negotiation and message sending/receiving is working fine, so good work.

BTW: When using SCTP over pure UDP (no DTLS here) I need to limit SCTP chunks size to 1200 bytes. This is, if for example I do this:

sctpStream.write(DATA_2MB);  // or hopefully soon: sctpStream.write(DATA_2MB, 52);

I need that node-sctp splits such a 2MB data into SCTP chunks of maximum 1200 bytes. Is it possible? I do not see any option to set something like MTU.

Try sctp.defaults({ PMTU: 1200 }) 0d3e9da

ibc commented

Thanks. Will test it in next days once I write code to send large messages :)

BTW, those sctp.defaults are global and not per socket, right?

BTW, those sctp.defaults are global and not per socket, right?

Yep

ibc commented

Just want to confirm that sctp.defaults({ PMTU: 1200 }) works incredibly well (if re ignore the PPID stuff :)).

I'm just testing SCTP over UDP (no DTLS). I've tried socket.send(ARRAY_BUFFER_24000_BYTES) by setting PTMU: 1200 and indeed I receive this in my SCTP server:

RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1176]
RTC::PlainRtpTransport::OnPacketReceived() | ---- received UDP packet [len:1068]
RTC::PlainRtpTransport::OnPacketReceived() | ---- it's a SCTP packet [len:1068]

RTC::SctpAssociation::onRecvSctpData() | data chunk received [length:24000, streamId:666, SSN:1, TSN:1882738555, PPID:0, context:0, flags:8]

:)

Super!

ibc commented

Sorry for the off-topic: Do you plan to publish a new release (git version tag and NPM version)?

BTW I think that the limitation exposed above could just be documented in the README. This is: "in pure UDP mode just a single SCTP association can be handled within a binding port".