Sign in to follow this  

creating basic lobby services

This topic is 1069 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, I have seen some simular threads here but not one that specifically gives me the info i'm after.

 

I would like to create a fairly simple barebones (to start with) lobby server. I have an existing, finished game that was originally on Xbox360 and used the live services. I've since ported it to pc and rewrote the network using Lidgren - it's finished and working. One player can host and another can connect to the IP and play the game. Now I want to create and host a proper lobby server, I have a pretty good idea what i'm doing but wanted to get some opinions before I charge in blindly!

 

What i'd like to create is a service I can use for ALL games I create - think of it as a mini (reallllly mini) battle net. So the server will be running, through admin controls i'll setup "games" it knows about with unique id's and once a client has connected and registered what game it belongs to the client will be able to send request packets for game listings (i figure a list of gameid + some string to identify it in a human way, be that host name or some name the hoster has set for his game room) and then later request full game details (ip, etc) by passing one of the ID's.  At it's most basic level /thats it/.

 

No multiplayer game logic, no real communication with the players once they've started their private game session (except perhaps something to say a game is in progress or has finished and remove it from list). It should be quite light.  Later on I will add leaderboard services (which my mobile apps can also use simply for online scores) and probably lobby chat - i'd like players to be able to chat in the lobby before whatever game they are playing actually starts.

 

Sorry for the waffle tl;dr etc but I wanted good clear explination of my intent. Here's where I want to get advice before I storm in: given I want this to be an expandable system for use in my current and FUTURE games and that any dev's hope is that their games are successful what do I need to watch out for and how should I handle the storing and sending of data in a way that scales and doesnt die if I have say 5 games using the server that are all moderately successful with thousands of players wanting to host and search for games each? Even simple game listing and basic chat can start to become an issue when 10k clients are attempting it.  I sort of figured I might store games in progress and games availible to join in a sql database? or would that be a bad idea? Just in ram would be faster to access but that could get large, fast.  Should I be looking at some sort of compression for chat strings to minimise packet size?

 

Any advice at all would be greatly appreciated! I could run in and "just make it" but i'm sure i'll get got by something later on.

 

Incidently i'm most likely to write this in c# - though c++ is also an option.

Share this post


Link to post
Share on other sites
Do you want a single server process to be able to handle a multitude of games? If so, each request would need to have a game identifier. It might be simpler to say that you run a different service (on a different port/host) for each different game.

Typically, you'll want login information to go with lobbying. I e, if a user says "I'm Britney Spears," you have to make sure that that user is, in fact, uniquely registered as Britney Spears; typically using a password. And, once passwords/logins are involved, you either get into sophisticated key exchange schemes (which are harder over UDP,) or you end up first establishing a session key using TLS/HTTPS, and then verifying that key once provided on the UDP session. I recommend the latter :-)

So, you'd want some service that accepts username-and-password, and provides session-key. That service also accepts username-and-session-key and returns "yes" or "no" (for use by the lobby.) Alternatively, the session key can contain the user name and a signature using a shared secret with the lobby server.

The lobby then accepts username-and-session-key, and then accepts host-game-parameters or find-game-parameters, and provides updates to the client based on whether matches are found. A nice variation is if the client provides general-game-parameters, and the lobby server first finds someone hosting; if not found, it turns the client into a host, and makes it wait for other clients -- that way, a player doesn't have to decide whether to be host or client. When the wire protocol tells the client whether to host or be client, you can then later make "smarter" decisions on who hosts (based on reputation, networking, payment plans, etc) without changing the client software.

Additionally, you'll probably want the lobby server to provide NAT punch-through introduction services.

Finally, you want a log of things-that-happened to come out of both the session server and the lobby server. That way, you can debug and audit the operation of the system.

Share this post


Link to post
Share on other sites

Firstly: thanks for your reply, some good information there! :)

 

I'm intending to host this service on the cloud (microsoft azure). I am part of the bizspark program so for a couple of years I get $150 of azure credits every month so it provides the perfect platform for testing the viability of this software I think! I was intending to have a single server to handle a multitude of games as it seemed to fit well with what I understand of cloud computing where an application can scale and be granted (or removed) extra resources as and when required.

 

NAT Punch through is definitely something I should look into and had not considered.

 

