medooze / media-server-node

WebRTC Media Server for Node.js
MIT License
802 stars 119 forks source link

Local candidate port issue #177

Closed NormandoHall closed 3 years ago

NormandoHall commented 3 years ago

I'm testing this great media server, but I have an issue with local candidate port, because I am behind a NAT and a router forwarding UDP range ports. I am testing with demo node REC, and get this on console:

$ node index.js xxx.xxx.xxx.xxx
[0x7f6c1e30e780][1622873215.943][LOG]>RTPBundleTransport::Init()
[0x7f6c1e30e780][1622873215.943][LOG]-RTPBundleTransport::Init() | Got port [34503]
[0x7f6c1e30e780][1622873215.943][LOG]<RTPBundleTransport::Init()
[0x7f6c1e30e780][1622873215.947][LOG]-RTPTransport::SetPortRange() | configured RTP/RTCP ports range [50000,60000]
[0x7f6c1e30e780][1622873216.013][LOG]>RTPTransport::Init()
[0x7f6c1e30e780][1622873216.014][LOG]-RTPTransport::Init() | Got ports [5004,5005]
[0x7f6c1e30e780][1622873216.014][LOG]<RTPTransport::Init()

As you can see I want to offer a port between 50000-60000 range, but I get 34053 (this is random every time I restart). Are there a way I can set this candidate port fixed to some value?

Thanks

nicholi commented 3 years ago

The first port, 34503, can be easily explained I think. The minLocalPort and maxLocalPort of RTPTransport are initialized to zero. These are used in RTPBundleTransport::Init() when choosing the random port, which will inevitably end up as zero. When zero is specified as the port when calling bind() for a socket the system's ephemereal port range is used, which is specified in /proc/sys/net/ipv4/local_port_range.

The values on most implementations are likely going to be 32768+. On Ubuntu it happens to be 32768-60999. Given this much larger ranger it can be seen how the first random port would be chosen.

After which you initialize the min/max to your range, 50000-60000. However what is a bit perplexeing is why RTPTransport::Init() chooses the ports 5004-5005, when you just set the range to 50000 at least. If there were a call to RTPTransport::SetLocalPort() this would explain it, as it is a mechanism to attempt this port on first try. After which reverts to random ports within RTPTransport::GetMinPort and RTPTransport::GetMaxPort if there were any problems binding.

I am not fully sure on the translation of these to the js classes, just yet. But I am also somewhat interested in being able to lock down the exact port ranges as well.

nicholi commented 3 years ago

It would seem the first port chosen in RTPBundleTransport comes from creation of an Endpoint, (via mediaServer.createEndpoint), which immediately calls Init() in it's constructor. Meaning prior to any call of createEndpoint() you must make a call to mediaServer.setPortRange() to enforce your range.

The second port seems to be chosen from the StreamerSession class, in which you can optionally attempt to force the port with the params object, params.local.port. Else it should default to the same range specified from setPortRange.

Untested, but just following the code.

NormandoHall commented 3 years ago

@Nicholi you're right! I call setPortRange before createEndPoint() and fix this issue.

thanks! Regards

NormandoHall commented 3 years ago

After which you initialize the min/max to your range, 50000-60000. However what is a bit perplexeing is why RTPTransport::Init() chooses the ports 5004-5005, when you just set the range to 50000 at least. If there were a call to RTPTransport::SetLocalPort() this would explain it, as it is a mechanism to attempt this port on first try. After which reverts to random ports within RTPTransport::GetMinPort and RTPTransport::GetMaxPort if there were any problems binding.

About 5004 is because I am testing demo, wich has broadcaster enabled RTP on port 5004, and of course, media server create + 1 port number for RTCP.