The server code is still not published for all to see. I've thought about doing it a number of times, but there are a few sticking points I've wanted to deal with before doing so. A few select people do have copies of the source though.An alternative would be that you or someone who has the source makes the necessary changes to it.
I suppose a few people did occasionally send me logs, but I'm afraid the logs I saw didn't indicate to me a clear problem, or at the very least a clear cause. Granted, the log files tend to be somewhat hard to read, even for me.In some cases the log files just don't contain the information that is required to track down a problem. That is also due to most packets being generated and processed by op2 and not the netfix code. If something goes wrong that is usually when one player stops receiving packets from another player. And netfix has no code to detect this.
As for your changes to prevent multiple joins, what about check if a joining player already has an address match in the player list? (Both IP and port, since people behind the same router can have the same IP but will have different ports). That would eliminate the need to add an extra GUID field to the packet.It can occur (and its in one of the logs I sent to you) that the external port changes while joining a game. You can't even assume that the ip stays the same, since most isps change that after 24 hours. Imo netfix should be able to recover from an ip change at any time.
I'm also wondering where you put the source net ID check. I've long considered a similar sounding check, but possibly in a different place in the code.Its in the AddPlayer function which I extended to take the GUID as a new parameter. But I'll possibly move it out of that function to a place a few lines before AddPlayer is called.
Also, could you elaborate on how JoinHelpRequest appears to be incomplete?Here is one that I once received:
Source: 0
Dest : 0
Size : 24
type : 1
checksum: d224111f
commandType: 10
payloadData: a 0 0 0 8d 81 f3 2 33 f6 b4 4b 9a 22 c9 5 cc 2a d0 7f 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Packet from player 0 ((AF:2) 18.f6.12.48:de8c) received on unexpected port (de8c instead of 7919) [PlayerNetId: 18]
Source: 18
Dest : c0a288
Size : 4
type : 6d
checksum: bd64587
commandType: 246611992
payloadData: 18 0 b3 e
Packet from player 4 ((AF:2) 63.8c.4c.40:68e) received on unexpected port (68e instead of de8c) [PlayerNetId: 24]
Source: 24
Dest : c0a288
Size : 4
type : f8
checksum: c95d093
commandType: 259129368
payloadData: 18 0 72 f
QuoteI suppose a few people did occasionally send me logs, but I'm afraid the logs I saw didn't indicate to me a clear problem, or at the very least a clear cause. Granted, the log files tend to be somewhat hard to read, even for me.In some cases the log files just don't contain the information that is required to track down a problem. That is also due to most packets being generated and processed by op2 and not the netfix code. If something goes wrong that is usually when one player stops receiving packets from another player. And netfix has no code to detect this.
It's quite expected that a port change will be required on game join with certain routers. A port change during play might also happen due to a router reboot.QuoteIt can occur (and its in one of the logs I sent to you) that the external port changes while joining a game. You can't even assume that the ip stays the same, since most isps change that after 24 hours. Imo netfix should be able to recover from an ip change at any time.
As for your changes to prevent multiple joins, what about check if a joining player already has an address match in the player list? (Both IP and port, since people behind the same router can have the same IP but will have different ports). That would eliminate the need to add an extra GUID field to the packet.
Another potentially useful tool that would burden users less, would be to have each client send info to the server on game join or game start that can be logged. The server already has the potential to record IP addresses and ports. It can't likely see port changes though without being told. It also probably doesn't know the player net IDs. Those extra values would certain help debugging efforts. Also, by collecting the port information in one place, the game server might be in a better position to determine who has problem routers, and what restrictions they have.Two different points here:
An IP address change during play is very unlikely. When an IP address lease is close to expiring, the device holding it will issue a renew request. It will be re-assigned the same IP address with a new lease time. If it didn't get the old IP address, then you'd expect all your connections to get reset periodically, which doesn't happen in practice, and would likely break a lot of software if it did.Maybe I am living in a different world. All my connections get reset periodically (unless I switch off my computer during the reset time which I usually do). And, yea, currently I avoid playing games near the reset time.
Also, in the context of the current problem, this is strictly about game join. If by some miracle someone's IP address changed right as they were joining..., they would have to click "Join" again? Maybe a wait a few seconds for their previous join attempt to time out and get dropped? I don't believe any of the timeouts are longer than 15 seconds, if even that.Is there a timeout for people who did already complete the join process? I.e. if their port/ip changes after they joined a game, but before its started?
The port tracking code does not allow for IP address modifications, only port modifications. That means that currently an IP change during gameplay will disconnect someone permanently. You could update the port tracking code, unrelated to the game join packet, to also track IP address changes, but I would recommend against this. It's of questionable value, and would be a security concern. If the IP could be auto updated that easily during game play, then someone could hijack someone else's session. I think this is of greater concern than the very unlikely possibility of someone's IP address changing during gameplay, which would probably mean their computer got reset anyway.The last assumption is simply wrong. But I understand the security concerns. Still, imo ip changes should not end a game. Instead of just discarding packets from a previously unknown ip, people could be asked whether they want to accept the ip change. Maybe some sort of automatic authentication / reauthentication mechanism could be used (with auth info being newly generated for every game. I don't want to add a system where players would have to log into an account in order to play).
The packets you posted look corrupt. Where are you logging this? Do the source IP addresses correspond to other players? The "type" value should only ever be 0 or 1, and the "commandType" value should be a reasonably small integer.I logged them as a host of a 3 player game. I suspect that I also got them as the host of a 5 player game. Logs from other players show that they didn't get those packets. So, they're probably only sent to the host. Furthermore, I never saw such packets in a 2 player game.
Edit: Also, it's very stange that the address field of the JoinHelperPacket is zeroed out. This is set by the game server to match the client requesting the join. If it came through the game server, there should be no way this field is zero.NetFix doesn't generate JoinHelpRequests. Outpost2 doesn't generate JoinHelpRequests. Whats left?
Is it possible you compiled the code with different struct packing alignments? The proper pragmas should exist in the code to keep it uniform. I assume you didn't do anything to change those?The assumption is correct. I didn't modify the forced exports code at all (except a few includes, maybe). And if alignment was really wrong, other packets would be broken, too.
Is there a timeout for people who did already complete the join process? I.e. if their port/ip changes after they joined a game, but before its started?I believe so, but I don't quite remember anymore. I think a player who stops responding will get dropped. I vaguely remember this happening while debugging when one client was stopped at a breakpoint.
I wouldn't suggest sending everything. I'd prefer to keep the protocol as light as possible in terms of bandwidth requirements. If the information isn't strictly needed to support network operation, then I'd like to keep it out of the protocol. I'd also like to not waste disk space by actually recording available information.Are you referring to my game server logging concerns?
My comment was more a thought that proper logs might help development, as would a slight increase in information, mostly concerning external port mappings, and possibly player network IDs. The later is not strictly needed to implement any useful features, but might be interesting to debug current apparent problems. I don't believe the player net ID is of a particularly sensitive nature. It essentially consists of the generation time (time since Windows was last booted), and the player's index in the player table. Neither is a permanent identifier for a player, and should change for each game played. Essentially I'm suggesting collecting a global view of the connection state to better understand the connection problems (and possibly the mapping of temporary player IDs to connections). What makes current development so difficult is only being able to see the connections from one point of view (which will different from other points of view for the problem cases that need debugging).The net id is not critical information in my eyes. IP address (and maybe port) are, though.
To auto-detect certain router issues, you'd need to be aware of certain external port changes. These results would need to be compared from two different external sources. The game server is one possible external source, but another one would be needed for auto-detection. I had previously thought two game servers working together might work for an enhanced mode that can warn of router problems. This would allow those properties to be determined on connect, even before a game is even hosted. However, I would prefer not having to run two game servers on two seperate boxes if possible, and I definately don't want to think about keeping game lists synched between two of them, or modifying one to be a custom non-full game server. Another alternative is somehow using the port information from connecting peers. The current problem is that a peer only knows how it sees other peers. There is no global view of the port mappings, nor is any given peer aware of it's external port mappings to other players. It's also worth noting that such a scheme would only work once players start connecting to each other, after a game has been hosted.The global view on all port mappings that you're mentioning is what is needed, in my eyes. It would allow players to detect issues without the help of the game server.
I think the solution I might like the best, is if each peer informed each other what it sees of that person. There would be no global view in this case, but each peer should learn enough about itself to determine if it's behind a problem router. It would require more packets to be exchanged than if the information was collected in a central place, although, the packets would be slightly smaller. It also negates any privacy concerns since a client would only be learning about itself using information already available to other clients.Thats also a good suggestion.
This doesn't create for an easy debugging/development environment though, and if something goes wrong it will require each player to submit whatever logs are generated on their computer to diagnose the problem.Thats why a global view would be better.
If there is a timeout, it effects only the pre game setup window. And that doesn't help us, since we want a timed out player to vanish from the peerInfo array.QuoteIs there a timeout for people who did already complete the join process? I.e. if their port/ip changes after they joined a game, but before its started?I believe so, but I don't quite remember anymore. I think a player who stops responding will get dropped. I vaguely remember this happening while debugging when one client was stopped at a breakpoint.
I would also like to avoid pestering the user with dialog boxes concerning IP changes (and mostly avoid having to write such code).The boxes wouldn't appear too often, so you can't talk about pestering. For the case that someone attempts to hack into a game, there could be an option to ignore subsequent ip changes. If you don't want to code that thing, I'd be willing to do that. But maybe we find an alternative, anyways.
I also don't want to add account login requirements. If anything, maybe share a randomly generated pairwise unique value between peers for this purpose, and do the switchover automatically if the secret is known. You'd want the number to be random to prevent abuse by anyone on the internet. You'd want the pairwise uniqueness property to prevent other players from that game from abusing otherwise shared information.Diffie-Hellman key exchange could do that. But in my eyes a public-/private key system would be better suited. RSA with ridiculously small key lengths will probably be good enough. It could then work as follows:
I'm still perplexed by the packets you say you've recorded. If you find anything else out about them I'd like to know. It looks like a possible bug to me. I don't think they are actually valid packets.Will do.
So, in short, the game server can potentially track which games you've joined, if it so desired. Not strictly needed in all cases, but I did hear about problems less frequently after this was implemented. I don't believe there is a foolproof way of only sending this help request when strictly needed, so instead I've chosen to minimize delay when it is needed.I do agree that the help request should always be sent. Doesn't mean it has to be logged.
Are you referring to my game server logging concerns?Basically yes.
The net id is not critical information in my eyes. IP address (and maybe port) are, though.You're quite right. But you've also posted results that suggest there is a problem with the player net IDs. Hence, debug information concerning them would be of immediate use to solving this particular problem. There is no long term use to keep track of that though, and I would prefer not needing to pass it around once the problem is solved, or ever if the bug is tracked down first. The IP and port information would be of lasting value to the protocol though for router property detection.
The global view on all port mappings that you're mentioning is what is needed, in my eyes. It would allow players to detect issues without the help of the game server.I like how you ended that "without the help of the game server". That is a particularly relevant comment, since the NetFix is designed to be usable without a functioning game server. Just enter the IP of the host you want to join, like the usual TCP/IP game setup. In that case, using peers to detect router properties, without needing a game server would be of value.
If there is a timeout, it effects only the pre game setup window. And that doesn't help us, since we want a timed out player to vanish from the peerInfo array.I'm not too sure what you're getting at here. I believe they are dropped from the peerInfo array if they timeout during game setup. After game start, it's handled by the drop player dialog.
Do you think router problems should be announced to:#2 would definitely be nice, since it takes away the need to explain to the "problem player" how to get the info. #3 would be nicer, but not needed, since most of the time people are hosting who know how stuff works.
1) only the person with the problem router
2) the person with the problem router and the game host
3) all people who were trying to start the game
Currently I'm leaning towards a solution that would make only #1 possible. A slight modification should make either #1 or #2 possible. Does anyone else have any thoughts on this? Is this a privacy concern for people?
// Set the source player net ID
packet->header.sourcePlayerNetID = playerNetID;