The truth is I know that right now I can sit down and write this software straight away and i'd have no concerns if it was just for a single game because if I do something inefficiently it would be unlikely to ever show with todays computing power and high speed internet etc. But with this goal of being able to, for sake of argument, "infinitely scale up" adding more games each with their own player base I find myself questioning myself and what I know and what is the best way to store data (despite the fact I know SQL is used for HUGE performance critical programs, silly me!) and wonder what sort of pitfalls there are that I have never considered!

 

I'm going to go google for this TLS/HTTPS session key method you suggest for authentication - do you possibly have any links to useful articles on it or any subjects related to this task that you think I should read?

 

Thanks )

Share this post


Link to post
Share on other sites

cloud computing where an application can scale and be granted (or removed) extra resources as and when required


Note that your application will not scale across hosts in the cloud unless you explicitly build it to be federated. Is that a goal of yours? Federated matchmaking is really, really, hard. And not needed for any game you're likely to create on your own :-)

do you possibly have any links to useful articles on it


I wrote a chapter in one of the Game Programming Gems books about it.
A web page variant of that chapter is here: http://www.mindcontrol.org/~hplus/authentication.html

Share this post


Link to post
Share on other sites

really, really good read! I feel pretty confident about tackling user authentication now, thanks! Infact overall I feel pretty good about prototyping this server now and giving it a spin.  I do have one last question for you though:

 

Given that this servers job is ONLY to register and list hosted games and later perhaps provide lobby chat and some other basic lobby functions - what sort of CPU power and ram am I going to be aiming for?  Azure lets you be very specific in what you need when it comes to number of cores and amount of ram.  With most of the data stored in a DB instead of active memory im thinking lots of ram isnt a requirement, but i've never really considered how CPU intensive network traffic is *scratches chin* what do you think?

Share this post


Link to post
Share on other sites

The main things you need are authentication, game-selection and/or matchmaking, and facilitating NAT punch-through. This could all be done as a RESTful service. I would suggest that the easiest way to design such a thing would be to have the lobby service deal with only one game, but you can run multiple instances of the service bound to different network endpoints to service multiple games.

 

Depending on how forward-looking you want to be, the next version of Windows server will support containerization (similar to linux containerization LXC, as popularized by Docker) which would probably be the best long-term solution of all. Azure will support this as soon as its ready. A container is essentially a way of running an application or service is a way that's completely isolated from other containers, and hence you can treat the system as if you're the only one running -- each container can have its own dependencies that might otherwise conflict with those required by other containers, for instance. It has the advantages of a VM but is lighter-weight because you're only using the resources required for the application and its dependencies, not a distinct OS stack for each application. You can do this on azure today if you wrote the service for linux, since you can run Linux on Azure. The benefit of containers is that you can test locally the same exact container that you will run in the cloud, or toss the container over to whoever provides you the best value for hosting containers. Google and lots of other huge web-services companies have (or are) adopting containers like mad because of their benefits for DevOps, they really are the wave of the future.

Share this post


Link to post
Share on other sites

hmm, containers sound very interesting!

 

I learned a long time ago to not just ignore the advice of experienced dev's just because it doesn't match my original idea and a prevailing theme from everyones replies has been to have a seperate instance of the lobby server for each game using it. I'm really taking that on board but I have a few questions specifically about it :)

 

My original concept for the one instance was having a sort of start-it-and-leave-it-alone server that through a control panel (be it local or through a web interface) I could add "game" instances to it which it would give a UID to identify and I could configure some basic information such as if I add achievements later on a list of such achievements for that game, etc etc. Later on I might add a very basic friends system so people could see when their friends were online and what game they were playing using this lobby. I can still do all of that with seperate instances as long as they share one common database of course.

 

But what if I said that in the back of my mind is the vague idea that if this works and prooves stable with my games that I may in the long term offer the service to other small indie devs who need a bare bones framework for game discovery in their multiplayer games but are not using steam or LIVE and can't afford the starting cost for services like smartfox (and do not need the excess of features!) or the VM/Cloud subscription fees? Would you still suggest a seperate instance for each game? That could become.. quite alot of instances if it took off!

 

If I keep as one instance of the server, reading and storing data to a SQL db and then sending it to connected clients (but never doing game logic and having nothing really to do with games that have been "started" except an occasional poll to see if they still exist if game requires "game in progress" to be visible for additional players to join) then what sort of problems should I expect to encounter? Programmatically its a very simple thing to add multiple games to the server, it's just one more level of structure (ie instead of "foreach gameroom" it becomes "foreach game { foreach gameroom } }") so I am assuming that people suggest a seperate instance for each game for phsyical reasons such as processing and memory constraints? What else do I need to know?

 

