1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
4 // Copyright(C) 2005 Simon Howard
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 // Network server code
37 #include "net_client.h"
38 #include "net_common.h"
42 #include "net_packet.h"
43 #include "net_server.h"
45 #include "net_structrw.h"
49 // waiting for the game to start
63 net_connection_t connection
;
67 // Last time new gamedata was received from this client
69 int last_gamedata_time
;
71 // recording a demo without -longtics
73 boolean recording_lowres
;
75 // send queue: items to send to the client
76 // this is a circular buffer
79 net_full_ticcmd_t sendqueue
[BACKUPTICS
];
81 // Latest acknowledged by the client
83 unsigned int acknowledged
;
85 // Observer: receives data but does not participate in the game.
89 // MD5 hash sums of the client's WAD directory and dehacked data
91 md5_digest_t wad_md5sum
;
92 md5_digest_t deh_md5sum
;
94 // Is this client is playing with the Freedoom IWAD?
96 unsigned int is_freedoom
;
100 // structure used for the recv window
104 // Whether this tic has been received yet
108 // Latency value received from the client
112 // Last time we sent a resend request for this tic
114 unsigned int resend_time
;
121 static net_server_state_t server_state
;
122 static boolean server_initialized
= false;
123 static net_client_t clients
[MAXNETNODES
];
124 static net_client_t
*sv_players
[MAXPLAYERS
];
125 static net_context_t
*server_context
;
126 static unsigned int sv_gamemode
;
127 static unsigned int sv_gamemission
;
128 static net_gamesettings_t sv_settings
;
132 static unsigned int recvwindow_start
;
133 static net_client_recv_t recvwindow
[BACKUPTICS
][MAXPLAYERS
];
135 #define NET_SV_ExpandTicNum(b) NET_ExpandTicNum(recvwindow_start, (b))
137 static void NET_SV_DisconnectClient(net_client_t
*client
)
141 NET_Conn_Disconnect(&client
->connection
);
145 static boolean
ClientConnected(net_client_t
*client
)
147 // Check that the client is properly connected: ie. not in the
148 // process of connecting or disconnecting
150 return client
->active
151 && client
->connection
.state
== NET_CONN_STATE_CONNECTED
;
154 // Send a message to be displayed on a client's console
156 static void NET_SV_SendConsoleMessage(net_client_t
*client
, char *s
, ...)
160 net_packet_t
*packet
;
163 vsnprintf(buf
, sizeof(buf
), s
, args
);
166 packet
= NET_Conn_NewReliable(&client
->connection
,
167 NET_PACKET_TYPE_CONSOLE_MESSAGE
);
169 NET_WriteString(packet
, buf
);
172 // Send a message to all clients
174 static void NET_SV_BroadcastMessage(char *s
, ...)
181 vsnprintf(buf
, sizeof(buf
), s
, args
);
184 for (i
=0; i
<MAXNETNODES
; ++i
)
186 if (ClientConnected(&clients
[i
]))
188 NET_SV_SendConsoleMessage(&clients
[i
], buf
);
196 // Assign player numbers to connected clients
198 static void NET_SV_AssignPlayers(void)
205 for (i
=0; i
<MAXNETNODES
; ++i
)
207 if (ClientConnected(&clients
[i
]))
209 if (!clients
[i
].drone
)
211 sv_players
[pl
] = &clients
[i
];
212 sv_players
[pl
]->player_number
= pl
;
217 clients
[i
].player_number
= -1;
222 for (; pl
<MAXPLAYERS
; ++pl
)
224 sv_players
[pl
] = NULL
;
228 // Returns the number of players currently connected.
230 static int NET_SV_NumPlayers(void)
237 for (i
=0; i
<MAXPLAYERS
; ++i
)
239 if (sv_players
[i
] != NULL
&& ClientConnected(sv_players
[i
]))
248 // Returns the number of drones currently connected.
250 static int NET_SV_NumDrones(void)
257 for (i
=0; i
<MAXNETNODES
; ++i
)
259 if (ClientConnected(&clients
[i
]) && clients
[i
].drone
)
268 // returns the number of clients connected
270 static int NET_SV_NumClients(void)
277 for (i
=0; i
<MAXNETNODES
; ++i
)
279 if (ClientConnected(&clients
[i
]))
288 // Find the latest tic which has been acknowledged as received by
291 static unsigned int NET_SV_LatestAcknowledged(void)
293 unsigned int lowtic
= UINT_MAX
;
296 for (i
=0; i
<MAXNETNODES
; ++i
)
298 if (ClientConnected(&clients
[i
]))
300 if (clients
[i
].acknowledged
< lowtic
)
302 lowtic
= clients
[i
].acknowledged
;
311 // Possibly advance the recv window if all connected clients have
312 // used the data in the window
314 static void NET_SV_AdvanceWindow(void)
319 if (NET_SV_NumPlayers() <= 0)
324 lowtic
= NET_SV_LatestAcknowledged();
326 // Advance the recv window until it catches up with lowtic
328 while (recvwindow_start
< lowtic
)
330 boolean should_advance
;
332 // Check we have tics from all players for first tic in
335 should_advance
= true;
337 for (i
=0; i
<MAXPLAYERS
; ++i
)
339 if (sv_players
[i
] == NULL
|| !ClientConnected(sv_players
[i
]))
344 if (!recvwindow
[0][i
].active
)
346 should_advance
= false;
353 // The first tic is not complete: ie. we have not
354 // received tics from all connected players. This can
355 // happen if only one player is in the game.
360 // Advance the window
362 memcpy(recvwindow
, recvwindow
+ 1, sizeof(*recvwindow
) * (BACKUPTICS
- 1));
363 memset(&recvwindow
[BACKUPTICS
-1], 0, sizeof(*recvwindow
));
366 //printf("SV: advanced to %i\n", recvwindow_start);
370 // returns a pointer to the client which controls the server
372 static net_client_t
*NET_SV_Controller(void)
376 // first client in the list is the controller
378 for (i
=0; i
<MAXNETNODES
; ++i
)
380 if (ClientConnected(&clients
[i
]) && !clients
[i
].drone
)
389 // Given an address, find the corresponding client
391 static net_client_t
*NET_SV_FindClient(net_addr_t
*addr
)
395 for (i
=0; i
<MAXNETNODES
; ++i
)
397 if (clients
[i
].active
&& clients
[i
].addr
== addr
)
408 // send a rejection packet to a client
410 static void NET_SV_SendReject(net_addr_t
*addr
, char *msg
)
412 net_packet_t
*packet
;
414 packet
= NET_NewPacket(10);
415 NET_WriteInt16(packet
, NET_PACKET_TYPE_REJECTED
);
416 NET_WriteString(packet
, msg
);
417 NET_SendPacket(addr
, packet
);
418 NET_FreePacket(packet
);
421 static void NET_SV_InitNewClient(net_client_t
*client
,
425 client
->active
= true;
426 NET_Conn_InitServer(&client
->connection
, addr
);
428 client
->last_send_time
= -1;
429 client
->name
= strdup(player_name
);
431 // init the ticcmd send queue
434 client
->acknowledged
= 0;
435 client
->drone
= false;
437 client
->last_gamedata_time
= 0;
439 memset(client
->sendqueue
, 0xff, sizeof(client
->sendqueue
));
442 // parse a SYN from a client(initiating a connection)
444 static void NET_SV_ParseSYN(net_packet_t
*packet
,
445 net_client_t
*client
,
449 unsigned int cl_gamemode
, cl_gamemission
;
450 unsigned int cl_recording_lowres
;
451 unsigned int cl_drone
;
452 unsigned int is_freedoom
;
453 md5_digest_t deh_md5sum
, wad_md5sum
;
455 char *client_version
;
458 // read the magic number
460 if (!NET_ReadInt32(packet
, &magic
))
465 if (magic
!= NET_MAGIC_NUMBER
)
467 // invalid magic number
472 // Check the client version is the same as the server
474 client_version
= NET_ReadString(packet
);
476 if (client_version
== NULL
)
481 if (strcmp(client_version
, PACKAGE_STRING
) != 0)
486 // When running a netgame server, ignore version mismatches between
487 // the server and the client. Using this option may cause game
488 // desyncs to occur, or differences in protocol may mean the netgame
489 // will simply not function at all.
492 if (M_CheckParm("-ignoreversion") == 0)
494 NET_SV_SendReject(addr
,
495 "Version mismatch: server version is: "
501 // read the game mode and mission
503 if (!NET_ReadInt16(packet
, &cl_gamemode
)
504 || !NET_ReadInt16(packet
, &cl_gamemission
)
505 || !NET_ReadInt8(packet
, &cl_recording_lowres
)
506 || !NET_ReadInt8(packet
, &cl_drone
)
507 || !NET_ReadMD5Sum(packet
, wad_md5sum
)
508 || !NET_ReadMD5Sum(packet
, deh_md5sum
)
509 || !NET_ReadInt8(packet
, &is_freedoom
))
514 if (!NET_ValidGameMode(cl_gamemode
, cl_gamemission
))
519 // read the player's name
521 player_name
= NET_ReadString(packet
);
523 if (player_name
== NULL
)
528 // received a valid SYN
530 // not accepting new connections?
532 if (server_state
!= SERVER_WAITING_START
)
534 NET_SV_SendReject(addr
, "Server is not currently accepting connections");
538 // allocate a client slot if there isn't one already
542 // find a slot, or return if none found
544 for (i
=0; i
<MAXNETNODES
; ++i
)
546 if (!clients
[i
].active
)
548 client
= &clients
[i
];
560 // If this is a recently-disconnected client, deactivate
561 // to allow immediate reconnection
563 if (client
->connection
.state
== NET_CONN_STATE_DISCONNECTED
)
565 client
->active
= false;
575 // Before accepting a new client, check that there is a slot
578 NET_SV_AssignPlayers();
579 num_players
= NET_SV_NumPlayers();
581 if ((!cl_drone
&& num_players
>= MAXPLAYERS
)
582 || NET_SV_NumClients() >= MAXNETNODES
)
584 NET_SV_SendReject(addr
, "Server is full!");
588 // TODO: Add server option to allow rejecting clients which
589 // set lowres_turn. This is potentially desirable as the
590 // presence of such clients affects turning resolution.
592 // Adopt the game mode and mission of the first connecting client
594 if (num_players
== 0 && !cl_drone
)
596 sv_gamemode
= cl_gamemode
;
597 sv_gamemission
= cl_gamemission
;
600 // Save the MD5 checksums
602 memcpy(client
->wad_md5sum
, wad_md5sum
, sizeof(md5_digest_t
));
603 memcpy(client
->deh_md5sum
, deh_md5sum
, sizeof(md5_digest_t
));
604 client
->is_freedoom
= is_freedoom
;
606 // Check the connecting client is playing the same game as all
609 if (cl_gamemode
!= sv_gamemode
|| cl_gamemission
!= sv_gamemission
)
611 NET_SV_SendReject(addr
, "You are playing the wrong game!");
615 // Activate, initialize connection
617 NET_SV_InitNewClient(client
, addr
, player_name
);
619 client
->recording_lowres
= cl_recording_lowres
;
620 client
->drone
= cl_drone
;
623 if (client
->connection
.state
== NET_CONN_STATE_WAITING_ACK
)
625 // force an acknowledgement
626 client
->connection
.last_send_time
= -1;
630 // Parse a game start packet
632 static void NET_SV_ParseGameStart(net_packet_t
*packet
, net_client_t
*client
)
634 net_gamesettings_t settings
;
635 net_packet_t
*startpacket
;
639 if (client
!= NET_SV_Controller())
641 // Only the controller can start a new game
646 if (!NET_ReadSettings(packet
, &settings
))
653 // Check the game settings are valid
655 if (!NET_ValidGameSettings(sv_gamemode
, sv_gamemission
, &settings
))
660 if (server_state
!= SERVER_WAITING_START
)
662 // Can only start a game if we are in the waiting start state.
667 // Assign player numbers
669 NET_SV_AssignPlayers();
671 // Check if anyone is recording a demo and set lowres_turn if so.
673 settings
.lowres_turn
= false;
675 for (i
=0; i
<MAXPLAYERS
; ++i
)
677 if (sv_players
[i
] != NULL
&& sv_players
[i
]->recording_lowres
)
679 settings
.lowres_turn
= true;
683 nowtime
= I_GetTimeMS();
685 // Send start packets to each connected node
687 for (i
=0; i
<MAXNETNODES
; ++i
)
689 if (!ClientConnected(&clients
[i
]))
692 clients
[i
].last_gamedata_time
= nowtime
;
694 startpacket
= NET_Conn_NewReliable(&clients
[i
].connection
,
695 NET_PACKET_TYPE_GAMESTART
);
697 NET_WriteInt8(startpacket
, NET_SV_NumPlayers());
698 NET_WriteInt8(startpacket
, clients
[i
].player_number
);
699 NET_WriteSettings(startpacket
, &settings
);
702 // Change server state
704 server_state
= SERVER_IN_GAME
;
705 sv_settings
= settings
;
707 memset(recvwindow
, 0, sizeof(recvwindow
));
708 recvwindow_start
= 0;
711 // Send a resend request to a client
713 static void NET_SV_SendResendRequest(net_client_t
*client
, int start
, int end
)
715 net_packet_t
*packet
;
716 net_client_recv_t
*recvobj
;
718 unsigned int nowtime
;
721 //printf("SV: send resend for %i-%i\n", start, end);
723 packet
= NET_NewPacket(20);
725 NET_WriteInt16(packet
, NET_PACKET_TYPE_GAMEDATA_RESEND
);
726 NET_WriteInt32(packet
, start
);
727 NET_WriteInt8(packet
, end
- start
+ 1);
729 NET_Conn_SendPacket(&client
->connection
, packet
);
730 NET_FreePacket(packet
);
732 // Store the time we send the resend request
734 nowtime
= I_GetTimeMS();
736 for (i
=start
; i
<=end
; ++i
)
738 index
= i
- recvwindow_start
;
740 if (index
>= BACKUPTICS
)
747 recvobj
= &recvwindow
[index
][client
->player_number
];
749 recvobj
->resend_time
= nowtime
;
753 // Check for expired resend requests
755 static void NET_SV_CheckResends(net_client_t
*client
)
759 int resend_start
, resend_end
;
760 unsigned int nowtime
;
762 nowtime
= I_GetTimeMS();
764 player
= client
->player_number
;
768 for (i
=0; i
<BACKUPTICS
; ++i
)
770 net_client_recv_t
*recvobj
;
773 recvobj
= &recvwindow
[i
][player
];
775 // if need_resend is true, this tic needs another retransmit
776 // request (300ms timeout)
778 need_resend
= !recvobj
->active
779 && recvobj
->resend_time
!= 0
780 && nowtime
> recvobj
->resend_time
+ 300;
784 // Start a new run of resend tics?
786 if (resend_start
< 0)
795 if (resend_start
>= 0)
797 // End of a run of resend tics
799 //printf("SV: resend request timed out: %i-%i\n", resend_start, resend_end);
800 NET_SV_SendResendRequest(client
,
801 recvwindow_start
+ resend_start
,
802 recvwindow_start
+ resend_end
);
809 if (resend_start
>= 0)
811 NET_SV_SendResendRequest(client
,
812 recvwindow_start
+ resend_start
,
813 recvwindow_start
+ resend_end
);
817 // Process game data from a client
819 static void NET_SV_ParseGameData(net_packet_t
*packet
, net_client_t
*client
)
821 net_client_recv_t
*recvobj
;
824 unsigned int num_tics
;
825 unsigned int nowtime
;
828 int resend_start
, resend_end
;
831 if (server_state
!= SERVER_IN_GAME
)
838 // Drones do not contribute any game data.
842 player
= client
->player_number
;
846 if (!NET_ReadInt8(packet
, &ackseq
)
847 || !NET_ReadInt8(packet
, &seq
)
848 || !NET_ReadInt8(packet
, &num_tics
))
853 // Get the current time
855 nowtime
= I_GetTimeMS();
857 // Expand 8-bit values to the full sequence number
859 ackseq
= NET_SV_ExpandTicNum(ackseq
);
860 seq
= NET_SV_ExpandTicNum(seq
);
864 for (i
=0; i
<num_tics
; ++i
)
869 if (!NET_ReadSInt16(packet
, &latency
)
870 || !NET_ReadTiccmdDiff(packet
, &diff
, sv_settings
.lowres_turn
))
875 index
= seq
+ i
- recvwindow_start
;
877 if (index
< 0 || index
>= BACKUPTICS
)
879 // Not in range of the recv window
884 recvobj
= &recvwindow
[index
][player
];
885 recvobj
->active
= true;
886 recvobj
->diff
= diff
;
887 recvobj
->latency
= latency
;
889 client
->last_gamedata_time
= nowtime
;
892 // Higher acknowledgement point?
894 if (ackseq
> client
->acknowledged
)
896 client
->acknowledged
= ackseq
;
899 // Has this been received out of sequence, ie. have we not received
900 // all tics before the first tic in this packet? If so, send a
903 //printf("SV: %p: %i\n", client, seq);
905 resend_end
= seq
- recvwindow_start
;
910 if (resend_end
>= BACKUPTICS
)
911 resend_end
= BACKUPTICS
- 1;
913 index
= resend_end
- 1;
914 resend_start
= resend_end
;
918 recvobj
= &recvwindow
[index
][player
];
922 // ended our run of unreceived tics
927 if (recvobj
->resend_time
!= 0)
929 // Already sent a resend request for this tic
934 resend_start
= index
;
938 // Possibly send a resend request
940 if (resend_start
< resend_end
)
943 printf("missed %i-%i before %i, send resend\n",
944 recvwindow_start + resend_start,
945 recvwindow_start + resend_end - 1,
948 NET_SV_SendResendRequest(client
,
949 recvwindow_start
+ resend_start
,
950 recvwindow_start
+ resend_end
- 1);
954 static void NET_SV_ParseGameDataACK(net_packet_t
*packet
, net_client_t
*client
)
958 if (server_state
!= SERVER_IN_GAME
)
965 if (!NET_ReadInt8(packet
, &ackseq
))
970 // Expand 8-bit values to the full sequence number
972 ackseq
= NET_SV_ExpandTicNum(ackseq
);
974 // Higher acknowledgement point than we already have?
976 if (ackseq
> client
->acknowledged
)
978 client
->acknowledged
= ackseq
;
982 static void NET_SV_SendTics(net_client_t
*client
,
983 unsigned int start
, unsigned int end
)
985 net_packet_t
*packet
;
988 packet
= NET_NewPacket(500);
990 NET_WriteInt16(packet
, NET_PACKET_TYPE_GAMEDATA
);
992 // Send the start tic and number of tics
994 NET_WriteInt8(packet
, start
& 0xff);
995 NET_WriteInt8(packet
, end
-start
+ 1);
999 for (i
=start
; i
<=end
; ++i
)
1001 net_full_ticcmd_t
*cmd
;
1003 cmd
= &client
->sendqueue
[i
% BACKUPTICS
];
1007 I_Error("Wanted to send %i, but %i is in its place", i
, cmd
->seq
);
1012 NET_WriteFullTiccmd(packet
, cmd
, sv_settings
.lowres_turn
);
1017 NET_Conn_SendPacket(&client
->connection
, packet
);
1019 NET_FreePacket(packet
);
1022 // Parse a retransmission request from a client
1024 static void NET_SV_ParseResendRequest(net_packet_t
*packet
, net_client_t
*client
)
1026 unsigned int start
, last
;
1027 unsigned int num_tics
;
1030 // Read the starting tic and number of tics
1032 if (!NET_ReadInt32(packet
, &start
)
1033 || !NET_ReadInt8(packet
, &num_tics
))
1038 //printf("SV: %p: resend %i-%i\n", client, start, start+num_tics-1);
1040 // Check we have all the requested tics
1042 last
= start
+ num_tics
- 1;
1044 for (i
=start
; i
<=last
; ++i
)
1046 net_full_ticcmd_t
*cmd
;
1048 cmd
= &client
->sendqueue
[i
% BACKUPTICS
];
1052 // We do not have the requested tic (any more)
1053 // This is pretty fatal. We could disconnect the client,
1054 // but then again this could be a spoofed packet. Just
1061 // Resend those tics
1063 NET_SV_SendTics(client
, start
, last
);
1066 // Send a response back to the client
1068 void NET_SV_SendQueryResponse(net_addr_t
*addr
)
1070 net_packet_t
*reply
;
1071 net_querydata_t querydata
;
1075 querydata
.version
= PACKAGE_STRING
;
1079 querydata
.server_state
= server_state
;
1081 // Number of players/maximum players
1083 querydata
.num_players
= NET_SV_NumPlayers();
1084 querydata
.max_players
= MAXPLAYERS
;
1086 // Game mode/mission
1088 querydata
.gamemode
= sv_gamemode
;
1089 querydata
.gamemission
= sv_gamemission
;
1091 // Server description. This is currently hard-coded.
1093 querydata
.description
= "Chocolate Doom server";
1095 // Send it and we're done.
1097 reply
= NET_NewPacket(64);
1098 NET_WriteInt16(reply
, NET_PACKET_TYPE_QUERY_RESPONSE
);
1099 NET_WriteQueryData(reply
, &querydata
);
1100 NET_SendPacket(addr
, reply
);
1101 NET_FreePacket(reply
);
1104 // Process a packet received by the server
1106 static void NET_SV_Packet(net_packet_t
*packet
, net_addr_t
*addr
)
1108 net_client_t
*client
;
1109 unsigned int packet_type
;
1111 // Find which client this packet came from
1113 client
= NET_SV_FindClient(addr
);
1115 // Read the packet type
1117 if (!NET_ReadInt16(packet
, &packet_type
))
1124 if (packet_type
== NET_PACKET_TYPE_SYN
)
1126 NET_SV_ParseSYN(packet
, client
, addr
);
1128 else if (packet_type
== NET_PACKET_TYPE_QUERY
)
1130 NET_SV_SendQueryResponse(addr
);
1132 else if (client
== NULL
)
1134 // Must come from a valid client; ignore otherwise
1136 else if (NET_Conn_Packet(&client
->connection
, packet
, &packet_type
))
1138 // Packet was eaten by the common connection code
1142 //printf("SV: %s: %i\n", NET_AddrToString(addr), packet_type);
1144 switch (packet_type
)
1146 case NET_PACKET_TYPE_GAMESTART
:
1147 NET_SV_ParseGameStart(packet
, client
);
1149 case NET_PACKET_TYPE_GAMEDATA
:
1150 NET_SV_ParseGameData(packet
, client
);
1152 case NET_PACKET_TYPE_GAMEDATA_ACK
:
1153 NET_SV_ParseGameDataACK(packet
, client
);
1155 case NET_PACKET_TYPE_GAMEDATA_RESEND
:
1156 NET_SV_ParseResendRequest(packet
, client
);
1159 // unknown packet type
1165 // If this address is not in the list of clients, be sure to
1168 if (NET_SV_FindClient(addr
) == NULL
)
1170 NET_FreeAddress(addr
);
1175 static void NET_SV_SendWaitingData(net_client_t
*client
)
1177 net_packet_t
*packet
;
1178 net_client_t
*controller
;
1182 NET_SV_AssignPlayers();
1184 controller
= NET_SV_Controller();
1186 num_players
= NET_SV_NumPlayers();
1188 // time to send the client another status packet
1190 packet
= NET_NewPacket(10);
1191 NET_WriteInt16(packet
, NET_PACKET_TYPE_WAITING_DATA
);
1193 // include the number of players waiting
1195 NET_WriteInt8(packet
, num_players
);
1197 // send the number of drone clients
1199 NET_WriteInt8(packet
, NET_SV_NumDrones());
1201 // indicate whether the client is the controller
1203 NET_WriteInt8(packet
, client
== controller
);
1205 // send the player number of this client
1207 NET_WriteInt8(packet
, client
->player_number
);
1209 // send the addresses of all players
1211 for (i
=0; i
<num_players
; ++i
)
1217 NET_WriteString(packet
, sv_players
[i
]->name
);
1221 addr
= NET_AddrToString(sv_players
[i
]->addr
);
1223 NET_WriteString(packet
, addr
);
1226 // Send the WAD and dehacked checksums of the controlling client.
1228 if (controller
!= NULL
)
1230 NET_WriteMD5Sum(packet
, controller
->wad_md5sum
);
1231 NET_WriteMD5Sum(packet
, controller
->deh_md5sum
);
1232 NET_WriteInt8(packet
, controller
->is_freedoom
);
1236 NET_WriteMD5Sum(packet
, client
->wad_md5sum
);
1237 NET_WriteMD5Sum(packet
, client
->deh_md5sum
);
1238 NET_WriteInt8(packet
, client
->is_freedoom
);
1241 // send packet to client and free
1243 NET_Conn_SendPacket(&client
->connection
, packet
);
1244 NET_FreePacket(packet
);
1247 static void NET_SV_PumpSendQueue(net_client_t
*client
)
1249 net_full_ticcmd_t cmd
;
1252 int starttic
, endtic
;
1254 // If a client has not sent any acknowledgments for a while,
1255 // wait until they catch up.
1257 if (client
->sendseq
- NET_SV_LatestAcknowledged() > 40)
1262 // Work out the index into the receive window
1264 recv_index
= client
->sendseq
- recvwindow_start
;
1266 if (recv_index
< 0 || recv_index
>= BACKUPTICS
)
1271 // Check if we can generate a new entry for the send queue
1272 // using the data in recvwindow.
1274 for (i
=0; i
<MAXPLAYERS
; ++i
)
1276 if (sv_players
[i
] == client
)
1278 // Client does not rely on itself for data
1283 if (sv_players
[i
] == NULL
|| !ClientConnected(sv_players
[i
]))
1288 if (!recvwindow
[recv_index
][i
].active
)
1290 // We do not have this player's ticcmd, so we cannot
1291 // generate a complete command yet.
1297 //printf("SV: have complete ticcmd for %i\n", client->sendseq);
1299 // We have all data we need to generate a command for this tic.
1301 cmd
.seq
= client
->sendseq
;
1303 // Add ticcmds from all players
1307 for (i
=0; i
<MAXPLAYERS
; ++i
)
1309 net_client_recv_t
*recvobj
;
1311 if (sv_players
[i
] == client
)
1313 // Not the player we are sending to
1315 cmd
.playeringame
[i
] = false;
1319 if (sv_players
[i
] == NULL
|| !recvwindow
[recv_index
][i
].active
)
1321 cmd
.playeringame
[i
] = false;
1325 cmd
.playeringame
[i
] = true;
1327 recvobj
= &recvwindow
[recv_index
][i
];
1329 cmd
.cmds
[i
] = recvobj
->diff
;
1331 if (recvobj
->latency
> cmd
.latency
)
1332 cmd
.latency
= recvobj
->latency
;
1335 //printf("SV: %i: latency %i\n", client->player_number, cmd.latency);
1337 // Add into the queue
1339 client
->sendqueue
[client
->sendseq
% BACKUPTICS
] = cmd
;
1341 // Transmit the new tic to the client
1343 starttic
= client
->sendseq
- sv_settings
.extratics
;
1344 endtic
= client
->sendseq
;
1349 NET_SV_SendTics(client
, starttic
, endtic
);
1354 // Prevent against deadlock: resend requests are usually only
1355 // triggered if we miss a packet and receive the next one.
1356 // If we miss a whole load of packets, we can end up in a
1357 // deadlock situation where the client will not send any more.
1358 // If we don't receive any game data in a while, trigger a resend
1359 // request for the next tic we're expecting.
1361 void NET_SV_CheckDeadlock(net_client_t
*client
)
1366 // Don't expect game data from clients.
1373 nowtime
= I_GetTimeMS();
1375 // If we haven't received anything for a long time, it may be a deadlock.
1377 if (nowtime
- client
->last_gamedata_time
> 1000)
1379 // Search the receive window for the first tic we are expecting
1380 // from this player.
1382 for (i
=0; i
<BACKUPTICS
; ++i
)
1384 if (!recvwindow
[client
->player_number
][i
].active
)
1386 //printf("Possible deadlock: Sending resend request\n");
1388 // Found a tic we haven't received. Send a resend request.
1390 NET_SV_SendResendRequest(client
,
1391 recvwindow_start
+ i
,
1392 recvwindow_start
+ i
+ 5);
1394 client
->last_gamedata_time
= nowtime
;
1401 // Called when all players have disconnected. Return to listening for
1402 // players to start a new game, and disconnect any drones still connected.
1404 static void NET_SV_GameEnded(void)
1408 server_state
= SERVER_WAITING_START
;
1409 sv_gamemode
= indetermined
;
1411 for (i
=0; i
<MAXNETNODES
; ++i
)
1413 if (clients
[i
].active
)
1415 NET_SV_DisconnectClient(&clients
[i
]);
1420 // Perform any needed action on a client
1422 static void NET_SV_RunClient(net_client_t
*client
)
1426 NET_Conn_Run(&client
->connection
);
1428 if (client
->connection
.state
== NET_CONN_STATE_DISCONNECTED
1429 && client
->connection
.disconnect_reason
== NET_DISCONNECT_TIMEOUT
)
1431 NET_SV_BroadcastMessage("Client '%s' timed out and disconnected",
1435 // Is this client disconnected?
1437 if (client
->connection
.state
== NET_CONN_STATE_DISCONNECTED
)
1439 // deactivate and free back
1441 client
->active
= false;
1443 NET_FreeAddress(client
->addr
);
1445 // Are there any clients left connected? If not, return the
1446 // server to the waiting-for-players state.
1448 // Disconnect any drones still connected.
1450 if (NET_SV_NumPlayers() <= 0)
1456 if (!ClientConnected(client
))
1458 // client has not yet finished connecting
1463 if (server_state
== SERVER_WAITING_START
)
1465 // Waiting for the game to start
1467 // Send information once every second
1469 if (client
->last_send_time
< 0
1470 || I_GetTimeMS() - client
->last_send_time
> 1000)
1472 NET_SV_SendWaitingData(client
);
1473 client
->last_send_time
= I_GetTimeMS();
1477 if (server_state
== SERVER_IN_GAME
)
1479 NET_SV_PumpSendQueue(client
);
1480 NET_SV_CheckDeadlock(client
);
1484 // Add a network module to the server context
1486 void NET_SV_AddModule(net_module_t
*module
)
1488 module
->InitServer();
1489 NET_AddModule(server_context
, module
);
1492 // Initialize server and wait for connections
1494 void NET_SV_Init(void)
1498 // initialize send/receive context
1500 server_context
= NET_NewContext();
1504 for (i
=0; i
<MAXNETNODES
; ++i
)
1506 clients
[i
].active
= false;
1509 NET_SV_AssignPlayers();
1511 server_state
= SERVER_WAITING_START
;
1512 sv_gamemode
= indetermined
;
1513 server_initialized
= true;
1516 // Run server code to check for new packets/send packets as the server
1519 void NET_SV_Run(void)
1522 net_packet_t
*packet
;
1525 if (!server_initialized
)
1530 while (NET_RecvPacket(server_context
, &addr
, &packet
))
1532 NET_SV_Packet(packet
, addr
);
1533 NET_FreePacket(packet
);
1536 // "Run" any clients that may have things to do, independent of responses
1537 // to received packets
1539 for (i
=0; i
<MAXNETNODES
; ++i
)
1541 if (clients
[i
].active
)
1543 NET_SV_RunClient(&clients
[i
]);
1547 if (server_state
== SERVER_IN_GAME
)
1549 NET_SV_AdvanceWindow();
1551 for (i
=0; i
<MAXPLAYERS
; ++i
)
1553 if (sv_players
[i
] != NULL
&& ClientConnected(sv_players
[i
]))
1555 NET_SV_CheckResends(sv_players
[i
]);
1561 void NET_SV_Shutdown(void)
1567 if (!server_initialized
)
1572 fprintf(stderr
, "SV: Shutting down server...\n");
1574 // Disconnect all clients
1576 for (i
=0; i
<MAXNETNODES
; ++i
)
1578 if (clients
[i
].active
)
1580 NET_SV_DisconnectClient(&clients
[i
]);
1584 // Wait for all clients to finish disconnecting
1586 start_time
= I_GetTimeMS();
1591 // Check if any clients are still not finished
1595 for (i
=0; i
<MAXNETNODES
; ++i
)
1597 if (clients
[i
].active
)
1605 if (I_GetTimeMS() - start_time
> 5000)
1608 fprintf(stderr
, "SV: Timed out waiting for clients to disconnect.\n");
1611 // Run the client code in case this is a loopback client.
1616 // Don't hog the CPU