From 59b7438376c83763cc856f1aa000b3be095eea83 Mon Sep 17 00:00:00 2001 From: lotodore Date: Wed, 15 Aug 2007 13:28:28 +0000 Subject: [PATCH] Work on dedicated server. This svn revision is totally broken, it is part of a complete redesign of the server. There is a lobby thread for the server, and each game has its own game processing thread and a sender thread. Connections can be accepted from different sources, i.e. TCP/SCTP over IPv4, IPv6, all those work well in parallel. --- docs/net_protocol.txt | 234 ++++++-- src/gamedata.h | 8 +- src/net/common/clientstate.cpp | 23 +- src/net/common/netpacket.cpp | 810 ++++++++++++++++++++++++---- src/net/common/serverrecvthread.cpp | 663 ++++++----------------- src/net/common/sessionmanager.cpp | 237 ++++++++ src/net/netpacket.h | 185 ++++++- src/net/serverrecvstate.h | 2 +- src/net/serverrecvthread.h | 109 +--- src/net/sessiondata.h | 1 - src/net/sessionmanager.h | 73 +++ src/net/socket_msg.h | 13 +- 12 files changed, 1561 insertions(+), 797 deletions(-) create mode 100644 src/net/common/sessionmanager.cpp create mode 100644 src/net/sessionmanager.h diff --git a/docs/net_protocol.txt b/docs/net_protocol.txt index ebdd867c..b4fe26c0 100644 --- a/docs/net_protocol.txt +++ b/docs/net_protocol.txt @@ -1,4 +1,6 @@ Changelog: +08-14-2007: Supporting multiple games per server. + Player id is now 32 bit to avoid collisions. 08-02-2007: Added new requests for game start and kick player. Type ids changed. 07-24-2007: Join Game ACK / Player Joined do not specify player number. @@ -21,7 +23,7 @@ PokerTH general message format: Minimum length is 8. Maximum length is 256. -Client Request: Join Game +Client Request: Init 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -37,9 +39,9 @@ Client Request: Join Game +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Additional values for major version = 2: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Password Length | Name Length | + | Password Length | Player Name Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - || Reserved | + | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | \ Password (UTF-8) / @@ -47,24 +49,143 @@ Additional values for major version = 2: / | padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | \ - \ Name (UTF-8) / + \ Player Name (UTF-8) / | +-------------------------------+ / | padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -[Future versions will include an id of the game, to support -multiple games per server.] -Server Reply: Join Game ACK +Server Reply: Init ACK 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 2 | Message Length = 28 | + | Message Type = 2 | Message Length = 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Your Session ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Your Player ID | Your Player Flags | + | Your Player ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +Player ID: + Unique Player ID +Session ID: + Unique Session ID which is not known by other players + + +Server Notification: Game List New + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Message Type = 3 | Message Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Game ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Game Mode | Game Name Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | \ + \ Game Name (UTF-8) / + | +-------------------------------+ + / | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +Game List notifications will be automatically sent if the player +is in the lobby. If a game is joined/started, no more messages +will be sent. As soon as the player leaves a game without +disconnecting, Game List notifications will be sent again. + +Game Mode: + 1: Game Created + 2: Game Started + 3: Game Closed (only for Game List Update) + + +Server Notification: Game List Update + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Message Type = 4 | Message Length = 12 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Game ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Game Mode | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +Client Request: Create Game + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Message Type = 5 | Message Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Password Length | Game Name Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Max Number of Players | Small Blind | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Hands before raise | Proposed GUI Speed | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Player Action Timeout | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Start Money | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + \ Password (UTF-8) / + | +-------------------------------+ + / | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | \ + \ Game Name (UTF-8) / + | +-------------------------------+ + / | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +Proposed GUI Speed: + 1-11 +Player Action Timeout: + # seconds +Player Flags: + 0x01 set: Player is human + 0x02 set: Player is admin for this game + + +Server Reply: Create Game Ack + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Message Type = 6 | Message Length = 8 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Game ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +(also implies that the client successfully joined the game) + + +Client Request: Join Game + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Message Type = 7 | Message Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Game ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Password Length | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + \ Password (UTF-8) / + | +-------------------------------+ + / | padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +Server Reply: Join Game Ack + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Message Type = 8 | Message Length = 20 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Max Number of Players | Small Blind | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -75,30 +196,19 @@ Server Reply: Join Game ACK | Start Money | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -Player ID: - Unique Player ID -Proposed GUI Speed: - 1-11 -Player Action Timeout: - # seconds -Player Flags: - 0x01 set: Player is human - 0x02 set: Player is admin for this game - - Server Notification: Player Joined 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 3 | Message Length | + | Message Type = 9 | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player ID | Player Flags | + | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Name Length | Reserved | + | Player Flags | Player Name Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | \ - \ Name (UTF-8) / + \ Player Name (UTF-8) / | +-------------------------------+ / | padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -109,9 +219,9 @@ Server Notification: Player Left 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 4 | Message Length = 8 | + | Message Type = 10 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player ID | Reserved | + | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -120,9 +230,9 @@ Client Request: Kick Player 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 5 | Message Length = 8 | + | Message Type = 11 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player ID | Reserved | + | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -131,7 +241,7 @@ Client Request: Start Event 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 6 | Message Length = 4 | + | Message Type = 12 | Message Length = 4 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -140,18 +250,20 @@ Server Notification: Game Start 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 7 | Message Length | + | Message Type = 13 | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Start Dealer Player Id | Number of Players | + | Start Dealer Player Id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player ID Slot #1 | Player ID Slot #2 | + | Number of Players | Reserved | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Player ID Slot #1 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Player ID Slot #2 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | \ \ Additional Player Slots / / | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player ID Slot #n | Padding | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The player slots are the positions of the players on the table. Each slot contains the ID for the corresponding player. The slots are ordered. @@ -169,7 +281,7 @@ Server Notification: Hand Start 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 8 | Message Length = 8 | + | Message Type = 14 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Your 1st Card | Your 2nd Card | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -183,9 +295,11 @@ Server Request/Notification: Player's Turn 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 9 | Message Length = 8 | + | Message Type = 15 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Game State | Player ID | + | Player ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Game State | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Game State: @@ -200,7 +314,7 @@ Client Reply/Request: Player's Action 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 10 | Message Length = 12 | + | Message Type = 16 | Message Length = 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Game State | Player Action | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -225,11 +339,11 @@ Server Notification: Player's Action Done 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 11 | Message Length = 20 | + | Message Type = 17 | Message Length = 20 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Game State | Player Id | + | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player Action | Reserved | + | Game State | Player Action | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Total Player Bet | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -246,7 +360,7 @@ Server Reply: Player's Action Rejected 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 12 | Message Length = 16 | + | Message Type = 18 | Message Length = 16 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Game State | Player Action | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -274,7 +388,7 @@ Server Notification: Deal Flop Cards 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 13 | Message Length = 12 | + | Message Type = 19 | Message Length = 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Flop 1st Card | Flop 2nd Card | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -287,7 +401,7 @@ Server Notification: Deal Turn Card 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 14 | Message Length = 8 | + | Message Type = 20 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Turn Card | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -298,7 +412,7 @@ Server Notification: Deal River Card 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 15 | Message Length = 8 | + | Message Type = 21 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | River Card | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -309,7 +423,7 @@ Server Notification: All In Show Cards 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 16 | Message Length | + | Message Type = 22 | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Number Of PlayerCards Records | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -320,9 +434,9 @@ Server Notification: All In Show Cards PlayerCards Record +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player Id | 1st Card | + | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | 2nd Card | Reserved | + | 1st Card | 2nd Card | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -331,7 +445,7 @@ Server Notification: End Of Hand Show Cards 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 17 | Message Length | + | Message Type = 23 | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Number Of PlayerResult Records | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -342,13 +456,15 @@ Server Notification: End Of Hand Show Cards PlayerResult Record +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player Id | 1st Card | + | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | 2nd Card | Best Hand Position 1 | + | 1st Card | 2nd Card | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Best Hand Position 2 | Best Hand Position 3 | + | Best Hand Position 1 | Best Hand Position 2 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Best Hand Position 4 | Best Hand Position 5 | + | Best Hand Position 3 | Best Hand Position 4 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Best Hand Position 5 | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Value Of Cards | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -363,9 +479,9 @@ Server Notification: End Of Hand Hide Cards 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 18 | Message Length = 16 | + | Message Type = 24 | Message Length = 16 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Player Id | Reserved | + | Player ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Money Won | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -378,9 +494,9 @@ Server Notification: End Of Game 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Message Type = 19 | Message Length = 8 | + | Message Type = 25 | Message Length = 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Winner Player Id | Reserved | + | Winner Player Id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -407,7 +523,9 @@ Server Notification: Chat Text +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Message Type = 513 | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Text Length | Player Id | + | Player ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Text Length | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | \ \ Text (UTF-8) / diff --git a/src/gamedata.h b/src/gamedata.h index 9f86beda..016ea112 100644 --- a/src/gamedata.h +++ b/src/gamedata.h @@ -21,8 +21,14 @@ #ifndef _GAMEDATA_H_ #define _GAMEDATA_H_ -// For the sake of simplicity, this is a struct. +enum GameMode +{ + GAME_MODE_CREATED = 1, + GAME_MODE_STARTED, + GAME_MODE_CLOSED +}; +// For the sake of simplicity, this is a struct. struct GameData { GameData() : maxNumberOfPlayers(0), startMoney(0), smallBlind(0), diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index a17dc5f7..d1d5834b 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -344,12 +344,12 @@ ClientStateStartSession::Process(ClientThread &client) { ClientContext &context = client.GetContext(); - NetPacketJoinGame::Data initData; + NetPacketInit::Data initData; initData.password = context.GetPassword(); initData.playerName = context.GetPlayerName(); - boost::shared_ptr packet(new NetPacketJoinGame); - ((NetPacketJoinGame *)packet.get())->SetData(initData); + boost::shared_ptr packet(new NetPacketInit); + ((NetPacketInit *)packet.get())->SetData(initData); client.GetSender().Send(context.GetSocket(), packet); @@ -435,19 +435,16 @@ ClientStateWaitSession::InternalProcess(ClientThread &client, boost::shared_ptr< int retVal = MSG_SOCK_INTERNAL_PENDING; ClientContext &context = client.GetContext(); - if (packet->ToNetPacketJoinGameAck()) + if (packet->ToNetPacketInitAck()) { - // Everything is fine - we joined the game. - // Initialize game configuration. - NetPacketJoinGameAck::Data joinGameAckData; - packet->ToNetPacketJoinGameAck()->GetData(joinGameAckData); - client.SetGameData(joinGameAckData.gameData); - client.SetGuiPlayerId(joinGameAckData.yourPlayerUniqueId); + // Everything is fine - we are in the lobby. + NetPacketInitAck::Data initAckData; + packet->ToNetPacketInitAck()->GetData(initAckData); + client.SetGuiPlayerId(initAckData.yourPlayerUniqueId); - // TODO: Type Human is fixed here. - // Player number is 0 on join. Will be set when the game starts. + // Player number is 0 on init. Will be set when the game starts. boost::shared_ptr playerData( - new PlayerData(joinGameAckData.yourPlayerUniqueId, 0, joinGameAckData.ptype, joinGameAckData.prights)); + new PlayerData(initAckData.yourPlayerUniqueId, 0, PLAYER_TYPE_HUMAN, PLAYER_RIGHTS_NORMAL)); playerData->SetName(context.GetPlayerName()); client.AddPlayerData(playerData); diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp index 9d5edf64..4e7e2c77 100644 --- a/src/net/common/netpacket.cpp +++ b/src/net/common/netpacket.cpp @@ -27,25 +27,31 @@ using namespace std; #define ADD_PADDING(x) ((((x) + 3) >> 2) << 2) -#define NET_TYPE_JOIN_GAME 0x0001 -#define NET_TYPE_JOIN_GAME_ACK 0x0002 -#define NET_TYPE_PLAYER_JOINED 0x0003 -#define NET_TYPE_PLAYER_LEFT 0x0004 -#define NET_TYPE_KICK_PLAYER 0x0005 -#define NET_TYPE_START_EVENT 0x0006 -#define NET_TYPE_GAME_START 0x0007 -#define NET_TYPE_HAND_START 0x0008 -#define NET_TYPE_PLAYERS_TURN 0x0009 -#define NET_TYPE_PLAYERS_ACTION 0x000A -#define NET_TYPE_PLAYERS_ACTION_DONE 0x000B -#define NET_TYPE_PLAYERS_ACTION_REJECTED 0x000C -#define NET_TYPE_DEAL_FLOP_CARDS 0x000D -#define NET_TYPE_DEAL_TURN_CARD 0x000E -#define NET_TYPE_DEAL_RIVER_CARD 0x000F -#define NET_TYPE_ALL_IN_SHOW_CARDS 0x0010 -#define NET_TYPE_END_OF_HAND_SHOW_CARDS 0x0011 -#define NET_TYPE_END_OF_HAND_HIDE_CARDS 0x0012 -#define NET_TYPE_END_OF_GAME 0x0013 +#define NET_TYPE_INIT 0x0001 +#define NET_TYPE_INIT_ACK 0x0002 +#define NET_TYPE_GAME_LIST_NEW 0x0003 +#define NET_TYPE_GAME_LIST_UPDATE 0x0004 +#define NET_TYPE_CREATE_GAME 0x0005 +#define NET_TYPE_CREATE_GAME_ACK 0x0006 +#define NET_TYPE_JOIN_GAME 0x0007 +#define NET_TYPE_JOIN_GAME_ACK 0x0008 +#define NET_TYPE_PLAYER_JOINED 0x0009 +#define NET_TYPE_PLAYER_LEFT 0x000A +#define NET_TYPE_KICK_PLAYER 0x000B +#define NET_TYPE_START_EVENT 0x000C +#define NET_TYPE_GAME_START 0x000D +#define NET_TYPE_HAND_START 0x000E +#define NET_TYPE_PLAYERS_TURN 0x000F +#define NET_TYPE_PLAYERS_ACTION 0x0010 +#define NET_TYPE_PLAYERS_ACTION_DONE 0x0011 +#define NET_TYPE_PLAYERS_ACTION_REJECTED 0x0012 +#define NET_TYPE_DEAL_FLOP_CARDS 0x0013 +#define NET_TYPE_DEAL_TURN_CARD 0x0014 +#define NET_TYPE_DEAL_RIVER_CARD 0x0015 +#define NET_TYPE_ALL_IN_SHOW_CARDS 0x0016 +#define NET_TYPE_END_OF_HAND_SHOW_CARDS 0x0017 +#define NET_TYPE_END_OF_HAND_HIDE_CARDS 0x0018 +#define NET_TYPE_END_OF_GAME 0x0019 #define NET_TYPE_SEND_CHAT_TEXT 0x0200 #define NET_TYPE_CHAT_TEXT 0x0201 @@ -80,7 +86,7 @@ struct GCC_PACKED NetPacketHeader u_int16_t length; }; -struct GCC_PACKED NetPacketJoinGameData +struct GCC_PACKED NetPacketInitData { NetPacketHeader head; u_int16_t requestedVersionMajor; @@ -90,12 +96,34 @@ struct GCC_PACKED NetPacketJoinGameData u_int32_t reserved; }; -struct GCC_PACKED NetPacketJoinGameAckData +struct GCC_PACKED NetPacketInitAckData { NetPacketHeader head; u_int32_t sessionId; - u_int16_t playerId; - u_int16_t playerFlags; + u_int32_t playerId; +}; + +struct GCC_PACKED NetPacketGameListNewData +{ + NetPacketHeader head; + u_int32_t gameId; + u_int16_t gameMode; + u_int16_t gameNameLength; +}; + +struct GCC_PACKED NetPacketGameListUpdateData +{ + NetPacketHeader head; + u_int32_t gameId; + u_int16_t gameMode; + u_int16_t reserved; +}; + +struct GCC_PACKED NetPacketCreateGameData +{ + NetPacketHeader head; + u_int16_t passwordLength; + u_int16_t gameNameLength; u_int16_t maxNumberOfPlayers; u_int16_t smallBlind; u_int16_t handsBeforeRaise; @@ -105,34 +133,50 @@ struct GCC_PACKED NetPacketJoinGameAckData u_int32_t startMoney; }; -struct GCC_PACKED NetPacketJoinGameErrorData +struct GCC_PACKED NetPacketCreateGameAckData { NetPacketHeader head; - u_int16_t errorReason; + u_int32_t gameId; +}; + +struct GCC_PACKED NetPacketJoinGameData +{ + NetPacketHeader head; + u_int32_t gameId; + u_int16_t passwordLength; u_int16_t reserved; }; +struct GCC_PACKED NetPacketJoinGameAckData +{ + NetPacketHeader head; + u_int16_t maxNumberOfPlayers; + u_int16_t smallBlind; + u_int16_t handsBeforeRaise; + u_int16_t proposedGuiSpeed; + u_int16_t playerActionTimeout; + u_int16_t reserved; + u_int32_t startMoney; +}; + struct GCC_PACKED NetPacketPlayerJoinedData { NetPacketHeader head; - u_int16_t playerId; + u_int32_t playerId; u_int16_t playerFlags; u_int16_t playerNameLength; - u_int16_t reserved; }; struct GCC_PACKED NetPacketPlayerLeftData { NetPacketHeader head; - u_int16_t playerId; - u_int16_t reserved; + u_int32_t playerId; }; struct GCC_PACKED NetPacketKickPlayerData { NetPacketHeader head; - u_int16_t playerId; - u_int16_t reserved; + u_int32_t playerId; }; struct GCC_PACKED NetPacketStartEventData @@ -143,13 +187,14 @@ struct GCC_PACKED NetPacketStartEventData struct GCC_PACKED NetPacketGameStartData { NetPacketHeader head; - u_int16_t startDealerPlayerId; + u_int32_t startDealerPlayerId; u_int16_t numberOfPlayers; + u_int16_t reserved; }; struct GCC_PACKED PlayerSlotData { - u_int16_t playerId; + u_int32_t playerId; }; struct GCC_PACKED NetPacketHandStartData @@ -162,8 +207,9 @@ struct GCC_PACKED NetPacketHandStartData struct GCC_PACKED NetPacketPlayersTurnData { NetPacketHeader head; + u_int32_t playerId; u_int16_t gameState; - u_int16_t playerId; + u_int16_t reserved; }; struct GCC_PACKED NetPacketPlayersActionData @@ -177,10 +223,9 @@ struct GCC_PACKED NetPacketPlayersActionData struct GCC_PACKED NetPacketPlayersActionDoneData { NetPacketHeader head; + u_int32_t playerId; u_int16_t gameState; - u_int16_t playerId; u_int16_t playerAction; - u_int16_t reserved; u_int32_t totalPlayerBet; u_int32_t playerMoney; }; @@ -227,10 +272,9 @@ struct GCC_PACKED NetPacketAllInShowCardsData struct GCC_PACKED PlayerCardsData { - u_int16_t playerId; + u_int32_t playerId; u_int16_t card1; u_int16_t card2; - u_int16_t reserved; }; struct GCC_PACKED NetPacketEndOfHandShowCardsData @@ -242,7 +286,7 @@ struct GCC_PACKED NetPacketEndOfHandShowCardsData struct GCC_PACKED PlayerResultData { - u_int16_t playerId; + u_int32_t playerId; u_int16_t card1; u_int16_t card2; u_int16_t bestHandPos1; @@ -250,6 +294,7 @@ struct GCC_PACKED PlayerResultData u_int16_t bestHandPos3; u_int16_t bestHandPos4; u_int16_t bestHandPos5; + u_int16_t reserved; u_int32_t valueOfCards; u_int32_t moneyWon; u_int32_t playerMoney; @@ -258,8 +303,7 @@ struct GCC_PACKED PlayerResultData struct GCC_PACKED NetPacketEndOfHandHideCardsData { NetPacketHeader head; - u_int16_t playerId; - u_int16_t reserved; + u_int32_t playerId; u_int32_t moneyWon; u_int32_t playerMoney; }; @@ -267,8 +311,7 @@ struct GCC_PACKED NetPacketEndOfHandHideCardsData struct GCC_PACKED NetPacketEndOfGameData { NetPacketHeader head; - u_int16_t winnerPlayerId; - u_int16_t reserved; + u_int32_t winnerPlayerId; }; struct GCC_PACKED NetPacketSendChatTextData @@ -281,9 +324,9 @@ struct GCC_PACKED NetPacketSendChatTextData struct GCC_PACKED NetPacketChatTextData { NetPacketHeader head; + u_int32_t playerId; u_int16_t textLength; - u_int16_t playerId; - char text[1]; + u_int16_t reserved; }; struct GCC_PACKED NetPacketErrorData @@ -326,6 +369,24 @@ NetPacket::Create(char *data, unsigned &dataSize) { switch(ntohs(tmpHeader->type)) { + case NET_TYPE_INIT: + tmpPacket = boost::shared_ptr(new NetPacketInit); + break; + case NET_TYPE_INIT_ACK: + tmpPacket = boost::shared_ptr(new NetPacketInitAck); + break; + case NET_TYPE_GAME_LIST_NEW: + tmpPacket = boost::shared_ptr(new NetPacketGameListNew); + break; + case NET_TYPE_GAME_LIST_UPDATE: + tmpPacket = boost::shared_ptr(new NetPacketGameListUpdate); + break; + case NET_TYPE_CREATE_GAME: + tmpPacket = boost::shared_ptr(new NetPacketCreateGame); + break; + case NET_TYPE_CREATE_GAME_ACK: + tmpPacket = boost::shared_ptr(new NetPacketCreateGameAck); + break; case NET_TYPE_JOIN_GAME: tmpPacket = boost::shared_ptr(new NetPacketJoinGame); break; @@ -476,6 +537,42 @@ NetPacket::GetLen() const return ntohs(GetRawData()->length); } +const NetPacketInit * +NetPacket::ToNetPacketInit() const +{ + return NULL; +} + +const NetPacketInitAck * +NetPacket::ToNetPacketInitAck() const +{ + return NULL; +} + +const NetPacketGameListNew * +NetPacket::ToNetPacketGameListNew() const +{ + return NULL; +} + +const NetPacketGameListUpdate * +NetPacket::ToNetPacketGameListUpdate() const +{ + return NULL; +} + +const NetPacketCreateGame * +NetPacket::ToNetPacketCreateGame() const +{ + return NULL; +} + +const NetPacketCreateGameAck * +NetPacket::ToNetPacketCreateGameAck() const +{ + return NULL; +} + const NetPacketJoinGame * NetPacket::ToNetPacketJoinGame() const { @@ -657,12 +754,523 @@ NetPacket::Check(const NetPacketHeader *data) const //----------------------------------------------------------------------------- +NetPacketInit::NetPacketInit() +: NetPacket(NET_TYPE_INIT, sizeof(NetPacketInitData), MAX_PACKET_SIZE) +{ + NetPacketInitData *tmpData = (NetPacketInitData *)GetRawData(); + tmpData->requestedVersionMajor = htons(NET_VERSION_MAJOR); + tmpData->requestedVersionMinor = htons(NET_VERSION_MINOR); +} + +NetPacketInit::~NetPacketInit() +{ +} + +boost::shared_ptr +NetPacketInit::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketInit); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketInit::SetData(const NetPacketInit::Data &inData) +{ + u_int16_t playerNameLen = (u_int16_t)inData.playerName.length(); + u_int16_t passwordLen = (u_int16_t)inData.password.length(); + + // Some basic checks, so we don't use up too much memory. + // The constructed packet will also be checked. + if (!playerNameLen || playerNameLen > MAX_NAME_SIZE) + throw NetException(ERR_NET_INVALID_PLAYER_NAME, 0); + if (passwordLen > MAX_PASSWORD_SIZE) + throw NetException(ERR_NET_INVALID_PASSWORD_STR, 0); + + // Resize the packet so that the data fits in. + Resize((u_int16_t) + (sizeof(NetPacketInitData) + ADD_PADDING(playerNameLen) + ADD_PADDING(passwordLen))); + + NetPacketInitData *tmpData = (NetPacketInitData *)GetRawData(); + + // Set the data. + tmpData->passwordLength = htons(passwordLen); + tmpData->playerNameLength = htons(playerNameLen); + char *passwordPtr = (char *)tmpData + sizeof(NetPacketInitData); + memcpy(passwordPtr, inData.password.c_str(), passwordLen); + memcpy(passwordPtr + ADD_PADDING(passwordLen), inData.playerName.c_str(), playerNameLen); + + // Check the packet - just in case. + Check(GetRawData()); +} + +void +NetPacketInit::GetData(NetPacketInit::Data &outData) const +{ + // We assume that the data is valid. Validity has already been checked. + NetPacketInitData *tmpData = (NetPacketInitData *)GetRawData(); + + outData.versionMajor = ntohs(tmpData->requestedVersionMajor); + outData.versionMinor = ntohs(tmpData->requestedVersionMinor); + + u_int16_t passwordLen = ntohs(tmpData->passwordLength); + char *passwordPtr = (char *)tmpData + sizeof(NetPacketInitData); + outData.password = string(passwordPtr, passwordLen); + outData.playerName = string(passwordPtr + ADD_PADDING(passwordLen), ntohs(tmpData->playerNameLength)); +} + +const NetPacketInit * +NetPacketInit::ToNetPacketInit() const +{ + return this; +} + +void +NetPacketInit::InternalCheck(const NetPacketHeader* data) const +{ + u_int16_t dataLen = ntohs(data->length); + NetPacketInitData *tmpData = (NetPacketInitData *)data; + int passwordLength = ntohs(tmpData->passwordLength); + int playerNameLength = ntohs(tmpData->playerNameLength); + // Generous checking of dynamic packet size - + // larger packets are allowed. + // This is because the version number is in this packet, + // and later versions might provide larger packets. + if (dataLen < + sizeof(NetPacketInitData) + + ADD_PADDING(passwordLength) + + ADD_PADDING(playerNameLength)) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } + // Check string sizes. + if (passwordLength > MAX_PASSWORD_SIZE + || !playerNameLength + || playerNameLength > MAX_NAME_SIZE) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } + // Check name string. + char *namePtr = (char *)tmpData + sizeof(NetPacketInitData) + ADD_PADDING(passwordLength); + if (namePtr[0] == 0) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } +} + +//----------------------------------------------------------------------------- + +NetPacketInitAck::NetPacketInitAck() +: NetPacket(NET_TYPE_INIT_ACK, sizeof(NetPacketInitAckData), sizeof(NetPacketInitAckData)) +{ +} + +NetPacketInitAck::~NetPacketInitAck() +{ +} + +boost::shared_ptr +NetPacketInitAck::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketInitAck); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketInitAck::SetData(const NetPacketInitAck::Data &inData) +{ + NetPacketInitAckData *tmpData = (NetPacketInitAckData *)GetRawData(); + + tmpData->sessionId = htonl(inData.sessionId); + tmpData->playerId = htonl(inData.playerId); + + // Check the packet - just in case. + Check(GetRawData()); +} + +void +NetPacketInitAck::GetData(NetPacketInitAck::Data &outData) const +{ + NetPacketInitAckData *tmpData = (NetPacketInitAckData *)GetRawData(); + + outData.sessionId = ntohl(tmpData->sessionId); + outData.playerId = ntohl(tmpData->playerId); +} + +const NetPacketInitAck * +NetPacketInitAck::ToNetPacketInitAck() const +{ + return this; +} + +void +NetPacketInitAck::InternalCheck(const NetPacketHeader* data) const +{ + // Nothing to do. +} + +//----------------------------------------------------------------------------- + +NetPacketGameListNew::NetPacketGameListNew() +: NetPacket(NET_TYPE_GAME_LIST_NEW, sizeof(NetPacketGameListNewData), MAX_PACKET_SIZE) +{ +} + +NetPacketGameListNew::~NetPacketGameListNew() +{ +} + +boost::shared_ptr +NetPacketGameListNew::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketGameListNew); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketGameListNew::SetData(const NetPacketGameListNew::Data &inData) +{ + u_int16_t gameNameLen = (u_int16_t)inData.gameName.length(); + + // Some basic checks, so we don't use up too much memory. + // The constructed packet will also be checked. + if (!gameNameLen || gameNameLen > MAX_NAME_SIZE) + throw NetException(ERR_NET_INVALID_GAME_NAME, 0); + + // Resize the packet so that the data fits in. + Resize((u_int16_t) + (sizeof(NetPacketGameListNewData) + ADD_PADDING(gameNameLen))); + + NetPacketGameListNewData *tmpData = (NetPacketGameListNewData *)GetRawData(); + + // Set the data. + tmpData->gameId = htonl(inData.gameId); + tmpData->gameMode = htons(inData.gameMode); + tmpData->gameNameLength = htons(gameNameLen); + char *gameNamePtr = (char *)tmpData + sizeof(NetPacketGameListNewData); + memcpy(gameNamePtr, inData.gameName.c_str(), gameNameLen); + + // Check the packet - just in case. + Check(GetRawData()); +} + +void +NetPacketGameListNew::GetData(NetPacketGameListNew::Data &outData) const +{ + // We assume that the data is valid. Validity has already been checked. + NetPacketGameListNewData *tmpData = (NetPacketGameListNewData *)GetRawData(); + + outData.gameId = ntohl(tmpData->gameId); + outData.gameMode = static_cast(ntohs(tmpData->gameMode)); + u_int16_t gameNameLen = ntohs(tmpData->gameNameLength); + char *gameNamePtr = (char *)tmpData + sizeof(NetPacketGameListNewData); + outData.gameName = string(gameNamePtr, gameNameLen); +} + +const NetPacketGameListNew * +NetPacketGameListNew::ToNetPacketGameListNew() const +{ + return this; +} + +void +NetPacketGameListNew::InternalCheck(const NetPacketHeader* data) const +{ + u_int16_t dataLen = ntohs(data->length); + NetPacketGameListNewData *tmpData = (NetPacketGameListNewData *)data; + int gameNameLength = ntohs(tmpData->gameNameLength); + // Exact checking of dynamic packet size. + if (dataLen != + sizeof(NetPacketGameListNewData) + + ADD_PADDING(gameNameLength)) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } + // Check string size. + if (!gameNameLength + || gameNameLength > MAX_NAME_SIZE) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } + // Check name string. + char *namePtr = (char *)tmpData + sizeof(NetPacketGameListNewData); + if (namePtr[0] == 0) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } +} + +//----------------------------------------------------------------------------- + +NetPacketGameListUpdate::NetPacketGameListUpdate() +: NetPacket(NET_TYPE_GAME_LIST_UPDATE, sizeof(NetPacketGameListUpdateData), sizeof(NetPacketGameListUpdateData)) +{ +} + +NetPacketGameListUpdate::~NetPacketGameListUpdate() +{ +} + +boost::shared_ptr +NetPacketGameListUpdate::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketGameListUpdate); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketGameListUpdate::SetData(const NetPacketGameListUpdate::Data &inData) +{ + NetPacketGameListUpdateData *tmpData = (NetPacketGameListUpdateData *)GetRawData(); + + // Set the data. + tmpData->gameId = htonl(inData.gameId); + tmpData->gameMode = htons(inData.gameMode); + + // Check the packet - just in case. + Check(GetRawData()); +} + +void +NetPacketGameListUpdate::GetData(NetPacketGameListUpdate::Data &outData) const +{ + // We assume that the data is valid. Validity has already been checked. + NetPacketGameListUpdateData *tmpData = (NetPacketGameListUpdateData *)GetRawData(); + + outData.gameId = ntohl(tmpData->gameId); + outData.gameMode = static_cast(ntohs(tmpData->gameMode)); +} + +const NetPacketGameListUpdate * +NetPacketGameListUpdate::ToNetPacketGameListUpdate() const +{ + return this; +} + +void +NetPacketGameListUpdate::InternalCheck(const NetPacketHeader* data) const +{ + // Nothing to do. +} + +//----------------------------------------------------------------------------- + +NetPacketCreateGame::NetPacketCreateGame() +: NetPacket(NET_TYPE_CREATE_GAME, sizeof(NetPacketCreateGameData), MAX_PACKET_SIZE) +{ +} + +NetPacketCreateGame::~NetPacketCreateGame() +{ +} + +boost::shared_ptr +NetPacketCreateGame::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketCreateGame); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketCreateGame::SetData(const NetPacketCreateGame::Data &inData) +{ + u_int16_t gameNameLen = (u_int16_t)inData.gameName.length(); + u_int16_t passwordLen = (u_int16_t)inData.password.length(); + + // Some basic checks, so we don't use up too much memory. + // The constructed packet will also be checked. + if (!gameNameLen || gameNameLen > MAX_NAME_SIZE) + throw NetException(ERR_NET_INVALID_PLAYER_NAME, 0); + if (passwordLen > MAX_PASSWORD_SIZE) + throw NetException(ERR_NET_INVALID_PASSWORD_STR, 0); + + // Resize the packet so that the data fits in. + Resize((u_int16_t) + (sizeof(NetPacketCreateGameData) + ADD_PADDING(gameNameLen) + ADD_PADDING(passwordLen))); + + NetPacketCreateGameData *tmpData = (NetPacketCreateGameData *)GetRawData(); + + // Set the data. + tmpData->passwordLength = htons(passwordLen); + tmpData->gameNameLength = htons(gameNameLen); + tmpData->maxNumberOfPlayers = htons(inData.gameData.maxNumberOfPlayers); + tmpData->smallBlind = htons(inData.gameData.smallBlind); + tmpData->handsBeforeRaise = htons(inData.gameData.handsBeforeRaise); + tmpData->proposedGuiSpeed = htons(inData.gameData.guiSpeed); + tmpData->playerActionTimeout = htons(inData.gameData.playerActionTimeoutSec); + tmpData->startMoney = htonl(inData.gameData.startMoney); + + char *passwordPtr = (char *)tmpData + sizeof(NetPacketCreateGameData); + memcpy(passwordPtr, inData.password.c_str(), passwordLen); + memcpy(passwordPtr + ADD_PADDING(passwordLen), inData.gameName.c_str(), gameNameLen); + + // Check the packet - just in case. + Check(GetRawData()); +} + +void +NetPacketCreateGame::GetData(NetPacketCreateGame::Data &outData) const +{ + // We assume that the data is valid. Validity has already been checked. + NetPacketCreateGameData *tmpData = (NetPacketCreateGameData *)GetRawData(); + + outData.gameData.maxNumberOfPlayers = ntohs(tmpData->maxNumberOfPlayers); + outData.gameData.smallBlind = ntohs(tmpData->smallBlind); + outData.gameData.handsBeforeRaise = ntohs(tmpData->handsBeforeRaise); + outData.gameData.guiSpeed = ntohs(tmpData->proposedGuiSpeed); + outData.gameData.playerActionTimeoutSec = ntohs(tmpData->playerActionTimeout); + outData.gameData.startMoney = ntohl(tmpData->startMoney); + + u_int16_t passwordLen = ntohs(tmpData->passwordLength); + char *passwordPtr = (char *)tmpData + sizeof(NetPacketCreateGameData); + outData.password = string(passwordPtr, passwordLen); + outData.gameName = string(passwordPtr + ADD_PADDING(passwordLen), ntohs(tmpData->gameNameLength)); +} + +const NetPacketCreateGame * +NetPacketCreateGame::ToNetPacketCreateGame() const +{ + return this; +} + +void +NetPacketCreateGame::InternalCheck(const NetPacketHeader* data) const +{ + u_int16_t dataLen = ntohs(data->length); + NetPacketCreateGameData *tmpData = (NetPacketCreateGameData *)data; + int passwordLength = ntohs(tmpData->passwordLength); + int gameNameLength = ntohs(tmpData->gameNameLength); + // Exact checking of dynamic packet size. + if (dataLen < + sizeof(NetPacketCreateGameData) + + ADD_PADDING(passwordLength) + + ADD_PADDING(gameNameLength)) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } + // Check string sizes. + if (passwordLength > MAX_PASSWORD_SIZE + || !gameNameLength + || gameNameLength > MAX_NAME_SIZE) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } + // Check name string. + char *namePtr = (char *)tmpData + sizeof(NetPacketCreateGameData) + ADD_PADDING(passwordLength); + if (namePtr[0] == 0) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } + // Semantic checks + int maxNumPlayers = ntohs(tmpData->maxNumberOfPlayers); + int proposedGuiSpeed = ntohs(tmpData->proposedGuiSpeed); + if (maxNumPlayers < MIN_NUMBER_OF_PLAYERS + || maxNumPlayers > MAX_NUMBER_OF_PLAYERS + || !ntohs(tmpData->smallBlind) + || !ntohs(tmpData->handsBeforeRaise) + || proposedGuiSpeed < MIN_GUI_SPEED + || proposedGuiSpeed > MAX_GUI_SPEED + || !ntohl(tmpData->startMoney)) + { + throw NetException(ERR_SOCK_INVALID_PACKET, 0); + } +} + +//----------------------------------------------------------------------------- + +NetPacketCreateGameAck::NetPacketCreateGameAck() +: NetPacket(NET_TYPE_CREATE_GAME_ACK, sizeof(NetPacketCreateGameAckData), sizeof(NetPacketCreateGameAckData)) +{ +} + +NetPacketCreateGameAck::~NetPacketCreateGameAck() +{ +} + +boost::shared_ptr +NetPacketCreateGameAck::Clone() const +{ + boost::shared_ptr newPacket(new NetPacketCreateGameAck); + try + { + newPacket->SetRawData(GetRawData()); + } catch (const NetException &) + { + // Need to return the new packet anyway. + } + return newPacket; +} + +void +NetPacketCreateGameAck::SetData(const NetPacketCreateGameAck::Data &inData) +{ + NetPacketCreateGameAckData *tmpData = (NetPacketCreateGameAckData *)GetRawData(); + + tmpData->gameId = htonl(inData.gameId); + + // Check the packet - just in case. + Check(GetRawData()); +} + +void +NetPacketCreateGameAck::GetData(NetPacketCreateGameAck::Data &outData) const +{ + NetPacketCreateGameAckData *tmpData = (NetPacketCreateGameAckData *)GetRawData(); + + outData.gameId = ntohl(tmpData->gameId); +} + +const NetPacketCreateGameAck * +NetPacketCreateGameAck::ToNetPacketCreateGameAck() const +{ + return this; +} + +void +NetPacketCreateGameAck::InternalCheck(const NetPacketHeader* data) const +{ + // Nothing to do. +} + +//----------------------------------------------------------------------------- + NetPacketJoinGame::NetPacketJoinGame() : NetPacket(NET_TYPE_JOIN_GAME, sizeof(NetPacketJoinGameData), MAX_PACKET_SIZE) { - NetPacketJoinGameData *tmpData = (NetPacketJoinGameData *)GetRawData(); - tmpData->requestedVersionMajor = htons(NET_VERSION_MAJOR); - tmpData->requestedVersionMinor = htons(NET_VERSION_MINOR); } NetPacketJoinGame::~NetPacketJoinGame() @@ -686,28 +1294,25 @@ NetPacketJoinGame::Clone() const void NetPacketJoinGame::SetData(const NetPacketJoinGame::Data &inData) { - u_int16_t playerNameLen = (u_int16_t)inData.playerName.length(); u_int16_t passwordLen = (u_int16_t)inData.password.length(); // Some basic checks, so we don't use up too much memory. // The constructed packet will also be checked. - if (!playerNameLen || playerNameLen > MAX_NAME_SIZE) - throw NetException(ERR_NET_INVALID_PLAYER_NAME, 0); if (passwordLen > MAX_PASSWORD_SIZE) throw NetException(ERR_NET_INVALID_PASSWORD_STR, 0); // Resize the packet so that the data fits in. Resize((u_int16_t) - (sizeof(NetPacketJoinGameData) + ADD_PADDING(playerNameLen) + ADD_PADDING(passwordLen))); + (sizeof(NetPacketJoinGameData) + ADD_PADDING(passwordLen))); NetPacketJoinGameData *tmpData = (NetPacketJoinGameData *)GetRawData(); // Set the data. - tmpData->passwordLength = htons(passwordLen); - tmpData->playerNameLength = htons(playerNameLen); + tmpData->gameId = htonl(inData.gameId); + tmpData->passwordLength = htons(passwordLen); + char *passwordPtr = (char *)tmpData + sizeof(NetPacketJoinGameData); memcpy(passwordPtr, inData.password.c_str(), passwordLen); - memcpy(passwordPtr + ADD_PADDING(passwordLen), inData.playerName.c_str(), playerNameLen); // Check the packet - just in case. Check(GetRawData()); @@ -719,13 +1324,11 @@ NetPacketJoinGame::GetData(NetPacketJoinGame::Data &outData) const // We assume that the data is valid. Validity has already been checked. NetPacketJoinGameData *tmpData = (NetPacketJoinGameData *)GetRawData(); - outData.versionMajor = ntohs(tmpData->requestedVersionMajor); - outData.versionMinor = ntohs(tmpData->requestedVersionMinor); + outData.gameId = ntohl(tmpData->gameId); u_int16_t passwordLen = ntohs(tmpData->passwordLength); char *passwordPtr = (char *)tmpData + sizeof(NetPacketJoinGameData); outData.password = string(passwordPtr, passwordLen); - outData.playerName = string(passwordPtr + ADD_PADDING(passwordLen), ntohs(tmpData->playerNameLength)); } const NetPacketJoinGame * @@ -740,28 +1343,15 @@ NetPacketJoinGame::InternalCheck(const NetPacketHeader* data) const u_int16_t dataLen = ntohs(data->length); NetPacketJoinGameData *tmpData = (NetPacketJoinGameData *)data; int passwordLength = ntohs(tmpData->passwordLength); - int playerNameLength = ntohs(tmpData->playerNameLength); - // Generous checking of dynamic packet size - - // larger packets are allowed. - // This is because the version number is in this packet, - // and later versions might provide larger packets. + // Exact checking of dynamic packet size. if (dataLen < sizeof(NetPacketJoinGameData) - + ADD_PADDING(passwordLength) - + ADD_PADDING(playerNameLength)) + + ADD_PADDING(passwordLength)) { throw NetException(ERR_SOCK_INVALID_PACKET, 0); } - // Check string sizes. - if (passwordLength > MAX_PASSWORD_SIZE - || !playerNameLength - || playerNameLength > MAX_NAME_SIZE) - { - throw NetException(ERR_SOCK_INVALID_PACKET, 0); - } - // Check name string. - char *namePtr = (char *)tmpData + sizeof(NetPacketJoinGameData) + ADD_PADDING(passwordLength); - if (namePtr[0] == 0) + // Check string size. + if (passwordLength > MAX_PASSWORD_SIZE) { throw NetException(ERR_SOCK_INVALID_PACKET, 0); } @@ -797,15 +1387,7 @@ NetPacketJoinGameAck::SetData(const NetPacketJoinGameAck::Data &inData) { NetPacketJoinGameAckData *tmpData = (NetPacketJoinGameAckData *)GetRawData(); - u_int16_t tmpPlayerFlags = 0; - if (inData.ptype == PLAYER_TYPE_HUMAN) - tmpPlayerFlags |= NET_PLAYER_FLAG_HUMAN; - if (inData.prights == PLAYER_RIGHTS_ADMIN) - tmpPlayerFlags |= NET_PLAYER_FLAG_ADMIN; - - tmpData->sessionId = htonl(inData.sessionId); - tmpData->playerId = htons(inData.yourPlayerUniqueId); - tmpData->playerFlags = htons(tmpPlayerFlags); + // Set the data. tmpData->maxNumberOfPlayers = htons(inData.gameData.maxNumberOfPlayers); tmpData->smallBlind = htons(inData.gameData.smallBlind); tmpData->handsBeforeRaise = htons(inData.gameData.handsBeforeRaise); @@ -820,12 +1402,9 @@ NetPacketJoinGameAck::SetData(const NetPacketJoinGameAck::Data &inData) void NetPacketJoinGameAck::GetData(NetPacketJoinGameAck::Data &outData) const { + // We assume that the data is valid. Validity has already been checked. NetPacketJoinGameAckData *tmpData = (NetPacketJoinGameAckData *)GetRawData(); - outData.sessionId = ntohl(tmpData->sessionId); - outData.yourPlayerUniqueId = ntohs(tmpData->playerId); - outData.ptype = (ntohs(tmpData->playerFlags) & NET_PLAYER_FLAG_HUMAN) ? PLAYER_TYPE_HUMAN : PLAYER_TYPE_COMPUTER; - outData.prights = (ntohs(tmpData->playerFlags) & NET_PLAYER_FLAG_ADMIN) ? PLAYER_RIGHTS_ADMIN : PLAYER_RIGHTS_NORMAL; outData.gameData.maxNumberOfPlayers = ntohs(tmpData->maxNumberOfPlayers); outData.gameData.smallBlind = ntohs(tmpData->smallBlind); outData.gameData.handsBeforeRaise = ntohs(tmpData->handsBeforeRaise); @@ -843,6 +1422,7 @@ NetPacketJoinGameAck::ToNetPacketJoinGameAck() const void NetPacketJoinGameAck::InternalCheck(const NetPacketHeader* data) const { + u_int16_t dataLen = ntohs(data->length); NetPacketJoinGameAckData *tmpData = (NetPacketJoinGameAckData *)data; // Semantic checks int maxNumPlayers = ntohs(tmpData->maxNumberOfPlayers); @@ -905,9 +1485,9 @@ NetPacketPlayerJoined::SetData(const NetPacketPlayerJoined::Data &inData) tmpPlayerFlags |= NET_PLAYER_FLAG_ADMIN; // Set the data. - tmpData->playerFlags = htons(tmpPlayerFlags); - tmpData->playerId = htons(inData.playerId); - tmpData->playerNameLength = htons(playerNameLen); + tmpData->playerId = htonl(inData.playerId); + tmpData->playerFlags = htons(tmpPlayerFlags); + tmpData->playerNameLength = htons(playerNameLen); char *namePtr = (char *)tmpData + sizeof(NetPacketPlayerJoinedData); memcpy(namePtr, inData.playerName.c_str(), playerNameLen); @@ -921,9 +1501,9 @@ NetPacketPlayerJoined::GetData(NetPacketPlayerJoined::Data &outData) const // We assume that the data is valid. Validity has already been checked. NetPacketPlayerJoinedData *tmpData = (NetPacketPlayerJoinedData *)GetRawData(); + outData.playerId = ntohl(tmpData->playerId); outData.ptype = (ntohs(tmpData->playerFlags) & NET_PLAYER_FLAG_HUMAN) ? PLAYER_TYPE_HUMAN : PLAYER_TYPE_COMPUTER; outData.prights = (ntohs(tmpData->playerFlags) & NET_PLAYER_FLAG_ADMIN) ? PLAYER_RIGHTS_ADMIN : PLAYER_RIGHTS_NORMAL; - outData.playerId = ntohs(tmpData->playerId); char *namePtr = (char *)tmpData + sizeof(NetPacketPlayerJoinedData); outData.playerName = string(namePtr, ntohs(tmpData->playerNameLength)); } @@ -986,7 +1566,7 @@ NetPacketPlayerLeft::SetData(const NetPacketPlayerLeft::Data &inData) NetPacketPlayerLeftData *tmpData = (NetPacketPlayerLeftData *)GetRawData(); // Set the data. - tmpData->playerId = htons(inData.playerId); + tmpData->playerId = htonl(inData.playerId); // Check the packet - just in case. Check(GetRawData()); @@ -998,7 +1578,7 @@ NetPacketPlayerLeft::GetData(NetPacketPlayerLeft::Data &outData) const // We assume that the data is valid. Validity has already been checked. NetPacketPlayerLeftData *tmpData = (NetPacketPlayerLeftData *)GetRawData(); - outData.playerId = ntohs(tmpData->playerId); + outData.playerId = ntohl(tmpData->playerId); } const NetPacketPlayerLeft * @@ -1044,7 +1624,7 @@ NetPacketKickPlayer::SetData(const NetPacketKickPlayer::Data &inData) NetPacketKickPlayerData *tmpData = (NetPacketKickPlayerData *)GetRawData(); // Set the data. - tmpData->playerId = htons(inData.playerId); + tmpData->playerId = htonl(inData.playerId); // Check the packet - just in case. Check(GetRawData()); @@ -1056,7 +1636,7 @@ NetPacketKickPlayer::GetData(NetPacketKickPlayer::Data &outData) const // We assume that the data is valid. Validity has already been checked. NetPacketKickPlayerData *tmpData = (NetPacketKickPlayerData *)GetRawData(); - outData.playerId = ntohs(tmpData->playerId); + outData.playerId = ntohl(tmpData->playerId); } const NetPacketKickPlayer * @@ -1148,7 +1728,7 @@ NetPacketGameStart::SetData(const NetPacketGameStart::Data &inData) NetPacketGameStartData *tmpData = (NetPacketGameStartData *)GetRawData(); - tmpData->startDealerPlayerId = htons(inData.startData.startDealerPlayerId); + tmpData->startDealerPlayerId = htonl(inData.startData.startDealerPlayerId); tmpData->numberOfPlayers = htons(numPlayers); PlayerSlotList::const_iterator i = inData.playerSlots.begin(); @@ -1159,7 +1739,7 @@ NetPacketGameStart::SetData(const NetPacketGameStart::Data &inData) (PlayerSlotData *)((char *)tmpData + sizeof(NetPacketGameStartData)); while (i != end) { - curPlayerSlotData->playerId = htons((*i).playerId); + curPlayerSlotData->playerId = htonl((*i).playerId); ++curPlayerSlotData; ++i; } @@ -1173,7 +1753,7 @@ NetPacketGameStart::GetData(NetPacketGameStart::Data &outData) const { NetPacketGameStartData *tmpData = (NetPacketGameStartData *)GetRawData(); - outData.startData.startDealerPlayerId = ntohs(tmpData->startDealerPlayerId); + outData.startData.startDealerPlayerId = ntohl(tmpData->startDealerPlayerId); u_int16_t numPlayers = ntohs(tmpData->numberOfPlayers); outData.startData.numberOfPlayers = numPlayers; @@ -1184,7 +1764,7 @@ NetPacketGameStart::GetData(NetPacketGameStart::Data &outData) const for (int i = 0; i < numPlayers; i++) { PlayerSlot tmpPlayerSlot; - tmpPlayerSlot.playerId = ntohs(curPlayerSlotData->playerId); + tmpPlayerSlot.playerId = ntohl(curPlayerSlotData->playerId); outData.playerSlots.push_back(tmpPlayerSlot); ++curPlayerSlotData; @@ -1206,7 +1786,7 @@ NetPacketGameStart::InternalCheck(const NetPacketHeader* data) const // Check exact packet size. if (dataLen != sizeof(NetPacketGameStartData) - + ADD_PADDING(numPlayers * sizeof(PlayerSlotData))) + + numPlayers * sizeof(PlayerSlotData)) { throw NetException(ERR_SOCK_INVALID_PACKET, 0); } @@ -1305,8 +1885,8 @@ NetPacketPlayersTurn::SetData(const NetPacketPlayersTurn::Data &inData) { NetPacketPlayersTurnData *tmpData = (NetPacketPlayersTurnData *)GetRawData(); + tmpData->playerId = htonl(inData.playerId); tmpData->gameState = htons(inData.gameState); - tmpData->playerId = htons(inData.playerId); // Check the packet - just in case. Check(GetRawData()); @@ -1317,8 +1897,8 @@ NetPacketPlayersTurn::GetData(NetPacketPlayersTurn::Data &outData) const { NetPacketPlayersTurnData *tmpData = (NetPacketPlayersTurnData *)GetRawData(); + outData.playerId = ntohl(tmpData->playerId); outData.gameState = static_cast(ntohs(tmpData->gameState)); - outData.playerId = ntohs(tmpData->playerId); } const NetPacketPlayersTurn * @@ -1439,8 +2019,8 @@ NetPacketPlayersActionDone::SetData(const NetPacketPlayersActionDone::Data &inDa { NetPacketPlayersActionDoneData *tmpData = (NetPacketPlayersActionDoneData *)GetRawData(); + tmpData->playerId = htonl(inData.playerId); tmpData->gameState = htons(inData.gameState); - tmpData->playerId = htons(inData.playerId); tmpData->playerAction = htons(inData.playerAction); tmpData->totalPlayerBet = htonl(inData.totalPlayerBet); tmpData->playerMoney = htonl(inData.playerMoney); @@ -1454,8 +2034,8 @@ NetPacketPlayersActionDone::GetData(NetPacketPlayersActionDone::Data &outData) c { NetPacketPlayersActionDoneData *tmpData = (NetPacketPlayersActionDoneData *)GetRawData(); + outData.playerId = ntohl(tmpData->playerId); outData.gameState = static_cast(ntohs(tmpData->gameState)); - outData.playerId = ntohs(tmpData->playerId); outData.playerAction = static_cast(ntohs(tmpData->playerAction)); outData.totalPlayerBet = ntohl(tmpData->totalPlayerBet); outData.playerMoney = ntohl(tmpData->playerMoney); @@ -1795,7 +2375,7 @@ NetPacketAllInShowCards::SetData(const NetPacketAllInShowCards::Data &inData) (PlayerCardsData *)((char *)tmpData + sizeof(NetPacketAllInShowCardsData)); while (i != end) { - curPlayerCardsData->playerId = htons((*i).playerId); + curPlayerCardsData->playerId = htonl((*i).playerId); curPlayerCardsData->card1 = htons((*i).cards[0]); curPlayerCardsData->card2 = htons((*i).cards[1]); ++curPlayerCardsData; @@ -1821,7 +2401,7 @@ NetPacketAllInShowCards::GetData(NetPacketAllInShowCards::Data &outData) const for (int i = 0; i < numPlayerCards; i++) { PlayerCards tmpPlayerCards; - tmpPlayerCards.playerId = ntohs(curPlayerCardsData->playerId); + tmpPlayerCards.playerId = ntohl(curPlayerCardsData->playerId); tmpPlayerCards.cards[0] = ntohs(curPlayerCardsData->card1); tmpPlayerCards.cards[1] = ntohs(curPlayerCardsData->card2); @@ -1905,7 +2485,7 @@ NetPacketEndOfHandShowCards::SetData(const NetPacketEndOfHandShowCards::Data &in (PlayerResultData *)((char *)tmpData + sizeof(NetPacketEndOfHandShowCardsData)); while (i != end) { - curPlayerResultData->playerId = htons((*i).playerId); + curPlayerResultData->playerId = htonl((*i).playerId); curPlayerResultData->card1 = htons((*i).cards[0]); curPlayerResultData->card2 = htons((*i).cards[1]); curPlayerResultData->bestHandPos1 = htons((*i).bestHandPos[0]); @@ -1939,7 +2519,7 @@ NetPacketEndOfHandShowCards::GetData(NetPacketEndOfHandShowCards::Data &outData) for (int i = 0; i < numPlayerResults; i++) { PlayerResult tmpPlayerResult; - tmpPlayerResult.playerId = ntohs(curPlayerResultData->playerId); + tmpPlayerResult.playerId = ntohl(curPlayerResultData->playerId); tmpPlayerResult.cards[0] = ntohs(curPlayerResultData->card1); tmpPlayerResult.cards[1] = ntohs(curPlayerResultData->card2); tmpPlayerResult.bestHandPos[0] = ntohs(curPlayerResultData->bestHandPos1); @@ -2012,7 +2592,7 @@ NetPacketEndOfHandHideCards::SetData(const NetPacketEndOfHandHideCards::Data &in { NetPacketEndOfHandHideCardsData *tmpData = (NetPacketEndOfHandHideCardsData *)GetRawData(); - tmpData->playerId = htons(inData.playerId); + tmpData->playerId = htonl(inData.playerId); tmpData->moneyWon = htonl(inData.moneyWon); tmpData->playerMoney = htonl(inData.playerMoney); @@ -2025,7 +2605,7 @@ NetPacketEndOfHandHideCards::GetData(NetPacketEndOfHandHideCards::Data &outData) { NetPacketEndOfHandHideCardsData *tmpData = (NetPacketEndOfHandHideCardsData *)GetRawData(); - outData.playerId = ntohs(tmpData->playerId); + outData.playerId = ntohl(tmpData->playerId); outData.moneyWon = ntohl(tmpData->moneyWon); outData.playerMoney = ntohl(tmpData->playerMoney); } @@ -2072,7 +2652,7 @@ NetPacketEndOfGame::SetData(const NetPacketEndOfGame::Data &inData) { NetPacketEndOfGameData *tmpData = (NetPacketEndOfGameData *)GetRawData(); - tmpData->winnerPlayerId = htons(inData.winnerPlayerId); + tmpData->winnerPlayerId = htonl(inData.winnerPlayerId); // Check the packet - just in case. Check(GetRawData()); @@ -2083,7 +2663,7 @@ NetPacketEndOfGame::GetData(NetPacketEndOfGame::Data &outData) const { NetPacketEndOfGameData *tmpData = (NetPacketEndOfGameData *)GetRawData(); - outData.winnerPlayerId = ntohs(tmpData->winnerPlayerId); + outData.winnerPlayerId = ntohl(tmpData->winnerPlayerId); } const NetPacketEndOfGame * @@ -2229,7 +2809,7 @@ NetPacketChatText::SetData(const NetPacketChatText::Data &inData) NetPacketChatTextData *tmpData = (NetPacketChatTextData *)GetRawData(); // Set the data. - tmpData->playerId = htons(inData.playerId); + tmpData->playerId = htonl(inData.playerId); tmpData->textLength = htons(textLen); char *textPtr = (char *)tmpData + sizeof(NetPacketChatTextData); memcpy(textPtr, inData.text.c_str(), textLen); @@ -2244,7 +2824,7 @@ NetPacketChatText::GetData(NetPacketChatText::Data &outData) const // We assume that the data is valid. Validity has already been checked. NetPacketChatTextData *tmpData = (NetPacketChatTextData *)GetRawData(); - outData.playerId = ntohs(tmpData->playerId); + outData.playerId = ntohl(tmpData->playerId); char *textPtr = (char *)tmpData + sizeof(NetPacketChatTextData); outData.text = string(textPtr, ntohs(tmpData->textLength)); } diff --git a/src/net/common/serverrecvthread.cpp b/src/net/common/serverrecvthread.cpp index 0ac87f61..ca410ecd 100644 --- a/src/net/common/serverrecvthread.cpp +++ b/src/net/common/serverrecvthread.cpp @@ -19,18 +19,18 @@ #include #include -#include #include #include #include #include -#include -#include -#include +#include #include #define SERVER_CLOSE_SESSION_DELAY_SEC 10 +#define SERVER_MAX_NUM_SESSIONS 64 // Maximum number of idle users in lobby. + +#define SERVER_COMPUTER_PLAYER_NAME "Computer" using namespace std; @@ -38,60 +38,56 @@ using namespace std; class ServerSenderCallback : public SenderCallback { public: - ServerSenderCallback(ServerRecvThread &server) : m_server(server) {} + ServerSenderCallback(ServerLobbyThread &server) : m_server(server) {} virtual ~ServerSenderCallback() {} virtual void SignalNetError(SOCKET sock, int errorID, int osErrorID) { // We just ignore send errors for now, on server side. - // A send error should trigger a read error or a read + // A serious send error should trigger a read error or a read // returning 0 afterwards, and we will handle this error. } private: - ServerRecvThread &m_server; + ServerLobbyThread &m_server; }; -ServerRecvThread::ServerRecvThread(GuiInterface &gui, ConfigFile *playerConfig) -: m_curGameId(1), m_gui(gui), m_playerConfig(playerConfig) +ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig) +: m_gui(gui), m_playerConfig(playerConfig) { m_senderCallback.reset(new ServerSenderCallback(*this)); m_sender.reset(new SenderThread(GetSenderCallback())); m_receiver.reset(new ReceiverHelper); } -ServerRecvThread::~ServerRecvThread() +ServerLobbyThread::~ServerLobbyThread() { CleanupConnectQueue(); - CleanupSessionMap(); } void -ServerRecvThread::Init(const string &pwd, const GameData &gameData) +ServerLobbyThread::Init(const string &pwd) { m_password = pwd; - m_gameData = gameData; } void -ServerRecvThread::AddConnection(boost::shared_ptr data) +ServerLobbyThread::AddConnection(boost::shared_ptr data) { boost::mutex::scoped_lock lock(m_connectQueueMutex); m_connectQueue.push_back(data); } -void -ServerRecvThread::AddNotification(unsigned message, const string ¶m) +u_int32_t +ServerLobbyThread::GetNextUniquePlayerId() { - boost::mutex::scoped_lock lock(m_notificationQueueMutex); - m_notificationQueue.push_back(Notification(message, param)); + return m_curUniquePlayerId++; } void -ServerRecvThread::Main() +ServerLobbyThread::Main() { - SetState(SERVER_INITIAL_STATE::Instance()); GetSender().Run(); try @@ -110,12 +106,10 @@ ServerRecvThread::Main() } } if (tmpData.get()) - GetState().HandleNewConnection(*this, tmpData); + HandleNewConnection(tmpData); } - // Process current state. - GetState().Process(*this); - // Process thread-safe notifications. - NotificationLoop(); + // Process loop. + ProcessLoop(); // Close sessions. CloseSessionLoop(); } @@ -127,28 +121,131 @@ ServerRecvThread::Main() GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT); CleanupConnectQueue(); - CleanupSessionMap(); + m_sessionManager.Clear(); } void -ServerRecvThread::NotificationLoop() +ServerLobbyThread::ProcessLoop() { - boost::mutex::scoped_lock lock(m_notificationQueueMutex); - // Process all notifications. - while (!m_notificationQueue.empty()) - { - Notification notification = m_notificationQueue.front(); - m_notificationQueue.pop_front(); + // Wait for data. + SessionWrapper session = m_sessionManager.Select(RECV_TIMEOUT_MSEC); -// switch(notification.message) -// { -// break; -// } + if (session.sessionData.get()) + { + boost::shared_ptr packet; + try + { + // Receive the next packet. + packet = GetReceiver().Recv(session.sessionData->GetSocket()); + } catch (const NetException &) + { + // On error: Close this session. + CloseSessionDelayed(session); + return; + } + if (packet.get()) + { + if (packet->ToNetPacketInit()) + { + // Session should be in initial state. + if (session.sessionData->GetState() != SessionData::Init) + SessionError(session, ERR_SOCK_INVALID_STATE); + else + HandleNetPacketInit(session, *packet->ToNetPacketInit()); + } + // Session should be established. + else if (session.sessionData->GetState() != SessionData::Established) + SessionError(session, ERR_SOCK_INVALID_STATE); + else + { + if (packet->ToNetPacketCreateGame()) + HandleNetPacketCreateGame(session, *packet->ToNetPacketCreateGame()); + else if (packet->ToNetPacketJoinGame()) + HandleNetPacketJoinGame(session, *packet->ToNetPacketJoinGame()); + } + } } } void -ServerRecvThread::CloseSessionLoop() +ServerLobbyThread::HandleNetPacketInit(SessionWrapper session, const NetPacketInit &tmpPacket) +{ + NetPacketInit::Data initData; + tmpPacket.GetData(initData); + + // Check the protocol version. + if (initData.versionMajor != NET_VERSION_MAJOR) + { + SessionError(session, ERR_NET_VERSION_NOT_SUPPORTED); + return; + } + + // Check the server password. + if (!CheckPassword(initData.password)) + { + SessionError(session, ERR_NET_INVALID_PASSWORD); + return; + } + + // Check whether the player name is correct. + // Partly, this is also done in netpacket. + // However, some disallowed names are checked only here. + if (initData.playerName.empty() || initData.playerName.size() > MAX_NAME_SIZE + || initData.playerName.substr(0, sizeof(SERVER_COMPUTER_PLAYER_NAME) - 1) == SERVER_COMPUTER_PLAYER_NAME) + { + SessionError(session, ERR_NET_INVALID_PLAYER_NAME); + return; + } + + // Check whether this player is already connected. + if (IsPlayerConnected(initData.playerName)) + { + SessionError(session, ERR_NET_PLAYER_NAME_IN_USE); + return; + } + + // Create player data object. + boost::shared_ptr tmpPlayerData( + new PlayerData(GetNextUniquePlayerId(), 0, PLAYER_TYPE_HUMAN, PLAYER_RIGHTS_NORMAL)); + tmpPlayerData->SetName(initData.playerName); + tmpPlayerData->SetNetSessionData(session.sessionData); + + // Send ACK to client. + boost::shared_ptr initAck(new NetPacketInitAck); + NetPacketInitAck::Data initAckData; + initAckData.sessionId = session.sessionData->GetId(); // TODO: currently unused. + initAckData.playerId = tmpPlayerData->GetUniqueId(); + static_cast(initAck.get())->SetData(initAckData); + GetSender().Send(session.sessionData->GetSocket(), initAck); + + // Send the game list to the client. + /*GameThreadList::iterator game_i = m_gameList.begin(); + GameThreadList::iterator game_end = m_gameList.end(); + while (game_i != game_end) + { + GetSender().Send(session.sessionData->GetSocket(), CreateNetPacketGameListUpdate(*(*game_i))); + ++game_i; + }*/ + + // Set player data for session. + m_sessionManager.SetSessionPlayerData(session.sessionData->GetSocket(), tmpPlayerData); + + // Session is now established. + session.sessionData->SetState(SessionData::Established); +} + +void +ServerLobbyThread::HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket) +{ +} + +void +ServerLobbyThread::HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket) +{ +} + +void +ServerLobbyThread::CloseSessionLoop() { CloseSessionList::iterator i = m_closeSessionList.begin(); CloseSessionList::iterator end = m_closeSessionList.end(); @@ -162,69 +259,32 @@ ServerRecvThread::CloseSessionLoop() } } -SOCKET -ServerRecvThread::Select() +void +ServerLobbyThread::HandleNewConnection(boost::shared_ptr connData) { - SOCKET retSock = INVALID_SOCKET; - - SOCKET maxSock = INVALID_SOCKET; - fd_set rdset; - FD_ZERO(&rdset); - + if (m_sessionManager.GetRawSessionCount() <= SERVER_MAX_NUM_SESSIONS) { - boost::mutex::scoped_lock lock(m_sessionMapMutex); - SocketSessionMap::iterator i = m_sessionMap.begin(); - SocketSessionMap::iterator end = m_sessionMap.end(); + // Create a random session id. + // This id can be used to reconnect to the server if the connection was lost. + unsigned sessionId; + RandomBytes((unsigned char *)&sessionId, sizeof(sessionId)); // TODO: check for collisions. - while (i != end) - { - SOCKET tmpSock = i->first; - FD_SET(tmpSock, &rdset); - if (tmpSock > maxSock || maxSock == INVALID_SOCKET) - maxSock = tmpSock; - ++i; - } - } - - if (maxSock == INVALID_SOCKET) - { - Msleep(RECV_TIMEOUT_MSEC); // just sleep if there is no session + // Create a new session. + boost::shared_ptr sessionData(new SessionData(connData->ReleaseSocket(), sessionId)); + m_sessionManager.AddSession(sessionData); } else { - // wait for data - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = RECV_TIMEOUT_MSEC * 1000; - int selectResult = select(maxSock + 1, &rdset, NULL, NULL, &timeout); - if (!IS_VALID_SELECT(selectResult)) - { - throw ServerException(ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO()); - } - if (selectResult > 0) // one (or more) of the sockets is readable - { - // Check which socket is readable, return the first. - boost::mutex::scoped_lock lock(m_sessionMapMutex); - SocketSessionMap::iterator i = m_sessionMap.begin(); - SocketSessionMap::iterator end = m_sessionMap.end(); - - while (i != end) - { - SOCKET tmpSock = i->first; - if (FD_ISSET(tmpSock, &rdset)) - { - retSock = tmpSock; - break; - } - ++i; - } - } + // Server is full. + // Create a generic session with Id 0. + boost::shared_ptr sessionData(new SessionData(connData->ReleaseSocket(), 0)); + // Gracefully close this session. + SessionError(SessionWrapper(sessionData, boost::shared_ptr()), ERR_NET_SERVER_FULL); } - return retSock; } void -ServerRecvThread::CleanupConnectQueue() +ServerLobbyThread::CleanupConnectQueue() { boost::mutex::scoped_lock lock(m_connectQueueMutex); @@ -233,155 +293,7 @@ ServerRecvThread::CleanupConnectQueue() } void -ServerRecvThread::CleanupSessionMap() -{ - boost::mutex::scoped_lock lock(m_sessionMapMutex); - - // Sockets will be closed automatically. - m_sessionMap.clear(); -} - -void -ServerRecvThread::InternalStartGame() -{ - // Kick all players which are not fully connected. - RemoveNotEstablishedSessions(); - // Set order of players. - AssignPlayerNumbers(); - - // Initialize the game. - GuiInterface &gui = GetGui(); - PlayerDataList playerData = GetPlayerDataList(); - - // Create EngineFactory - boost::shared_ptr factory(new LocalEngineFactory(m_playerConfig)); // LocalEngine erstellen - - // Set start data. - StartData startData; - startData.numberOfPlayers = playerData.size(); - - int tmpDealerPos = 0; - Tools::getRandNumber(0, startData.numberOfPlayers-1, 1, &tmpDealerPos, 0); - // The Player Id is not continuous. Therefore, the start dealer position - // needs to be converted to a player Id, and cannot be directly generated - // as player Id. - PlayerDataList::const_iterator player_i = playerData.begin(); - PlayerDataList::const_iterator player_end = playerData.end(); - - bool randDealerFound = false; - while (player_i != player_end) - { - if ((*player_i)->GetNumber() == tmpDealerPos) - { - // Get ID of the dealer. - startData.startDealerPlayerId = static_cast((*player_i)->GetUniqueId()); - randDealerFound = true; - break; - } - ++player_i; - } - assert(randDealerFound); // TODO: Throw exception. - - SetStartData(startData); - - m_game.reset(new Game(&gui, factory, playerData, GetGameData(), GetStartData(), m_curGameId++)); -} - -void -ServerRecvThread::InternalKickPlayer(unsigned uniqueId) -{ - SessionWrapper tmpSession = GetSessionByUniquePlayerId(uniqueId); - SessionError(tmpSession, ERR_NET_PLAYER_KICKED); -} - -SessionWrapper -ServerRecvThread::GetSession(SOCKET sock) const -{ - SessionWrapper tmpSession; - boost::mutex::scoped_lock lock(m_sessionMapMutex); - - SocketSessionMap::const_iterator pos = m_sessionMap.find(sock); - if (pos != m_sessionMap.end()) - { - tmpSession = pos->second; - } - return tmpSession; -} - -SessionWrapper -ServerRecvThread::GetSessionByPlayerName(const string playerName) const -{ - SessionWrapper tmpSession; - boost::mutex::scoped_lock lock(m_sessionMapMutex); - - SocketSessionMap::const_iterator session_i = m_sessionMap.begin(); - SocketSessionMap::const_iterator session_end = m_sessionMap.end(); - - while (session_i != session_end) - { - // Check all players which are fully connected. - if (session_i->second.sessionData->GetState() == SessionData::Established) - { - boost::shared_ptr tmpPlayer(session_i->second.playerData); - assert(tmpPlayer.get()); - if (tmpPlayer->GetName() == playerName) - { - tmpSession = session_i->second; - break; - } - } - - ++session_i; - } - return tmpSession; -} - -SessionWrapper -ServerRecvThread::GetSessionByUniquePlayerId(unsigned uniqueId) const -{ - SessionWrapper tmpSession; - boost::mutex::scoped_lock lock(m_sessionMapMutex); - - SocketSessionMap::const_iterator session_i = m_sessionMap.begin(); - SocketSessionMap::const_iterator session_end = m_sessionMap.end(); - - while (session_i != session_end) - { - // Check all players which are fully connected. - if (session_i->second.sessionData->GetState() == SessionData::Established) - { - boost::shared_ptr tmpPlayer(session_i->second.playerData); - assert(tmpPlayer.get()); - if (tmpPlayer->GetUniqueId() == uniqueId) - { - tmpSession = session_i->second; - break; - } - } - - ++session_i; - } - return tmpSession; -} - -void -ServerRecvThread::AddSession(boost::shared_ptr sessionData) -{ - boost::mutex::scoped_lock lock(m_sessionMapMutex); - - SocketSessionMap::iterator pos = m_sessionMap.lower_bound(sessionData->GetSocket()); - - // If pos points to a pair whose key is equivalent to the socket, this handle - // already exists within the list. - if (pos != m_sessionMap.end() && sessionData->GetSocket() == pos->first) - { - throw ServerException(ERR_SOCK_CONN_EXISTS, 0); - } - m_sessionMap.insert(pos, SocketSessionMap::value_type(sessionData->GetSocket(), SessionWrapper(sessionData, boost::shared_ptr()))); -} - -void -ServerRecvThread::SessionError(SessionWrapper session, int errorCode) +ServerLobbyThread::SessionError(SessionWrapper session, int errorCode) { if (session.sessionData.get()) { @@ -391,22 +303,9 @@ ServerRecvThread::SessionError(SessionWrapper session, int errorCode) } void -ServerRecvThread::RejectNewConnection(boost::shared_ptr connData) +ServerLobbyThread::CloseSessionDelayed(SessionWrapper session) { - // Create a generic session with Id 0. - boost::shared_ptr sessionData(new SessionData(connData->ReleaseSocket(), 0)); - // Gracefully close this session. - SessionError(SessionWrapper(sessionData, boost::shared_ptr()), ERR_NET_GAME_ALREADY_RUNNING); -} - -void -ServerRecvThread::CloseSessionDelayed(SessionWrapper session) -{ - { - boost::mutex::scoped_lock lock(m_sessionMapMutex); - - m_sessionMap.erase(session.sessionData->GetSocket()); - } + m_sessionManager.RemoveSession(session.sessionData->GetSocket()); boost::shared_ptr tmpPlayerData = session.playerData; if (tmpPlayerData.get() && !tmpPlayerData->GetName().empty()) @@ -416,7 +315,7 @@ ServerRecvThread::CloseSessionDelayed(SessionWrapper session) NetPacketPlayerLeft::Data thisPlayerLeftData; thisPlayerLeftData.playerId = tmpPlayerData->GetUniqueId(); static_cast(thisPlayerLeft.get())->SetData(thisPlayerLeftData); - SendToAllPlayers(thisPlayerLeft); + m_sessionManager.SendToAllSessions(GetSender(), thisPlayerLeft); GetCallback().SignalNetServerPlayerLeft(tmpPlayerData->GetName()); } @@ -428,166 +327,7 @@ ServerRecvThread::CloseSessionDelayed(SessionWrapper session) } void -ServerRecvThread::RemoveNotEstablishedSessions() -{ - SessionList removeList; - - SocketSessionMap::iterator session_i = m_sessionMap.begin(); - SocketSessionMap::iterator session_end = m_sessionMap.end(); - - while (session_i != session_end) - { - // Remove all players which are not fully connected. - assert(session_i->second.sessionData.get()); - if (session_i->second.sessionData->GetState() != SessionData::Established) - { - // Do not mess with the map within this loop. - // Just store what needs to be removed. - removeList.push_back(session_i->second); - } - ++session_i; - } - - SessionList::iterator remove_i = removeList.begin(); - SessionList::iterator remove_end = removeList.end(); - - while (remove_i != remove_end) - { - // Inform the players that we are starting without them. - // Gracefully remove them from the server. - SessionError(*remove_i, ERR_NET_GAME_ALREADY_RUNNING); - ++remove_i; - } -} - -void -ServerRecvThread::RemoveDisconnectedPlayers() -{ - // This should only be called between hands. - if (m_game.get()) - { - for (int i = 0; i < m_game->getStartQuantityPlayers(); i++) - { - boost::shared_ptr tmpPlayer = m_game->getPlayerArray()[i]; - if (!IsPlayerConnected(tmpPlayer->getMyUniqueID()) && tmpPlayer->getMyType() == PLAYER_TYPE_HUMAN) - { - tmpPlayer->setMyCash(0); - tmpPlayer->setMyActiveStatus(false); - tmpPlayer->setNetSessionData(boost::shared_ptr()); - } - } - } -} - -void -ServerRecvThread::AddComputerPlayer(boost::shared_ptr player) -{ - m_computerPlayers.push_back(player); -} - -void -ServerRecvThread::ResetComputerPlayerList() -{ - m_computerPlayers.clear(); -} - -size_t -ServerRecvThread::GetCurNumberOfPlayers() const -{ - PlayerDataList playerList = GetPlayerDataList(); - return playerList.size(); -} - -bool -ServerRecvThread::IsPlayerConnected(const string &playerName) const -{ - bool retVal = false; - - SessionWrapper tmpSession = GetSessionByPlayerName(playerName); - - if (tmpSession.sessionData.get() && tmpSession.playerData.get()) - retVal = true; - - return retVal; -} - -bool -ServerRecvThread::IsPlayerConnected(unsigned uniquePlayerId) const -{ - bool retVal = false; - - SessionWrapper tmpSession = GetSessionByUniquePlayerId(uniquePlayerId); - - if (tmpSession.sessionData.get() && tmpSession.playerData.get()) - retVal = true; - - return retVal; -} - -void -ServerRecvThread::SetSessionPlayerData(boost::shared_ptr sessionData, boost::shared_ptr playerData) -{ - assert(playerData.get()); - assert(!playerData->GetName().empty()); - assert(sessionData.get()); - - boost::mutex::scoped_lock lock(m_sessionMapMutex); - - SocketSessionMap::iterator pos = m_sessionMap.find(sessionData->GetSocket()); - if (pos != m_sessionMap.end()) - { - pos->second.playerData = playerData; - - // Signal joining player to GUI. - GetCallback().SignalNetServerPlayerJoined(playerData->GetName()); - } -} - -PlayerDataList -ServerRecvThread::GetPlayerDataList() const -{ - PlayerDataList playerList; - boost::mutex::scoped_lock lock(m_sessionMapMutex); - - SocketSessionMap::const_iterator session_i = m_sessionMap.begin(); - SocketSessionMap::const_iterator session_end = m_sessionMap.end(); - - while (session_i != session_end) - { - // Get all players which are fully connected. - if (session_i->second.sessionData->GetState() == SessionData::Established) - { - boost::shared_ptr tmpPlayer(session_i->second.playerData); - assert(tmpPlayer.get()); - assert(!tmpPlayer->GetName().empty()); - playerList.push_back(tmpPlayer); - } - ++session_i; - } - if (!m_computerPlayers.empty()) - playerList.insert(playerList.end(), m_computerPlayers.begin(), m_computerPlayers.end()); - return playerList; -} - -void -ServerRecvThread::AssignPlayerNumbers() -{ - int playerNumber = 0; - - PlayerDataList playerList = GetPlayerDataList(); - PlayerDataList::iterator player_i = playerList.begin(); - PlayerDataList::iterator player_end = playerList.end(); - - while (player_i != player_end) - { - (*player_i)->SetNumber(playerNumber); - ++playerNumber; - ++player_i; - } -} - -void -ServerRecvThread::SendError(SOCKET s, int errorCode) +ServerLobbyThread::SendError(SOCKET s, int errorCode) { boost::shared_ptr packet(new NetPacketError); NetPacketError::Data errorData; @@ -596,119 +336,54 @@ ServerRecvThread::SendError(SOCKET s, int errorCode) GetSender().Send(s, packet); } -void -ServerRecvThread::SendToAllPlayers(boost::shared_ptr packet) +bool +ServerLobbyThread::IsPlayerConnected(const string &playerName) const { - // This function needs to be thread safe. - boost::mutex::scoped_lock lock(m_sessionMapMutex); + bool retVal = false; - SocketSessionMap::iterator i = m_sessionMap.begin(); - SocketSessionMap::iterator end = m_sessionMap.end(); + SessionWrapper tmpSession = m_sessionManager.GetSessionByPlayerName(playerName); - while (i != end) - { - assert(i->second.sessionData.get()); + if (tmpSession.sessionData.get() && tmpSession.playerData.get()) + retVal = true; - // Send each fully connected client a copy of the packet. - if (i->second.sessionData->GetState() == SessionData::Established) - GetSender().Send(i->first, boost::shared_ptr(packet->Clone())); - ++i; - } -} - -void -ServerRecvThread::SendToAllButOnePlayers(boost::shared_ptr packet, SOCKET except) -{ - // This function needs to be thread safe. - boost::mutex::scoped_lock lock(m_sessionMapMutex); - - SocketSessionMap::iterator i = m_sessionMap.begin(); - SocketSessionMap::iterator end = m_sessionMap.end(); - - while (i != end) - { - // Send each fully connected client but one a copy of the packet. - if (i->second.sessionData->GetState() == SessionData::Established) - if (i->first != except) - GetSender().Send(i->first, boost::shared_ptr(packet->Clone())); - ++i; - } + return retVal; } ServerCallback & -ServerRecvThread::GetCallback() +ServerLobbyThread::GetCallback() { return m_gui; } -ServerRecvState & -ServerRecvThread::GetState() -{ - assert(m_curState); - return *m_curState; -} - -void -ServerRecvThread::SetState(ServerRecvState &newState) -{ - newState.Init(); - m_curState = &newState; -} - SenderThread & -ServerRecvThread::GetSender() +ServerLobbyThread::GetSender() { assert(m_sender.get()); return *m_sender; } ReceiverHelper & -ServerRecvThread::GetReceiver() +ServerLobbyThread::GetReceiver() { assert(m_receiver.get()); return *m_receiver; } -Game & -ServerRecvThread::GetGame() -{ - assert(m_game.get()); - return *m_game; -} - -const GameData & -ServerRecvThread::GetGameData() const -{ - return m_gameData; -} - -const StartData & -ServerRecvThread::GetStartData() const -{ - return m_startData; -} - -void -ServerRecvThread::SetStartData(const StartData &startData) -{ - m_startData = startData; -} - bool -ServerRecvThread::CheckPassword(const string &password) const +ServerLobbyThread::CheckPassword(const string &password) const { return (password == m_password); } ServerSenderCallback & -ServerRecvThread::GetSenderCallback() +ServerLobbyThread::GetSenderCallback() { assert(m_senderCallback.get()); return *m_senderCallback; } GuiInterface & -ServerRecvThread::GetGui() +ServerLobbyThread::GetGui() { return m_gui; } diff --git a/src/net/common/sessionmanager.cpp b/src/net/common/sessionmanager.cpp new file mode 100644 index 00000000..082bfdcf --- /dev/null +++ b/src/net/common/sessionmanager.cpp @@ -0,0 +1,237 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include +#include +#include + +using namespace std; + + +SessionManager::SessionManager() +{ +} + +SessionManager::~SessionManager() +{ + Clear(); +} + +void +SessionManager::AddSession(boost::shared_ptr sessionData) +{ + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + SessionMap::iterator pos = m_sessionMap.lower_bound(sessionData->GetSocket()); + + // If pos points to a pair whose key is equivalent to the socket, this handle + // already exists within the list. + if (pos != m_sessionMap.end() && sessionData->GetSocket() == pos->first) + { + throw ServerException(ERR_SOCK_CONN_EXISTS, 0); + } + m_sessionMap.insert(pos, SessionMap::value_type(sessionData->GetSocket(), SessionWrapper(sessionData, boost::shared_ptr()))); +} + +void +SessionManager::SetSessionPlayerData(SOCKET session, boost::shared_ptr playerData) +{ + boost::mutex::scoped_lock lock(m_sessionMapMutex); + SessionMap::iterator pos = m_sessionMap.find(session); + + if (pos != m_sessionMap.end()) + pos->second.playerData = playerData; +} + +void +SessionManager::RemoveSession(SOCKET session) +{ + boost::mutex::scoped_lock lock(m_sessionMapMutex); + m_sessionMap.erase(session); +} + +SessionWrapper +SessionManager::Select(unsigned timeoutMsec) +{ + SessionWrapper retSession; + SOCKET maxSock = INVALID_SOCKET; + fd_set rdset; + FD_ZERO(&rdset); + + { + boost::mutex::scoped_lock lock(m_sessionMapMutex); + SessionMap::iterator i = m_sessionMap.begin(); + SessionMap::iterator end = m_sessionMap.end(); + + while (i != end) + { + SOCKET tmpSock = i->first; + FD_SET(tmpSock, &rdset); + if (tmpSock > maxSock || maxSock == INVALID_SOCKET) + maxSock = tmpSock; + ++i; + } + } + + if (maxSock == INVALID_SOCKET) + { + Thread::Msleep(timeoutMsec); // just sleep if there is no session + } + else + { + // wait for data + struct timeval timeout; + timeout.tv_sec = timeoutMsec / 1000; + timeout.tv_usec = (timeoutMsec % 1000) * 1000; + int selectResult = select(maxSock + 1, &rdset, NULL, NULL, &timeout); + if (!IS_VALID_SELECT(selectResult)) + { + throw ServerException(ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO()); + } + if (selectResult > 0) // one (or more) of the sockets is readable + { + // Check which socket is readable, return the first. + boost::mutex::scoped_lock lock(m_sessionMapMutex); + SessionMap::iterator i = m_sessionMap.begin(); + SessionMap::iterator end = m_sessionMap.end(); + + while (i != end) + { + if (FD_ISSET(i->first, &rdset)) + { + retSession = i->second; + break; + } + ++i; + } + } + } + return retSession; +} + +SessionWrapper +SessionManager::GetSessionByPlayerName(const string playerName) const +{ + SessionWrapper tmpSession; + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + SessionMap::const_iterator session_i = m_sessionMap.begin(); + SessionMap::const_iterator session_end = m_sessionMap.end(); + + while (session_i != session_end) + { + // Check all players which are fully connected. + if (session_i->second.sessionData->GetState() == SessionData::Established) + { + boost::shared_ptr tmpPlayer(session_i->second.playerData); + assert(tmpPlayer.get()); + if (tmpPlayer->GetName() == playerName) + { + tmpSession = session_i->second; + break; + } + } + + ++session_i; + } + return tmpSession; +} + +SessionWrapper +SessionManager::GetSessionByUniquePlayerId(unsigned uniqueId) const +{ + SessionWrapper tmpSession; + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + SessionMap::const_iterator session_i = m_sessionMap.begin(); + SessionMap::const_iterator session_end = m_sessionMap.end(); + + while (session_i != session_end) + { + // Check all players which are fully connected. + if (session_i->second.sessionData->GetState() == SessionData::Established) + { + boost::shared_ptr tmpPlayer(session_i->second.playerData); + assert(tmpPlayer.get()); + if (tmpPlayer->GetUniqueId() == uniqueId) + { + tmpSession = session_i->second; + break; + } + } + + ++session_i; + } + return tmpSession; +} + +void +SessionManager::Clear() +{ + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + // Sockets will be closed automatically. + m_sessionMap.clear(); +} + +unsigned +SessionManager::GetRawSessionCount() +{ + boost::mutex::scoped_lock lock(m_sessionMapMutex); + return m_sessionMap.size(); +} + +void +SessionManager::SendToAllSessions(SenderThread &sender, boost::shared_ptr packet) +{ + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + SessionMap::iterator i = m_sessionMap.begin(); + SessionMap::iterator end = m_sessionMap.end(); + + while (i != end) + { + assert(i->second.sessionData.get()); + + // Send each fully connected client a copy of the packet. + if (i->second.sessionData->GetState() == SessionData::Established) + sender.Send(i->first, boost::shared_ptr(packet->Clone())); + ++i; + } +} + +void +SessionManager::SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr packet, SOCKET except) +{ + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + SessionMap::iterator i = m_sessionMap.begin(); + SessionMap::iterator end = m_sessionMap.end(); + + while (i != end) + { + // Send each fully connected client but one a copy of the packet. + if (i->second.sessionData->GetState() == SessionData::Established) + if (i->first != except) + sender.Send(i->first, boost::shared_ptr(packet->Clone())); + ++i; + } +} + diff --git a/src/net/netpacket.h b/src/net/netpacket.h index d0d4340e..647d65c3 100644 --- a/src/net/netpacket.h +++ b/src/net/netpacket.h @@ -40,6 +40,12 @@ struct NetPacketHeader; +class NetPacketInit; +class NetPacketInitAck; +class NetPacketGameListNew; +class NetPacketGameListUpdate; +class NetPacketCreateGame; +class NetPacketCreateGameAck; class NetPacketJoinGame; class NetPacketJoinGameAck; class NetPacketPlayerJoined; @@ -80,6 +86,12 @@ public: u_int16_t GetType() const; u_int16_t GetLen() const; + virtual const NetPacketInit *ToNetPacketInit() const; + virtual const NetPacketInitAck *ToNetPacketInitAck() const; + virtual const NetPacketGameListNew *ToNetPacketGameListNew() const; + virtual const NetPacketGameListUpdate *ToNetPacketGameListUpdate() const; + virtual const NetPacketCreateGame *ToNetPacketCreateGame() const; + virtual const NetPacketCreateGameAck *ToNetPacketCreateGameAck() const; virtual const NetPacketJoinGame *ToNetPacketJoinGame() const; virtual const NetPacketJoinGameAck *ToNetPacketJoinGameAck() const; virtual const NetPacketPlayerJoined *ToNetPacketPlayerJoined() const; @@ -117,7 +129,7 @@ private: const u_int16_t m_maxSize; }; -class NetPacketJoinGame : public NetPacket +class NetPacketInit : public NetPacket { public: struct Data @@ -128,6 +140,151 @@ public: std::string password; }; + NetPacketInit(); + virtual ~NetPacketInit(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketInit *ToNetPacketInit() const; + +protected: + + virtual void InternalCheck(const NetPacketHeader* data) const; +}; + +class NetPacketInitAck : public NetPacket +{ +public: + struct Data + { + u_int32_t sessionId; + u_int32_t playerId; + }; + + NetPacketInitAck(); + virtual ~NetPacketInitAck(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketInitAck *ToNetPacketInitAck() const; + +protected: + + virtual void InternalCheck(const NetPacketHeader* data) const; +}; + +class NetPacketGameListNew : public NetPacket +{ +public: + struct Data + { + u_int32_t gameId; + GameMode gameMode; + std::string gameName; + }; + + NetPacketGameListNew(); + virtual ~NetPacketGameListNew(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketGameListNew *ToNetPacketGameListNew() const; + +protected: + + virtual void InternalCheck(const NetPacketHeader* data) const; +}; + +class NetPacketGameListUpdate : public NetPacket +{ +public: + struct Data + { + u_int32_t gameId; + GameMode gameMode; + }; + + NetPacketGameListUpdate(); + virtual ~NetPacketGameListUpdate(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketGameListUpdate *ToNetPacketGameListUpdate() const; + +protected: + + virtual void InternalCheck(const NetPacketHeader* data) const; +}; + +class NetPacketCreateGame : public NetPacket +{ +public: + struct Data + { + std::string gameName; + std::string password; + GameData gameData; + }; + + NetPacketCreateGame(); + virtual ~NetPacketCreateGame(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketCreateGame *ToNetPacketCreateGame() const; + +protected: + + virtual void InternalCheck(const NetPacketHeader* data) const; +}; + +class NetPacketCreateGameAck : public NetPacket +{ +public: + struct Data + { + u_int32_t gameId; + }; + + NetPacketCreateGameAck(); + virtual ~NetPacketCreateGameAck(); + + virtual boost::shared_ptr Clone() const; + + void SetData(const Data &inData); + void GetData(Data &outData) const; + + virtual const NetPacketCreateGameAck *ToNetPacketCreateGameAck() const; + +protected: + + virtual void InternalCheck(const NetPacketHeader* data) const; +}; + +class NetPacketJoinGame : public NetPacket +{ +public: + struct Data + { + u_int32_t gameId; + std::string password; + }; + NetPacketJoinGame(); virtual ~NetPacketJoinGame(); @@ -148,10 +305,6 @@ class NetPacketJoinGameAck : public NetPacket public: struct Data { - u_int32_t sessionId; - u_int16_t yourPlayerUniqueId; - PlayerType ptype; - PlayerRights prights; GameData gameData; }; @@ -175,7 +328,7 @@ class NetPacketPlayerJoined : public NetPacket public: struct Data { - u_int16_t playerId; + u_int32_t playerId; PlayerType ptype; PlayerRights prights; std::string playerName; @@ -201,7 +354,7 @@ class NetPacketPlayerLeft : public NetPacket public: struct Data { - u_int16_t playerId; + u_int32_t playerId; }; NetPacketPlayerLeft(); @@ -224,7 +377,7 @@ class NetPacketKickPlayer : public NetPacket public: struct Data { - u_int16_t playerId; + u_int32_t playerId; }; NetPacketKickPlayer(); @@ -264,7 +417,7 @@ public: struct PlayerSlot { - unsigned playerId; + u_int32_t playerId; }; typedef std::list PlayerSlotList; @@ -319,7 +472,7 @@ public: struct Data { GameState gameState; - u_int16_t playerId; + u_int32_t playerId; }; NetPacketPlayersTurn(); @@ -368,7 +521,7 @@ public: struct Data { GameState gameState; - u_int16_t playerId; + u_int32_t playerId; PlayerAction playerAction; u_int32_t totalPlayerBet; u_int32_t playerMoney; @@ -490,7 +643,7 @@ class NetPacketAllInShowCards : public NetPacket public: struct PlayerCards { - u_int16_t playerId; + u_int32_t playerId; u_int16_t cards[2]; }; @@ -521,7 +674,7 @@ class NetPacketEndOfHandShowCards : public NetPacket public: struct PlayerResult { - u_int16_t playerId; + u_int32_t playerId; u_int16_t cards[2]; u_int16_t bestHandPos[5]; u_int32_t valueOfCards; @@ -556,7 +709,7 @@ class NetPacketEndOfHandHideCards : public NetPacket public: struct Data { - u_int16_t playerId; + u_int32_t playerId; u_int32_t moneyWon; u_int32_t playerMoney; }; @@ -581,7 +734,7 @@ class NetPacketEndOfGame : public NetPacket public: struct Data { - u_int16_t winnerPlayerId; + u_int32_t winnerPlayerId; }; NetPacketEndOfGame(); @@ -627,7 +780,7 @@ class NetPacketChatText : public NetPacket public: struct Data { - u_int16_t playerId; + u_int32_t playerId; std::string text; }; diff --git a/src/net/serverrecvstate.h b/src/net/serverrecvstate.h index cc4dda80..3e13dfee 100644 --- a/src/net/serverrecvstate.h +++ b/src/net/serverrecvstate.h @@ -124,7 +124,7 @@ protected: private: - u_int16_t m_curUniquePlayerId; + u_int32_t m_curUniquePlayerId; static boost::thread_specific_ptr Ptr; }; diff --git a/src/net/serverrecvthread.h b/src/net/serverrecvthread.h index f093381d..9f15af17 100644 --- a/src/net/serverrecvthread.h +++ b/src/net/serverrecvthread.h @@ -21,119 +21,70 @@ #ifndef _SERVERRECVTHREAD_H_ #define _SERVERRECVTHREAD_H_ -#include #include -#include +#include +#include #include #include #include -#include #include -#include -#include #include #define RECEIVER_THREAD_TERMINATE_TIMEOUT 200 -class ServerRecvState; class SenderThread; class ReceiverHelper; class ServerSenderCallback; -class NetPacket; class ConfigFile; struct GameData; class Game; -struct SessionWrapper -{ - SessionWrapper() {} - SessionWrapper(boost::shared_ptr s, boost::shared_ptr p) - : sessionData(s), playerData(p) {} - boost::shared_ptr sessionData; - boost::shared_ptr playerData; -}; - -class ServerRecvThread : public Thread +class ServerLobbyThread : public Thread { public: - ServerRecvThread(GuiInterface &gui, ConfigFile *playerConfig); - virtual ~ServerRecvThread(); + ServerLobbyThread(GuiInterface &gui, ConfigFile *playerConfig); + virtual ~ServerLobbyThread(); - void Init(const std::string &pwd, const GameData &gameData); + void Init(const std::string &pwd); void AddConnection(boost::shared_ptr data); - void AddNotification(unsigned message, const std::string ¶m); + u_int32_t GetNextUniquePlayerId(); ServerCallback &GetCallback(); - void SendError(SOCKET s, int errorCode); - void SendToAllPlayers(boost::shared_ptr packet); - void SendToAllButOnePlayers(boost::shared_ptr packet, SOCKET except); - - Game &GetGame(); - protected: - struct Notification - { - Notification(unsigned m, std::string p) - : message(m), param(p) {} - unsigned message; - std::string param; - }; - typedef std::deque > ConnectQueue; - typedef std::map SocketSessionMap; typedef std::list SessionList; - typedef std::deque NotificationQueue; typedef std::list > > CloseSessionList; // Main function of the thread. virtual void Main(); - void NotificationLoop(); + void ProcessLoop(); + void HandleNetPacketInit(SessionWrapper session, const NetPacketInit &tmpPacket); + void HandleNetPacketCreateGame(SessionWrapper session, const NetPacketCreateGame &tmpPacket); + void HandleNetPacketJoinGame(SessionWrapper session, const NetPacketJoinGame &tmpPacket); void CloseSessionLoop(); + void HandleNewConnection(boost::shared_ptr connData); + SOCKET Select(); void CleanupConnectQueue(); void CleanupSessionMap(); - void InternalStartGame(); - void InternalKickPlayer(unsigned uniqueId); - - SessionWrapper GetSession(SOCKET sock) const; - SessionWrapper GetSessionByPlayerName(const std::string playerName) const; - SessionWrapper GetSessionByUniquePlayerId(unsigned uniqueId) const; - void AddSession(boost::shared_ptr sessionData); // new Sessions have no player data void SessionError(SessionWrapper session, int errorCode); - void RejectNewConnection(boost::shared_ptr connData); void CloseSessionDelayed(SessionWrapper session); - void RemoveNotEstablishedSessions(); - void RemoveDisconnectedPlayers(); + void SendError(SOCKET s, int errorCode); - void AddComputerPlayer(boost::shared_ptr player); - void ResetComputerPlayerList(); - - size_t GetCurNumberOfPlayers() const; bool IsPlayerConnected(const std::string &playerName) const; - bool IsPlayerConnected(unsigned uniquePlayerId) const; - void SetSessionPlayerData(boost::shared_ptr sessionData, boost::shared_ptr playerData); - PlayerDataList GetPlayerDataList() const; - - void AssignPlayerNumbers(); - - ServerRecvState &GetState(); - void SetState(ServerRecvState &newState); SenderThread &GetSender(); ReceiverHelper &GetReceiver(); - const GameData &GetGameData() const; - const StartData &GetStartData() const; - void SetStartData(const StartData &startData); bool CheckPassword(const std::string &password) const; ServerSenderCallback &GetSenderCallback(); @@ -143,45 +94,19 @@ private: ConnectQueue m_connectQueue; mutable boost::mutex m_connectQueueMutex; - ServerRecvState *m_curState; - NotificationQueue m_notificationQueue; - mutable boost::mutex m_notificationQueueMutex; - - SocketSessionMap m_sessionMap; - mutable boost::mutex m_sessionMapMutex; - - PlayerDataList m_computerPlayers; + SessionManager m_sessionManager; CloseSessionList m_closeSessionList; std::auto_ptr m_receiver; std::auto_ptr m_sender; - - std::auto_ptr m_game; - GameData m_gameData; - StartData m_startData; - unsigned m_curGameId; std::auto_ptr m_senderCallback; - - std::string m_password; - GuiInterface &m_gui; + std::string m_password; ConfigFile *m_playerConfig; - -friend class ServerRecvStateInit; -friend class AbstractServerRecvStateReceiving; -friend class AbstractServerRecvStateRunning; -friend class ServerRecvStateStartGame; -friend class ServerRecvStateStartHand; -friend class ServerRecvStateStartRound; -friend class ServerRecvStateWaitPlayerAction; -friend class ServerRecvStateComputerAction; -friend class ServerRecvStateShowCardsDelay; -friend class ServerRecvStateDealCardsDelay; -friend class ServerRecvStateNextHandDelay; -friend class ServerRecvStateNextGameDelay; + u_int32_t m_curUniquePlayerId; }; #endif diff --git a/src/net/sessiondata.h b/src/net/sessiondata.h index 83f26d08..c2b99a21 100644 --- a/src/net/sessiondata.h +++ b/src/net/sessiondata.h @@ -21,7 +21,6 @@ #ifndef _SESSIONDATA_H_ #define _SESSIONDATA_H_ -#include #include #include diff --git a/src/net/sessionmanager.h b/src/net/sessionmanager.h new file mode 100644 index 00000000..41230b8b --- /dev/null +++ b/src/net/sessionmanager.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* Thread safe server session manager. */ + +#ifndef _SESSIONMANAGER_H_ +#define _SESSIONMANAGER_H_ + +#include +#include +#include + +#include +#include + +class SenderThread; +class NetPacket; + +struct SessionWrapper +{ + SessionWrapper() {} + SessionWrapper(boost::shared_ptr s, boost::shared_ptr p) + : sessionData(s), playerData(p) {} + boost::shared_ptr sessionData; + boost::shared_ptr playerData; +}; + +class SessionManager +{ +public: + SessionManager(); + virtual ~SessionManager(); + + void AddSession(boost::shared_ptr sessionData); // new Sessions have no player data + void SetSessionPlayerData(SOCKET session, boost::shared_ptr playerData); + void RemoveSession(SOCKET session); + + SessionWrapper Select(unsigned timeoutMsec); + SessionWrapper GetSessionByPlayerName(const std::string playerName) const; + SessionWrapper GetSessionByUniquePlayerId(unsigned uniqueId) const; + + void Clear(); + unsigned GetRawSessionCount(); + + void SendToAllSessions(SenderThread &sender, boost::shared_ptr packet); + void SendToAllButOneSessions(SenderThread &sender, boost::shared_ptr packet, SOCKET except); + +protected: + + typedef std::map SessionMap; + +private: + + SessionMap m_sessionMap; + mutable boost::mutex m_sessionMapMutex; +}; + +#endif diff --git a/src/net/socket_msg.h b/src/net/socket_msg.h index b2f9cba9..f8df2ff1 100644 --- a/src/net/socket_msg.h +++ b/src/net/socket_msg.h @@ -51,12 +51,13 @@ #define ERR_NET_INVALID_PLAYER_NAME 107 #define ERR_NET_INVALID_PLAYER_CARDS 108 #define ERR_NET_INVALID_PLAYER_RESULTS 109 -#define ERR_NET_INVALID_CHAT_TEXT 110 -#define ERR_NET_UNKNOWN_PLAYER_ID 111 -#define ERR_NET_INVALID_ROUND 112 -#define ERR_NET_PLAYER_KICKED 113 -#define ERR_NET_INVALID_PLAYER_COUNT 114 -#define ERR_NET_PLAYER_NOT_IN_GAME 115 +#define ERR_NET_INVALID_GAME_NAME 110 +#define ERR_NET_INVALID_CHAT_TEXT 111 +#define ERR_NET_UNKNOWN_PLAYER_ID 112 +#define ERR_NET_INVALID_ROUND 113 +#define ERR_NET_PLAYER_KICKED 114 +#define ERR_NET_INVALID_PLAYER_COUNT 115 +#define ERR_NET_PLAYER_NOT_IN_GAME 116 // This is an internal message which is not reported. #define MSG_SOCK_INTERNAL_PENDING 0