So many thanks from me to everyone involved in this discussion, it's been a treasure trove of information :)

Share this post


Link to post
Share on other sites

facilitating NAT punch-through. This could all be done as a RESTful service.


NAT punch-through does not work over REST because of the low-level networking details involved -- basic NAT actually uses UDP! Even TCP NAT cannot be done REST-fully, because it relies on persistent connections and re-using local port numbers.

Game matchmaking CAN be done REST-fully, assuming that you're OK doing long-waiting on a match. I e, the client would issue a HTTP request for a game match, and the server wouldn't return the match until a match was actually made, stalling the request 1-20 seconds while searching.
The reason you don't want to do multiple REST requests for matchmaking, is that you'd run into situations like this:
1) client issues REST request to "put me into the queue"
2) client's supposed to poll every so often for "did I find something"
3) clients queue entry gets match to a game
4) however, client shut down, and server doesn't know about it, so other players are matched with a zombie player

Matchmaking is not a great match to the REST model. It's real-time data -- it's not cacheable. REST works best when data has some amount of cacheability lifetime.

Share this post


Link to post
Share on other sites

Sorry, "facilitating" was too vague -- I merely meant exchanging whatever information was necessary to begin NAT punch-through between the peers, not performing punch-through itself. In practice, that's probably not much info at all.

 

As for REST, I would think it would be sufficient to set the response to not be cached, no? True, its then a polling API, but you can code around the dropped-client issue, and the system should be robust against that anyhow. I imagine I would have it poll after a handful of seconds, and the response would contain the current matched players; you'd keep getting the current player list until all were ready to go, and only then would you get the host info when it was immediately ready to go. REST/polling is probably pretty chatty though, I agree.

Share this post


Link to post
Share on other sites

As for REST, I would think it would be sufficient to set the response to not be cached, no?


Yes, that would "work," with the draw-back I suggested.
In general, it turns out that REST is a good match to services where data is at least in some sense cacheable.
When caching is not useful and real-time is part of the equation, REST is often less good of a match.
Thus, thinking about caching is a good proxy for thinking about whether REST design makes sense for whatever you're building.
(There are other design paradigms: messaging, RPC, etc -- good design means using the right paradigm for the right problem.)

Share this post


Link to post
Share on other sites

hplus0603 - would you mind if I sent you a short private message? I believe I have worked out how I wish to do my authentication and logins etc and would like an expert opinion incase I missed something - but as silly as it sounds i'd rather there wasnt a thread bullet pointing exactly how my security works incase I go live and it's later found and gives someone with malicious intent a little edge :P

Share this post


Link to post
Share on other sites

i'd rather there wasnt a thread bullet pointing exactly how my security works


I'm happy to review anything that is posted publicly in the forums. For questions where the forums do not get the benefit of the answer, I may be available for a paid consulting gig.

In general, your best bet is to go public with your questions. Your client is publicly available to anyone who plays your game, so analysis for a determined attacker is not hard.
And, for anyone to actually attack your game, the game has to be successful enough that a determined attacker thinks attacking your game is more interesting than attacking WoW / Clash of Clans / Battlefield / whatever.

If your security is good, then making it public is fine. If your security is bad, not making it public just means you have less chance of finding the badness.

Share this post


Link to post
Share on other sites

Okay, well fair enough. It's just a "take every edge you can get" mentality in a world where malicious attempts on anything internet are inevitable :)

 

But for the benefit of the forums then, these are the steps i'm intending to take to authenticate and join a lobby. I really appreciate your feedback on it as although I have nearly two decades of programming behind me I do not have much experience with networking so this is a bit of a new avenue for me!

 

This is assuming a user account has already been created (probably through a web page) and there is an SQL db with the login name and a password hashed with a "server secret" to avoid ever storing plain text passwords.

 

