Spidermonkey with steamworks p2p?

Steam has a neat feature which, if you use steam’s api, handles usual p2p connection problems for you (hole punching and even relay servers if that doesnt work).
It requires you to use steamworks’ read and write methods instead of a custom socket for every steamID you’re connecting to.
Now here’s my question for the people who know spidermonkey’s internals better than I do:
How much work it would be, to convert spidermonkey to use above described steam api instead of regular sockets?

I don’t know anything about Steam’s API… but assuming you wrap it all in Java then it may just be as easy as creating a new connector type.

That actually sounds great!
Wrapping it into java is already done by an excellent library steamworks4j.

The key to remember is that the Network class is just a set of convenience methods for instantiating typical servers and clients. You can use whatever custom endpoints/connectors/whatever pretty easily if you create your client and server directly, I think. It could be you also need to extend the default client and server but I’m not sure.

I designed it to support custom connectors in the core but I may not have exposed it well since we never had a real use case for it yet.

Hey @grizeldi,
have you made any progress? I want the same feature: use of jme network via steam P2P.

1 Like

Not much. I tried to understand spidermonkey’s internals, but still have no idea what some things do, so I just gave up.

You could always ask… I wrote it, so you have access to that actual coder. :slight_smile:

4 Likes

I’m also interested in that as I also use steamworks4j and the sim-eth-es example as a base. But I will first try to find out how I could inject an own connector (as far I understood that is all I need more or less).
In case of questions I know now who I will mention then :smiley:

I have the classes needed for this somewhere, but most of them are missing implementations. I can post them here if it would help.

2 Likes

I’m in the middle of writing an implementation. It doesn’t mesh very well with a lot of the existing spidermonkey code. I originally attempted to write steamp2p as a different connection type but I ran into a lot of problems with that fitting cleanly in the existing architecture. I took a break to work on some other issues but I am going to dig into it again shortly.

2 Likes

So i’ve made some progress on this. its going to require a bit more setup than most connections, however, since you really need some way to get the connections in the first place. Steam P2P works using their SteamID system which makes it a little more complicated. You basically need some sort of Steam App State that handles a lot of the queries and things you need to make it work.

They also technically have 3 different connections systems that all function a little differently (IE Lobbies, Servers, and join from friends). I’m trying to keep this as decoupled as possible so I can eventually extract it into its own lib.

So far I’ve got a dedicated server running that interfaces with the steam master server list and I have the initial handshaking between the client and server running. There is still some weirdness with the connection process that I haven’t figured out yet. Like when you first attempt to connect Spidermonkey sends 2 packets (25 and 18 bytes) and usually only the first one is received and the connection times out. Then if you attempt to connect again it sees both and starts connecting. So, I still have a lot to figure out, but i’ve made good progress.

4 Likes

@pspeed So i’ve slowly been working on getting steam working with spider monkey and I have a few questions for you. So first off… After I figured out a few of my own errors and created the connector, kernel and endpoints spider monkey mostly worked so A+ there.

So my first question is about the initial client registration that takes place. Basically, I see 2 packets being sent out initially. One 25 byte packet for the reliable channel and an 18 byte packet for the unreliable channel. Steam p2p seems to lose that first unreliable packet pretty frequently which causes the application to time out. I’ve worked around this by forcing the unreliable packet to be sent reliable (since the underlying steam connection handles both anyways) and it seems to work. Is there something i’m missing here? Does spidermonkey really rely on the first unreliable message to get through?

My second question is around channels. Specifically, is there a reason that the KernelFactory was hard wired in the default server? I’m assuming it was just missed since spider monkey has really only been used with tcp and udp connections in the past. If i’m reading the code right… I don’t think I can use anything beyond the default channels at the moment.

Regarding the second question I vaguely remember creating my own Client and Server implementations along with a factory for them so I could use custom connectors.

If you do not send an unreliable packet then the server will not know where to send unreliable packets back to the client. You need that first UDP packet to punch through the firewall.

Maybe steam is not using UDP or is doing its own punching… but it’s sort of a near-physical limitation of NAT that you must know what port to send UDP packets back to.

Regarding the other, the original intent was to create your own server in these cases, I guess. The server itself may have been a bit simpler back then but often once you get outside of TCP and UDP there may be more management involved that the server will need to take care of anyway (for example making sure SSL certs are available, etc.).

Steam uses a form nat hole punching and if that fails it can relay off the steam servers. I understand why you need to send that packet… my question is more how is it not a bug that spidermonkey depends on that packet getting through in order to start? Since it’s unreliable it stands to reason that it could fail to reach it’s destination. I’d be the first to admit that my understanding of networking isn’t the best so I wouldn’t be surprised if I was missing something here.

As far as the default server goes… i’ll have to rethink my implementation a little bit then. There are certainly parts that I can make cleaner if I can integrate steam more directly.

I have experience in server architecture. My question is why are you depending on a receipt of a UDP packet? You can’t. You shouldn’t. The whole point is not to. The fault in the arch lies there. There is no reliable way because it’s designed specifically to be that way.

So my question is why? The server does not know where to send a response but it shouldn’t send a response if it’s never been contacted. A response is actioned by a request.

In any event, could your data not be given by a TCP packet instead, and then proceed to UDP thereafter?

Well that’s ultimately what i’ve done in order to consistently connect using steam p2p. I’ve forced the first packet for the “unreliable” connector to be sent as reliable instead. It’s a bit of a hack, but I wanted to check to make sure I wasn’t missing something. I’ve had users that have attempted remote games just not start or be unable to connect and from what i’ve seen from the logs… I imagine they were running into this issue although i didn’t know it at the time.

If you’re relying on it, TCP is the protocol you should be using. It’s not a hack really, it’s in accordance with your requirements. It’s more of a trigger packet, really.

Yea, I mean it makes sense to bypass that for Steam p2p. That being said, shouldn’t the default client periodically send that UDP packet until it gets a response? From my naive understanding it looks like if you use tcp / udp there is a case where your server just locks and never connects if that udp packet happens to be dropped or go missing.

1 Like

Continually firing it until you get it can work, but again, you require a guarantee, do you not? Which is what the slower TC protocol does. If you don’t care about the information being recieved (e.g. a location of a player, because it’s continually being sent) use UDP.