jselbie / stunserver

Version 1.2. This is the source code to STUNTMAN - an open source STUN server and client code by john selbie. Compliant with the latest RFCs including 5389, 5769, and 5780. Also includes backwards compatibility for RFC 3489. Compiles on Linux, MacOS, BSD, Solaris, and Win32 with Cygwin. Windows binaries avaialble from www.stunprotocol.org.
http://www.stunprotocol.org
Apache License 2.0
1.45k stars 350 forks source link

Nodejs Addon #9

Closed formula1 closed 8 years ago

formula1 commented 9 years ago

This is an Enhancement

This server is clearly one of the best out there. However, creating a wrapper for it doesn't allow nearly as much control as having this server as a javascript object.

Why?

I wrote some psuedocode a while ago when I was trying to do it myself. However, my lack of c++ experience makes me worried I'll be spending a long time trying to learn the language rather than develop an application. Honestly, I don't like making requests because I know how requests feel. However, I also realize that if I never ask it may never happen. I also have taken a look at your code to see what would need to be changed, though I understood a reasonable amount of the low level aspects due to my Java experience I looked at things from a much higher level.

My original Plan

This was the documentation I was attempting to base it off of

After looking at your code, the files I believe that will need editing will be

I understand if you're not interested in doing this. Just figured I'd mention it

jselbie commented 9 years ago

Hi Sam,

Thanks for reaching out. I think you have some interesting ideas here. I think you are proposing 2 or 3 different things. While I know Javascript, I'm not that familiar with Node.js, but I think I know what are you suggesting. Let me summarize what I think you

  1. The ability to start and stop the server from a Node.js application and run within the Node process. And I think you are correct about changes to main.cpp. I suspect that we would need to just recompile the STUN server code base as a dynamic/shared library (dll or so file). We'd just need to expose a "start" method (that takes equivalent parameters as the command line) and then a "stop" method to turn it off. If you look at what "main" does, you'll see that all it does is parse the command line parameters that are used to initialize the CStunServer object. Perhaps we just need a proxy class in the C++ code to bridge between Node/Javascript and the CStunServerObject.
  2. Authentication. You have likely noticed that all the work to parse the STUN protocols authentication fields and authentication protocol responses have been implemented. It's just that the code that actually says, "yes or no" to a user and credentials is just stubbed out as an interface with some notes on how to implement (look at stuncore/StunAuth.h and server/sampleauthprovider.cpp). For Node, we'd just need a way for the Node code to expose and object to the C++ code that implements "DoAuthCheck" - and I think I see that's what you are trying to do in your pseudo code.
  3. Or do you want to run the "stunserver" as its own process and let it invoke Node code directly for the authentication validation? I don't think this is what you are asking (I think you want #2 above) and I'm not sure if that's something Node allows for. But we can discuss it if that's a possibility.

In any case, the reason why I left the authentication code unfinished is because no one has ever asked for STUN authentication. That, and I do not know of any client devices that have STUN authentication support. Does WebRTC support authentication parameters to a STUN server? Or what scenario did you have in mind?

Anyway, we're setting up the tree tonight at the house, so I'll reply back more with details tomorrow or the day after. I need to familiarize myself again with the different STUN auth mechanisms and look at those docs on Node/C++ interop that you sent me.

An interesting collaboration might be that I do the work in the C++ code to allow the code to compile as a shared library (with objects exposes to implement #1 above), and then you consume it in Node code. Then we move on to implement #2 together.

Let me know what you think.

jrs

formula1 commented 9 years ago

:) Thank you for the response, I'd be happy to help you any way I can. But most importantly, enjoy your holidays!

1) Starting and Stopping with configurations - Without a doubt that is what I had in mind. The "main" file seemed mostly about parsing command line arguments though there are some functions I believe can be reused such as BuildServerConfigurationFromArgs

2) From what I can tell, authentication is done in GET variables (which is highly insecure however... I guess thats just the way the web works?). That being said a yes/no boolean is perfectly reasonable to convert to something you would need. And all that probably needs to be passed to the listener is the url. Though passing the headers would also be good when applicable