client connects to login server
login server sends random challenge number to client
client computes hash of challenge combined with a user supplied password and also sends a login name
login server looks up client by login name, de-hashes stored password using "server secret" and rehashes the sent challenge + stored (now unhashed) password and compares to hash client sent.
if password okay, login server generates an authentication ID, stores it on the sql server and sends client a ticket with their auth id, their user id and IP of server to connect to (could do load balancing here by smartly choosing different server ips?)
client disconnects from login server and connects to new ip given for lobby server
lobby server asks for user id and authentication token
client sends requested information
lobby looks up user id, read authentication token stored by login server and confirms that users auth token matches and has not expired, sends an "all okay" to client.
Client may now perform lobby functions like send chat, receive chat, list games, etc.
Periodically lobby server should request auth token from client to ensure no "man in the middle" injection and everything is as should be - correct supply of token extends expirary on that token.
Any token that expires should auto boot the user attempting to use it out.
 
My main concern is whether just accepting commands from the client after an auth token has been confirmed as valid and then occasionally checking that whatever is talking still has the valid auth token is sufficient runtime security - the alternative seems to be prefixing every packet with the same auth token but it just seems like alot of extra data to be sending all the time?

Share this post


Link to post
Share on other sites

client connects to login server
login server sends random challenge number to client
client computes hash of challenge combined with a user supplied password and also sends a login name
login server looks up client by login name, de-hashes stored password using "server secret" and rehashes the sent challenge + stored (now unhashed) password and compares to hash client sent.


This will work, although it requires that the server be able to decrypt the passwords.
That may be okay for a game, but is generally not a good idea, in case your server database gets somehow broken.
Making it hard for an attacker to get the actual password, such as using a specially hardened en/de-crypt server that's not visible to the external network, may help.
These days, I'd probably instead prefer to use TLS or HTTPS to provide plaintext name and password to the server, and the server hashes that plaintext password using bcrypt to compare to stored-in-database hashed-password. (This is safe as long as TLS / HTTPS is safe.)
An attacker can then only get the passwords that are in flight during the time of attack, rather than all the passwords.

if password okay, login server generates an authentication ID, stores it on the sql server and sends client a ticket with their auth id, their user id and IP of server to connect to (could do load balancing here by smartly choosing different server ips?)


I would probably send a ticket that consists of:
time:user-id:hmac(time+user-id,shared-server-secret)
This lets the lobby server verify the ticket (time+userid) without connecting back to the server, assuming lobby server and main server have the same clock and secret.

client disconnects from login server and connects to new ip given for lobby server
lobby server asks for user id and authentication token
client sends requested information


You can just have the client provide the information in its connection -- no need to "ask" for it. That's an efficiency thing, not a security thing.

Periodically lobby server should request auth token from client


Player could just provide the ticket every 30 seconds or whatever without any "request." You'd simply have a timer for how long ago a valid ticket was provided to the server, and disconnect any client that hasn't provided a valid ticket in X amount of time. Again, simplicity, but not a security thing.

My main concern is whether just accepting commands from the client after an auth token has been confirmed as valid and then occasionally checking that whatever is talking still has the valid auth token is sufficient runtime security


What attacks are you trying to guard against?

Most script kiddies on the internet (including game hackers) do not have the ability to receive data sent to a specific IP address. They can spoof the source IP address of some packet that's sent, but they won't see the return of that. Thus, once established, the periodic ticket sending is not particularly necessary.

Another option: You can provide an encryption key to the client when it first connects. The client can then encrypt each packet with that key. (Make sure to prefix each packet with a sufficiently long sufficiently random nonce!) The server can then tell that the client was the one that originally connected (or could originally receive the connect message) because the packet decrypts correctly.

Another option: You can use TLS. (Which means you can't do UDP NAT punch-through.)

Share this post


Link to post
Share on other sites

hmm, the reason I went with that method (vs ssl etc) was after reading your chapter on networking and seeing Challenge Hash Authentication sold as a "major benefit" and indeed with no passwords being sent to sniff etc the ONLY downside I could see was the server storing plain text.  I was not okay with the idea of plain text so my idea was that all passwords would be hashed server side by a secret key inside the server software itself so if someone DID get access to the db they would have hashed passwords and would need to then steal the actual software off my server and then reverse engineer it until they found the key.. or is there something much simpler they could do? I figured a large enough "secret" would prevent brute forcing, at least on any level anyone would bother here.  Would you say this is not sufficient and you'd still go for TSL/HTTPS?

 

I really like your optimisation suggestions, obvious when read but probably wouldnt of got them any time soon by myself!

 

At the end of the day this is a multiplayer lobby. It does NOT handle any game logic at all - if a hacker got in the worst thing they could do is steal a users account, change their password and maybe delete their friends list or intentionally behave bad on lobby chat to try and get a user banned and invalidate their acheivements etc.  I'm not sure how far I should take security - those things are certainly bad but not quite on the scale of "now I have your credit card information"!

 

edit: as I intend to run this from the azure cloud I believe I can trust microsoft with my data, even if I cancel my service later on :) there is also a default amount of redundancy using the cloud. but if I go the VM IaaS route as I intend then I guess the ultimate security of my server is down to my own configuration!

