Add weapon cycling bindings for mouse and joystick buttons. Add weapon cycling bindi...
[chocolate-doom.git] / src / net_server.c
blob383608be6b0c6af467a6673f4742dfc4206e5d1d
1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // Copyright(C) 2005 Simon Howard
5 //
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
19 // 02111-1307, USA.
21 // Network server code
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
28 #include "config.h"
30 #include "doomdef.h"
31 #include "doomstat.h"
32 #include "i_system.h"
33 #include "i_timer.h"
35 #include "m_argv.h"
37 #include "net_client.h"
38 #include "net_common.h"
39 #include "net_defs.h"
40 #include "net_io.h"
41 #include "net_loop.h"
42 #include "net_packet.h"
43 #include "net_server.h"
44 #include "net_sdl.h"
45 #include "net_structrw.h"
47 typedef enum
49 // waiting for the game to start
51 SERVER_WAITING_START,
53 // in a game
55 SERVER_IN_GAME,
56 } net_server_state_t;
58 typedef struct
60 boolean active;
61 int player_number;
62 net_addr_t *addr;
63 net_connection_t connection;
64 int last_send_time;
65 char *name;
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
78 int sendseq;
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.
87 boolean drone;
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;
98 } net_client_t;
100 // structure used for the recv window
102 typedef struct
104 // Whether this tic has been received yet
106 boolean active;
108 // Latency value received from the client
110 signed int latency;
112 // Last time we sent a resend request for this tic
114 unsigned int resend_time;
116 // Tic data itself
118 net_ticdiff_t diff;
119 } net_client_recv_t;
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;
130 // receive window
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)
139 if (client->active)
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, ...)
158 char buf[1024];
159 va_list args;
160 net_packet_t *packet;
162 va_start(args, s);
163 vsnprintf(buf, sizeof(buf), s, args);
164 va_end(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, ...)
176 char buf[1024];
177 va_list args;
178 int i;
180 va_start(args, s);
181 vsnprintf(buf, sizeof(buf), s, args);
182 va_end(args);
184 for (i=0; i<MAXNETNODES; ++i)
186 if (ClientConnected(&clients[i]))
188 NET_SV_SendConsoleMessage(&clients[i], buf);
192 NET_SafePuts(buf);
196 // Assign player numbers to connected clients
198 static void NET_SV_AssignPlayers(void)
200 int i;
201 int pl;
203 pl = 0;
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;
213 ++pl;
215 else
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)
232 int i;
233 int result;
235 result = 0;
237 for (i=0; i<MAXPLAYERS; ++i)
239 if (sv_players[i] != NULL && ClientConnected(sv_players[i]))
241 result += 1;
245 return result;
248 // Returns the number of drones currently connected.
250 static int NET_SV_NumDrones(void)
252 int i;
253 int result;
255 result = 0;
257 for (i=0; i<MAXNETNODES; ++i)
259 if (ClientConnected(&clients[i]) && clients[i].drone)
261 result += 1;
265 return result;
268 // returns the number of clients connected
270 static int NET_SV_NumClients(void)
272 int count;
273 int i;
275 count = 0;
277 for (i=0; i<MAXNETNODES; ++i)
279 if (ClientConnected(&clients[i]))
281 ++count;
285 return count;
288 // Find the latest tic which has been acknowledged as received by
289 // all clients.
291 static unsigned int NET_SV_LatestAcknowledged(void)
293 unsigned int lowtic = UINT_MAX;
294 int i;
296 for (i=0; i<MAXNETNODES; ++i)
298 if (ClientConnected(&clients[i]))
300 if (clients[i].acknowledged < lowtic)
302 lowtic = clients[i].acknowledged;
307 return lowtic;
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)
316 unsigned int lowtic;
317 int i;
319 if (NET_SV_NumPlayers() <= 0)
321 return;
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
333 // the recv window
335 should_advance = true;
337 for (i=0; i<MAXPLAYERS; ++i)
339 if (sv_players[i] == NULL || !ClientConnected(sv_players[i]))
341 continue;
344 if (!recvwindow[0][i].active)
346 should_advance = false;
347 break;
351 if (!should_advance)
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.
357 break;
360 // Advance the window
362 memcpy(recvwindow, recvwindow + 1, sizeof(*recvwindow) * (BACKUPTICS - 1));
363 memset(&recvwindow[BACKUPTICS-1], 0, sizeof(*recvwindow));
364 ++recvwindow_start;
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)
374 int i;
376 // first client in the list is the controller
378 for (i=0; i<MAXNETNODES; ++i)
380 if (ClientConnected(&clients[i]) && !clients[i].drone)
382 return &clients[i];
386 return NULL;
389 // Given an address, find the corresponding client
391 static net_client_t *NET_SV_FindClient(net_addr_t *addr)
393 int i;
395 for (i=0; i<MAXNETNODES; ++i)
397 if (clients[i].active && clients[i].addr == addr)
399 // found the client
401 return &clients[i];
405 return NULL;
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,
422 net_addr_t *addr,
423 char *player_name)
425 client->active = true;
426 NET_Conn_InitServer(&client->connection, addr);
427 client->addr = addr;
428 client->last_send_time = -1;
429 client->name = strdup(player_name);
431 // init the ticcmd send queue
433 client->sendseq = 0;
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,
446 net_addr_t *addr)
448 unsigned int magic;
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;
454 char *player_name;
455 char *client_version;
456 int i;
458 // read the magic number
460 if (!NET_ReadInt32(packet, &magic))
462 return;
465 if (magic != NET_MAGIC_NUMBER)
467 // invalid magic number
469 return;
472 // Check the client version is the same as the server
474 client_version = NET_ReadString(packet);
476 if (client_version == NULL)
478 return;
481 if (strcmp(client_version, PACKAGE_STRING) != 0)
484 // @category net
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: "
496 PACKAGE_STRING);
497 return;
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))
511 return;
514 if (!NET_ValidGameMode(cl_gamemode, cl_gamemission))
516 return;
519 // read the player's name
521 player_name = NET_ReadString(packet);
523 if (player_name == NULL)
525 return;
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");
535 return;
538 // allocate a client slot if there isn't one already
540 if (client == NULL)
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];
549 break;
553 if (client == NULL)
555 return;
558 else
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;
569 // New client?
571 if (!client->active)
573 int num_players;
575 // Before accepting a new client, check that there is a slot
576 // free
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!");
585 return;
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
607 // the other clients
609 if (cl_gamemode != sv_gamemode || cl_gamemission != sv_gamemission)
611 NET_SV_SendReject(addr, "You are playing the wrong game!");
612 return;
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;
636 int nowtime;
637 int i;
639 if (client != NET_SV_Controller())
641 // Only the controller can start a new game
643 return;
646 if (!NET_ReadSettings(packet, &settings))
648 // Malformed packet
650 return;
653 // Check the game settings are valid
655 if (!NET_ValidGameSettings(sv_gamemode, sv_gamemission, &settings))
657 return;
660 if (server_state != SERVER_WAITING_START)
662 // Can only start a game if we are in the waiting start state.
664 return;
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]))
690 continue;
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;
717 int i;
718 unsigned int nowtime;
719 int index;
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)
742 // Outside the range
744 continue;
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)
757 int i;
758 int player;
759 int resend_start, resend_end;
760 unsigned int nowtime;
762 nowtime = I_GetTimeMS();
764 player = client->player_number;
765 resend_start = -1;
766 resend_end = -1;
768 for (i=0; i<BACKUPTICS; ++i)
770 net_client_recv_t *recvobj;
771 boolean need_resend;
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;
782 if (need_resend)
784 // Start a new run of resend tics?
786 if (resend_start < 0)
788 resend_start = i;
791 resend_end = i;
793 else
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);
804 resend_start = -1;
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;
822 unsigned int seq;
823 unsigned int ackseq;
824 unsigned int num_tics;
825 unsigned int nowtime;
826 size_t i;
827 int player;
828 int resend_start, resend_end;
829 int index;
831 if (server_state != SERVER_IN_GAME)
833 return;
836 if (client->drone)
838 // Drones do not contribute any game data.
839 return;
842 player = client->player_number;
844 // Read header
846 if (!NET_ReadInt8(packet, &ackseq)
847 || !NET_ReadInt8(packet, &seq)
848 || !NET_ReadInt8(packet, &num_tics))
850 return;
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);
862 // Sanity checks
864 for (i=0; i<num_tics; ++i)
866 net_ticdiff_t diff;
867 signed int latency;
869 if (!NET_ReadSInt16(packet, &latency)
870 || !NET_ReadTiccmdDiff(packet, &diff, sv_settings.lowres_turn))
872 return;
875 index = seq + i - recvwindow_start;
877 if (index < 0 || index >= BACKUPTICS)
879 // Not in range of the recv window
881 continue;
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
901 // resend request.
903 //printf("SV: %p: %i\n", client, seq);
905 resend_end = seq - recvwindow_start;
907 if (resend_end <= 0)
908 return;
910 if (resend_end >= BACKUPTICS)
911 resend_end = BACKUPTICS - 1;
913 index = resend_end - 1;
914 resend_start = resend_end;
916 while (index >= 0)
918 recvobj = &recvwindow[index][player];
920 if (recvobj->active)
922 // ended our run of unreceived tics
924 break;
927 if (recvobj->resend_time != 0)
929 // Already sent a resend request for this tic
931 break;
934 resend_start = index;
935 --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,
946 seq);
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)
956 unsigned int ackseq;
958 if (server_state != SERVER_IN_GAME)
960 return;
963 // Read header
965 if (!NET_ReadInt8(packet, &ackseq))
967 return;
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;
986 unsigned int i;
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);
997 // Write the tics
999 for (i=start; i<=end; ++i)
1001 net_full_ticcmd_t *cmd;
1003 cmd = &client->sendqueue[i % BACKUPTICS];
1005 if (i != cmd->seq)
1007 I_Error("Wanted to send %i, but %i is in its place", i, cmd->seq);
1010 // Add command
1012 NET_WriteFullTiccmd(packet, cmd, sv_settings.lowres_turn);
1015 // Send packet
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;
1028 unsigned int i;
1030 // Read the starting tic and number of tics
1032 if (!NET_ReadInt32(packet, &start)
1033 || !NET_ReadInt8(packet, &num_tics))
1035 return;
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];
1050 if (i != cmd->seq)
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
1055 // ignore it.
1057 return;
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;
1073 // Version
1075 querydata.version = PACKAGE_STRING;
1077 // Server state
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))
1119 // no packet type
1121 return;
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
1140 else
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);
1148 break;
1149 case NET_PACKET_TYPE_GAMEDATA:
1150 NET_SV_ParseGameData(packet, client);
1151 break;
1152 case NET_PACKET_TYPE_GAMEDATA_ACK:
1153 NET_SV_ParseGameDataACK(packet, client);
1154 break;
1155 case NET_PACKET_TYPE_GAMEDATA_RESEND:
1156 NET_SV_ParseResendRequest(packet, client);
1157 break;
1158 default:
1159 // unknown packet type
1161 break;
1165 // If this address is not in the list of clients, be sure to
1166 // free it back.
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;
1179 int num_players;
1180 int i;
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)
1213 char *addr;
1215 // name
1217 NET_WriteString(packet, sv_players[i]->name);
1219 // address
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);
1234 else
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;
1250 int recv_index;
1251 int i;
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)
1259 return;
1262 // Work out the index into the receive window
1264 recv_index = client->sendseq - recvwindow_start;
1266 if (recv_index < 0 || recv_index >= BACKUPTICS)
1268 return;
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
1280 continue;
1283 if (sv_players[i] == NULL || !ClientConnected(sv_players[i]))
1285 continue;
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.
1293 return;
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
1305 cmd.latency = 0;
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;
1316 continue;
1319 if (sv_players[i] == NULL || !recvwindow[recv_index][i].active)
1321 cmd.playeringame[i] = false;
1322 continue;
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;
1346 if (starttic < 0)
1347 starttic = 0;
1349 NET_SV_SendTics(client, starttic, endtic);
1351 ++client->sendseq;
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)
1363 int nowtime;
1364 int i;
1366 // Don't expect game data from clients.
1368 if (client->drone)
1370 return;
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;
1395 break;
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)
1406 int i;
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)
1424 // Run common code
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",
1432 client->name);
1435 // Is this client disconnected?
1437 if (client->connection.state == NET_CONN_STATE_DISCONNECTED)
1439 // deactivate and free back
1441 client->active = false;
1442 free(client->name);
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)
1452 NET_SV_GameEnded();
1456 if (!ClientConnected(client))
1458 // client has not yet finished connecting
1460 return;
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)
1496 int i;
1498 // initialize send/receive context
1500 server_context = NET_NewContext();
1502 // no clients yet
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
1517 // requires
1519 void NET_SV_Run(void)
1521 net_addr_t *addr;
1522 net_packet_t *packet;
1523 int i;
1525 if (!server_initialized)
1527 return;
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)
1563 int i;
1564 boolean running;
1565 int start_time;
1567 if (!server_initialized)
1569 return;
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();
1587 running = true;
1589 while (running)
1591 // Check if any clients are still not finished
1593 running = false;
1595 for (i=0; i<MAXNETNODES; ++i)
1597 if (clients[i].active)
1599 running = true;
1603 // Timed out?
1605 if (I_GetTimeMS() - start_time > 5000)
1607 running = false;
1608 fprintf(stderr, "SV: Timed out waiting for clients to disconnect.\n");
1611 // Run the client code in case this is a loopback client.
1613 NET_CL_Run();
1614 NET_SV_Run();
1616 // Don't hog the CPU
1618 I_Sleep(1);