latysheff / node-sctp

SCTP userspace sockets for Node.js
MIT License
59 stars 10 forks source link

SCTP over UDP #3

Closed ibc closed 5 years ago

ibc commented 5 years ago

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

latysheff commented 5 years ago

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

ibc commented 5 years ago

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 5 years ago

Just in case, you may want to also support connected UDP sockets (which are supported by Node UDP). But be careful: https://github.com/nodejs/node/issues/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().

latysheff commented 5 years ago

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 5 years ago

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

latysheff commented 5 years ago

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 5 years ago

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

latysheff commented 5 years ago

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

ibc commented 5 years ago

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?

latysheff commented 5 years ago

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 5 years ago

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

ibc commented 5 years ago

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.

latysheff commented 5 years ago

Try sctp.defaults({ PMTU: 1200 }) https://github.com/latysheff/node-sctp/commit/0d3e9da936caab54da165832925ca16352eaa450

ibc commented 5 years ago

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?

latysheff commented 5 years ago

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

Yep

ibc commented 5 years ago

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]

:)

latysheff commented 5 years ago

Super!

ibc commented 5 years ago

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".