Edited by PanicRave

Share this post


Link to post
Share on other sites

Would you say this is not sufficient and you'd still go for TSL/HTTPS?


With TLS/HTTPS, the hacker can get the password of one user by exploiting faults in the protocols (which have been more common than previously thought.)

With challenge signature, the hacker can't get the password that way, but can get the password of many players if they break your server (which also seems to happen more than previously thought.)

Previously, I used to think that a competent operations team could keep an encrypted password database from falling in the wrong hands, but these days, I'm just not sure --- both problems have happened with alarming frequency the last few years.

Share this post


Link to post
Share on other sites

sorry to drag this thread up again but working on same project so didnt want to clutter board with more posts even though slightly different question now!

 

I have never used a database for such high volume data before, the biggest use i've ever put a db too is a forum. So atm i've been weighing up what data to store in ram and what data to store in DB, especially if I end up spreading the load over a few servers.  I guess im "choosing my bottleneck", wether ram or db, and im really uncertain to what extent I can push a db!

 

tl;dr - should I store games players are hosting (and unhosting) in the database? or just user data (llogin/pw/email/stats/etc)? anything I should be aware of?

 

Thanks :)

Share this post


Link to post
Share on other sites

I have never used a database for such high volume data before,


If I were to build it, I would store data that is going to be stale within an hour in RAM, and data that needs to be more persistent than that in a database.
I would also design my protocols to avoid changing persistent data frequently :-) Or, to put another way, any data that changes frequently, should be in RAM, and/or supplied on demand by the client.

Share this post


Link to post
Share on other sites

thats really helpful! I'm thinking then that a "hosted game" could go in a database because it could last a rather long time depending on the game.  However players may come and go from games quite frequently so perhaps each server should have in ram a list of online users (I have that atm) and what game they are in with the info for that game being in the database?  Its tempting to put the users that are in the game in the db though because I could store it as a hostmask, userid@server so any lobby service looking at the users list could instantly see a) what users are in a game and b) what servers those users belong to so they could easilly send chat the right way without having to traverse a peer to peer tree (eg IRC).  But that may be just too much hit on the DB when the userbase gets large.

 

So instead perhaps the db should store the game and who hosted it in the db, lobby servers can read that and know which server to inform when one of their clients requests to "join" and in response the server with the user who hosted can pass on a list of other users already joined and their host masks, that way user discover is one direct message and no server tree required!

 

So finally I guess - data that goes stale in an hour.. just to be clear do you mean data that wouldnt change or data that would cease to be useful?  for example, a User name is rarely going to change.  I could make my "online users list" just an array of database id's for looking up that stuff.  However although the username wont change it will be frequently used / useful for lobby chatter lists, announcing joins and disconnects and all sorts of other stuff... so is that a candidate for ram or db lookups?

 

I guess I need to know if a db read is an expensive as a db write!

Share this post


Link to post
Share on other sites
That would probably work just fine for may cases, especially when player joining/leaving is not frequent, and games have long life times -- chess, or whatever.

When I wrote a version of this, I put both "currently available games" and "players seeking games" in RAM only. This was more for a FPS-like experience, where games may be shorter, and player are at least semi-often looking for new matches.

A server that is currently accepting users would send an update with current game state (name/mode/current-players/open-slots/whatever) every 5 seconds or so. When the lobby server hasn't heard from a game hosting server for 12 seconds, it would drop that game from its list of available-to-match games.

Meanwhile, a player looking for games would send match parameters, and be sent back a list of games, typically once every 5 seconds as well. If you expect for there to be 100s of matched games in the response, you'll want to manage this with some kind of consistent sorting and pagination.

The only persistent data I'd store in a DB for a game matchmaker would be the user name and password hashes, to verify the user accounts (and perhaps something like a game purchase serial number or whatever.)

Share this post


Link to post
Share on other sites

This topic is 1069 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this