3) It would probably be best if it was integrated into node. However, if that idea is too big for right now, I can write a wrapper that would call it as if in terminal, listen to the stdout and stderr and send a kill signal when I want it to stop. For Authentication, with your help, we can

Heres some examples of servers and tcp in node

Now, I'm not sure how the peices fit togethor, though I could probably figure it out with enough time. But hopefully these examples give you a view of how move code from outside v8 to within. Maybe it doesnt at all.

jselbie commented 9 years ago

I created a branch called "nodejs" to prototype this. I got the code compiling as a nodejs module and have a single-port server running in a test app:

https://github.com/jselbie/stunserver/tree/nodejs/nodejs

Take a look at the test.js, binding.gyp, and binding.cpp files

At this moment, it just allows for us to say:

var stun = require('./build/Release/stunserver');
var result = stun.startserver(3478);  // 3478 is default UDP port for STUN

Next steps are to actually expose CStunServer C++ class as a javascript object and then allow a way for the auth code to call back into javascript.

Can you give it a try and let me know what you think?

formula1 commented 9 years ago

It gets started no problem, I'm having a problem testing though

I'm feeling a bit dumb right now to say the least.

If you want to test that out

From there you can

but locally there there is nearly no purpose. I was initially going to make a pull request but I don't think thats proper here.

Edit - I am dumb stunclient localhost

jselbie commented 9 years ago

Why not use the "stunclient" command line tool https://github.com/jselbie/stunserver/tree/master/clientthat comes with the stuntman stun server code base? At the command prompt you just type something like:

$>  stunclient stun.stunprotocol.org 3478

And it will print out the NAT test results. (Type "stunclient --help" for more details)

If you need a test stun server, you can always use stun.stunprotocol.org (port 3478). Wherever you are at (work or home), you are most likely under some sort of NAT environment - so the externally hosted server should work fine for you.

Just out of curiosity - does WebRTC (as implemented in the browsers) support authentication for STUN ? I ask because I was under the impression that most clients did not support STUN authentication (but do for TURN). How does WebRTC allow for clients to pass the username and password fields?

jrs

On Mon, Dec 8, 2014 at 11:34 AM, Sam Tobia notifications@github.com wrote:

It gets started no problem, I'm having a problem testing though

I'm feeling a bit dumb right now to say the least.

If you want to test that out

  • cd stunserver/nodejs/servertest
  • npm install
  • bower install
  • node .

From there you can

  • open up the webpage listening on localhost:3000
  • Click a name - this will go through the offer accept routine
  • once the button highlights green, you should be all set

but locally there there is nearly no purpse

— Reply to this email directly or view it on GitHub https://github.com/jselbie/stunserver/issues/9#issuecomment-66172356.

formula1 commented 9 years ago

I totally forgot about it v_v, I specifically remember looking at all the tests and utilities as well :C

After Work, I'll let you know my results

formula1 commented 9 years ago
$ client/stunclient zorrix.com 3478
Binding test: success
Local address: 192.168.1.118:44865
Mapped address: x.x.x.x:44865

$ stun zorrix.com:3478
STUN client version 0.96
Primary: Independent Mapping, Independent Filter, preserves ports, no hairpin   
Return value is 0x000013

screenshot from 2014-12-08 21 27 48

Its beautiful. I'm now quite confused on whether or not I got it working successfully before. Obviously, I was mistaken. Nonetheless, I am pleased!

One thing I got caught up on for 5 minutes was the fact it runs by default in udp. That may be better, though because almost everything I work with is tcp, I avoided trying anything new during my initial tests. That being said, I'll take a look at your v8 code and see if I can copy your style so I can be helpful

Update

I'm looking for a solution to the loop problem

Can't say for sure, but from what I understand about node, its single threaded that just keeps pushing function calls on a stack. The only thing we need is to keep the thread alive without blocking. setInterval is an option, however its still not pretty. I'm assuming your depending on the OS to let you know when something hits the port, which means you don't need to poll, nor even run a loop which should reduce strain on the rest of the environment.

