Keeping the ne'er do wells out...
Online games... The unsavoury types are always drawn to them. As a game admin, you simply kick them out of your game, or ban them if you're in such a mood and that's the end of it. But now looking at it from the developer side of things, I can't help thinking a bit more about it.
It's one of UDP's advantages over TCP. When you get a known trouble maker trying to join your game, your server can either tell them to sod off (in the nicest way possible), or it could pretend that it never even got the request. Easy.
What about when you have TCP, or both? TCP can't just "ignore" a connection request* - it's just not allowed. All you can do is either call accept, which will (normally) block until a connection request actually arrives -- or not, in which case, no one can connect, not even the good guys... It's something most people here won't need to think too hard about, but perhaps a bit if input for those who it will affect (namely: me)
Most games using a TCP connection system, will continually call the accept function, since it wouldn't be much of a multiplayer game if only the host could play. When a known trouble maker comes along, the server simply closes its side of the connection and refuses to send anymore data. The trouble I learned recently is that you can't actually force the remote peer to close their end of the connection - and you can't delete your socket handle until they do shut the connection, in case they are still sending data to you...
Now I know that winsock isn't really built for games. For starter's Nagle's Algorithm starts enabled, and it's highly recommended in the MSDN that you leave it enabled. Yes, it's easy to disable (setsockopt with TCP_NODELAY set to false), but the fact you have to manually disable it at all, says it's not what winsock is really targetted towards.
So, already I've realised that once an undesirable gets in, I could in theory have them wasting a valid socket resource (if they're not using an official client), by refusing to shut the connection and waiting for the timeout to occur. By recently I found a way round this... Winsock allows something called "conditional accept" which is a callback called by the accept function, where you can look at the sender's IP and port (although the port isn't really helpful at this stage) and decide whether to open the connection, or to refuse it - Thereby causing the socket to get error 10061, as if the server application wasn't running.
A little more reading though, and I discover that this conditional accept thing is on the list of "Lamest things supported on win32". Without conditional accept, as soon as a connection request arrives, it's accepted automatically in kernel space, so it's about as fast as it can be, whereas the conditional accept callback is done in user space, and switching between them many times a second takes time. The argument is, that it would be so slow that genuine users can be getting 10060 timed out errors due to the accept not being handled fast enough.
Anyone here know anything about kernel stuff? I know nothing about it, but when I asked my brother, his response was "anyone who thinks that switching between kernel space and user space is slow, probably thinks a kernel has something to do with fried chicken". He also suggested that even with several hundred users, a well optimised system would see no slow down in accepting new users via this "slow" callback, and that it would probably only fall over during a SYN-flood (but not using the callback is just as vulnerable).
Personally, I can't see why other TCP games haven't used conditional accepting. It's been around for years, so professional companies must think there's something wrong with it. But what? It seems like such an obvious solution. Why do we need to say: "no, you're not allowed in... Go away please" when we could simply pretend there's no one home (Same as they can do on UDP)?
*Actually TCP can ignore connection requests. During the conditional accept callback simply don't return a known value (CF_ACCEPT or CF_REJECT) and your socket will get error 10061 (rebind the socket and then you can carry on using it) but their socket will get 10060, as if the server wasn't even switched on... However, it's a cheap hack and probably not a good idea to use it, since this is undocumented behaviour.
- 1
4 Comments
Recommended Comments