formula1 commented 9 years ago

https://github.com/formula1/stunserver/compare/jselbie:nodejs...auth?expand=1

It builds, I have no idea if it works or not though. How do I test this?

formula1 commented 9 years ago

So I've made some progress but I've hit more snags

I now am slightly educated on segmentation faults and understand they are associated to

I edited the original code mostly in three places

These are the obstacles I hit

jselbie commented 9 years ago

In server.h, declare the "stunAuth" member added to CStunServerConfig as follows:

CRefCountedPtr<IStunAuth> spAuth;

At the very top of the CStunServer::Initialize(...) method, remove this line:

CRefCountedPtr<IStunAuth> _spAuth;

That line should be declared in the CStunServer class declaration, but not as a local member variable.

Change this block of code that was added:

if(config.stunAuth != NULL){
  Logging::LogMsg(LL_DEBUG,"We have stunAuth UDP");
  *_spAuth = *config.stunAuth;
}else{
  Logging::LogMsg(LL_DEBUG,"We don't stunAuth UDP");
}

To be this:

_spAuth = config.stunAuth;
Logging::LogMsg(LL_DEBUG,"We %s have stunAuth UDP", (_spAuth != NULL)?"do":"do not");

Make the same corresponding change in CTCPServer::Initialize

formula1 commented 9 years ago

Yes sir!

formula1 commented 9 years ago

Made those changes, still segmentation fault. I'm clearly missing something here

I saw before you had a CreateInstanceNoInit Though I avoided subclassing from this due to fear of not being able to construct with a reference to the appropriate node compatible instance.

I considered making the Server also an IStunAuth but I decided against it to avoid complicating things further

Perhaps its time I did more research into templates

formula1 commented 9 years ago

So, I figured out where and why the segmenation fault was happening - http://stackoverflow.com/questions/12153998/how-do-i-use-v8-in-a-thread

A solution could be to unlock v8 when a new socket is created. This has taken me far longer than I wanted and since I have a far better understanding of how it works from a psuedocode/protocol standpoint I may start looking in that direction. You have been a really great help. Thank you for everything.

jselbie commented 9 years ago

I was feeling bad that I had not responded in a while. Caught up in the holidays. Are you putting together a new pull request?

On Mon, Jan 5, 2015 at 11:35 PM, Sam Tobia notifications@github.com wrote:

So, I figured out where and why the segmenation fault was happening - http://stackoverflow.com/questions/12153998/how-do-i-use-v8-in-a-thread

A solution could be to unlock v8 when a new socket is created. This has taken me far longer than I wanted and since I have a far better understanding of how it works from a psuedocode/protocol standpoint I may start looking in that direction. You have been a really great help. Thank you for everything.

— Reply to this email directly or view it on GitHub https://github.com/jselbie/stunserver/issues/9#issuecomment-68835057.

formula1 commented 9 years ago

Sir, don't feel bad. I have been fully enjoying the holidays, though I probably would have enjoyed more working on this or other things. I was also been purposefully trying to keep your attention by being as active as I can be.

Any pull request I can give is hardly progress unfortunately (though it took me a while to figure out this is the issue).

Both of which are unstable and neither working.

A solution may be libuv's queue work. Since thats what node runs in, its already available (libuv is how I keep the server alive now without running an infinite loop or a setInterval call [though technically what I am doing is a set interval call]). But my brain is pretty fried at the moment

wtcross commented 9 years ago

Having node bindings would make stunserver amazingly powerful/flexible in a lot of ways. Thank you for doing this work so far.

formula1 commented 9 years ago

It's partly for selfish reasons of course, since I wanted it as well. But I feel lucky that this was created in the first place so I could attempt. It's tough advertising these types of projects as something that should be helped with. But I think anyone involved with serverside javascript would see this or a similar project as a convenient tool in the long run

jselbie commented 8 years ago

Closing out for now. We can revisit node integration later.