e21de8c5859c47b1f5e1dcae2cda6678f8704715
[rocksndiamonds.git] / src / network.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // network.c
10 // ============================================================================
11
12 #include <signal.h>
13 #include <sys/time.h>
14
15 #include "libgame/libgame.h"
16
17 #include "network.h"
18 #include "netserv.h"
19 #include "main.h"
20 #include "game.h"
21 #include "tape.h"
22 #include "files.h"
23 #include "tools.h"
24 #include "screens.h"
25
26 struct NetworkClientPlayerInfo
27 {
28   byte nr;
29   char name[MAX_PLAYER_NAME_LEN + 1];
30   struct NetworkClientPlayerInfo *next;
31 };
32
33 static struct NetworkClientPlayerInfo first_player =
34 {
35   0,
36   EMPTY_PLAYER_NAME,
37   NULL
38 };
39
40 /* server stuff */
41
42 static TCPsocket sfd;           /* TCP server socket */
43 static UDPsocket udp;           /* UDP server socket */
44 static SDLNet_SocketSet rfds;   /* socket set */
45
46 static byte realbuffer[512];
47 static byte readbuffer[MAX_BUFFER_SIZE], writbuffer[MAX_BUFFER_SIZE];
48 static byte *buffer = realbuffer + 4;
49 static int nread = 0, nwrite = 0;
50 static boolean stop_network_game = FALSE;
51
52 static void DrawNetworkTextExt(char *message, int font_nr, boolean initialize)
53 {
54   static int xpos = 0, ypos = 0;
55   int font_width = getFontWidth(font_nr);
56   int font_height = getFontHeight(font_nr);
57
58   if (initialize)
59   {
60     xpos = (WIN_XSIZE - getTextWidth(message, font_nr)) / 2;
61     ypos = 120;
62
63     DrawText(xpos, ypos, message, font_nr);
64
65     xpos = 0;
66     ypos = 150;
67
68     Error(ERR_DEBUG, "========== %s ==========", message);
69   }
70   else
71   {
72     int max_chars_per_line = WIN_XSIZE / font_width;
73     int max_lines_per_text = 10;
74     int num_lines_spacing = (font_nr == FC_YELLOW ? 1 : 3);
75     int num_lines_printed = DrawTextBuffer(xpos, ypos, message, font_nr,
76                                            max_chars_per_line, -1,
77                                            max_lines_per_text, 0, -1,
78                                            TRUE, TRUE, FALSE);
79
80     ypos += (num_lines_printed + num_lines_spacing) * font_height;
81
82     Error(ERR_DEBUG, "%s", message);
83   }
84
85   BackToFront();
86 }
87
88 static void DrawNetworkText(char *message)
89 {
90   DrawNetworkTextExt(message, FC_YELLOW, FALSE);
91 }
92
93 static void DrawNetworkText_Success(char *message)
94 {
95   DrawNetworkTextExt(message, FC_GREEN, FALSE);
96 }
97
98 static void DrawNetworkText_Failed(char *message)
99 {
100   DrawNetworkTextExt(message, FC_RED, FALSE);
101 }
102
103 static void DrawNetworkText_Title(char *message)
104 {
105   DrawNetworkTextExt(message, FC_GREEN, TRUE);
106 }
107
108 static void SendBufferToServer(int size)
109 {
110   if (!network.enabled)
111     return;
112
113   realbuffer[0] = realbuffer[1] = realbuffer[2] = 0;
114   realbuffer[3] = (byte)size;
115   buffer[0] = 0;
116
117   if (nwrite + 4 + size >= MAX_BUFFER_SIZE)
118     Error(ERR_EXIT, "internal error: network send buffer overflow");
119
120   memcpy(writbuffer + nwrite, realbuffer, 4 + size);
121   nwrite += 4 + size;
122
123   /* directly send the buffer to the network server */
124   SDLNet_TCP_Send(sfd, writbuffer, nwrite);
125   nwrite = 0;
126 }
127
128 struct NetworkClientPlayerInfo *getNetworkPlayer(int player_nr)
129 {
130   struct NetworkClientPlayerInfo *player = NULL;
131
132   for (player = &first_player; player; player = player->next)
133     if (player->nr == player_nr)
134       break;
135
136   if (player == NULL)   /* should not happen */
137     Error(ERR_EXIT, "protocol error: reference to non-existing player %d",
138           player_nr);
139
140   return player;
141 }
142
143 char *getNetworkPlayerName(int player_nr)
144 {
145   struct NetworkClientPlayerInfo *player;
146
147   if (player_nr == 0)
148     return("the network game server");
149   else if (player_nr == first_player.nr)
150     return("you");
151   else
152     for (player = &first_player; player; player = player->next)
153       if (player->nr == player_nr && strlen(player->name) > 0)
154         return(player->name);
155
156   return(EMPTY_PLAYER_NAME);
157 }
158
159 static void StartNetworkServer(int port)
160 {
161   static int p;
162
163   p = port;
164 #if defined(TARGET_SDL2)
165   server_thread = SDL_CreateThread(NetworkServerThread,
166                                    "NetworkServerThread", &p);
167 #else
168   server_thread = SDL_CreateThread(NetworkServerThread, &p);
169 #endif
170   network_server = TRUE;
171 }
172
173 boolean ConnectToServer(char *hostname, int port)
174 {
175   IPaddress ip;
176   int server_host = 0;
177   int i;
178
179   DrawNetworkText_Title("Initializing Network");
180
181   if (port == 0)
182     port = DEFAULT_SERVER_PORT;
183
184   if (hostname == NULL)
185   {
186     // if no hostname given, try to auto-detect network server in local network
187     // by doing a UDP broadcast on the network server port and wait for answer
188
189     SDLNet_SocketSet udp_socket_set = SDLNet_AllocSocketSet(1);
190     if (!udp_socket_set)
191       Error(ERR_EXIT, "SDLNet_AllocSocketSet() failed: %s"), SDLNet_GetError();
192
193     udp = SDLNet_UDP_Open(0);
194     if(!udp)
195       Error(ERR_EXIT, "SDLNet_UDP_Open() failed: %s", SDLNet_GetError());
196
197     if (SDLNet_UDP_AddSocket(udp_socket_set, udp) == -1)
198       Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_AddSocket() failed: %s"),
199         SDLNet_GetError();
200
201     char *data_ptr = "network server UDB broadcast";
202     int data_len = strlen(data_ptr) + 1;
203     IPaddress ip_address;
204
205     SDLNet_Write32(0xffffffff, &ip_address.host);       /* 255.255.255.255 */
206     SDLNet_Write16(port,       &ip_address.port);
207
208     UDPpacket packet =
209     {
210       -1,
211       (Uint8 *)data_ptr,
212       data_len,
213       data_len,
214       0,
215       ip_address
216     };
217
218     SDLNet_UDP_Send(udp, -1, &packet);
219
220     DrawNetworkText("Looking for local network server ...");
221
222     if (SDLNet_CheckSockets(udp_socket_set, 1000) == 1)
223     {
224       int num_packets = SDLNet_UDP_Recv(udp, &packet);
225
226       if (num_packets == 1)
227       {
228         DrawNetworkText_Success("Network server found!");
229
230         server_host = SDLNet_Read32(&packet.address.host);
231       }
232       else
233       {
234         DrawNetworkText_Failed("No answer from network server!");
235       }
236     }
237     else
238     {
239       DrawNetworkText_Failed("No network server found!");
240     }
241   }
242
243   rfds = SDLNet_AllocSocketSet(1);
244
245   if (hostname)
246   {
247     SDLNet_ResolveHost(&ip, hostname, port);
248
249     if (ip.host == INADDR_NONE)
250       Error(ERR_EXIT, "cannot locate host '%s'", hostname);
251     else
252       server_host = SDLNet_Read32(&ip.host);
253
254     DrawNetworkText("Connecting to remote host ...");
255   }
256   else
257   {
258     // if no hostname was given and no network server was auto-detected in the
259     // local network, try to connect to a network server at the local host
260     if (server_host == 0)
261       server_host = 0x7f000001;                 /* 127.0.0.1 */
262
263     SDLNet_Write32(server_host, &ip.host);
264     SDLNet_Write16(port,        &ip.port);
265
266     DrawNetworkText("Connecting to local host ...");
267   }
268
269   Error(ERR_DEBUG, "trying to connect to network server at %d.%d.%d.%d ...",
270         (server_host >> 24) & 0xff,
271         (server_host >> 16) & 0xff,
272         (server_host >>  8) & 0xff,
273         (server_host >>  0) & 0xff);
274
275   sfd = SDLNet_TCP_Open(&ip);
276
277   if (sfd)
278   {
279     SDLNet_TCP_AddSocket(rfds, sfd);
280
281     DrawNetworkText_Success("Successfully connected!");
282
283     return TRUE;
284   }
285   else
286   {
287     DrawNetworkText_Failed("Failed to connect to network server!");
288
289     printf("SDLNet_TCP_Open(): %s\n", SDLNet_GetError());
290   }
291
292   if (hostname)                 /* connect to specified server failed */
293     return FALSE;
294
295   DrawNetworkText("Starting new local network server ...");
296
297   StartNetworkServer(port);
298
299   /* wait for server to start up and try connecting several times */
300   for (i = 0; i < 6; i++)
301   {
302     Delay(500);                 /* wait 500 ms == 0.5 seconds */
303
304     if ((sfd = SDLNet_TCP_Open(&ip)))           /* connected */
305     {
306       DrawNetworkText_Success("Successfully connected!");
307
308       SDLNet_TCP_AddSocket(rfds, sfd);
309       return TRUE;
310     }
311   }
312
313   DrawNetworkText_Failed("Failed to connect to network server!");
314
315   /* when reaching this point, connect to newly started server has failed */
316   return FALSE;
317 }
318
319 void SendToServer_PlayerName(char *player_name)
320 {
321   int len_player_name = strlen(player_name);
322
323   buffer[1] = OP_PLAYER_NAME;
324   memcpy(&buffer[2], player_name, len_player_name);
325   SendBufferToServer(2 + len_player_name);
326   Error(ERR_NETWORK_CLIENT, "you set your player name to \"%s\"", player_name);
327 }
328
329 void SendToServer_ProtocolVersion()
330 {
331   buffer[1] = OP_PROTOCOL_VERSION;
332   buffer[2] = PROTOCOL_VERSION_1;
333   buffer[3] = PROTOCOL_VERSION_2;
334   buffer[4] = PROTOCOL_VERSION_3;
335
336   SendBufferToServer(5);
337 }
338
339 void SendToServer_NrWanted(int nr_wanted)
340 {
341   buffer[1] = OP_NUMBER_WANTED;
342   buffer[2] = nr_wanted;
343
344   SendBufferToServer(3);
345 }
346
347 void SendToServer_StartPlaying()
348 {
349   unsigned int new_random_seed = InitRND(level.random_seed);
350
351   int dummy = 0;                /* !!! HAS NO MEANING ANYMORE !!! */
352                                 /* the name of the level must be enough */
353
354   buffer[1] = OP_START_PLAYING;
355   buffer[2] = (byte)(level_nr >> 8);
356   buffer[3] = (byte)(level_nr & 0xff);
357   buffer[4] = (byte)(dummy >> 8);
358   buffer[5] = (byte)(dummy & 0xff);
359
360   buffer[6] = (unsigned char)((new_random_seed >> 24) & 0xff);
361   buffer[7] = (unsigned char)((new_random_seed >> 16) & 0xff);
362   buffer[8] = (unsigned char)((new_random_seed >>  8) & 0xff);
363   buffer[9] = (unsigned char)((new_random_seed >>  0) & 0xff);
364
365   strcpy((char *)&buffer[10], leveldir_current->identifier);
366
367   SendBufferToServer(10 + strlen(leveldir_current->identifier) + 1);
368 }
369
370 void SendToServer_PausePlaying()
371 {
372   buffer[1] = OP_PAUSE_PLAYING;
373
374   SendBufferToServer(2);
375 }
376
377 void SendToServer_ContinuePlaying()
378 {
379   buffer[1] = OP_CONTINUE_PLAYING;
380
381   SendBufferToServer(2);
382 }
383
384 void SendToServer_StopPlaying(int cause_for_stopping)
385 {
386   buffer[1] = OP_STOP_PLAYING;
387   buffer[2] = cause_for_stopping;
388
389   SendBufferToServer(3);
390 }
391
392 void SendToServer_MovePlayer(byte player_action)
393 {
394   buffer[1] = OP_MOVE_PLAYER;
395   buffer[2] = player_action;
396
397   SendBufferToServer(3);
398 }
399
400 static void Handle_OP_BAD_PROTOCOL_VERSION()
401 {
402   Error(ERR_WARN, "protocol version mismatch");
403   Error(ERR_EXIT, "server expects %d.%d.x instead of %d.%d.%d",
404         buffer[2], buffer[3],
405         PROTOCOL_VERSION_1, PROTOCOL_VERSION_2, PROTOCOL_VERSION_3);
406 }
407
408 static void Handle_OP_YOUR_NUMBER()
409 {
410   int new_client_nr = buffer[2];
411   int new_index_nr = new_client_nr - 1;
412   struct PlayerInfo *old_local_player = local_player;
413   struct PlayerInfo *new_local_player = &stored_player[new_index_nr];
414
415   printf("OP_YOUR_NUMBER: %d\n", buffer[0]);
416   first_player.nr = new_client_nr;
417
418   if (old_local_player != new_local_player)
419   {
420     /* set relevant player settings and change to new player */
421
422     local_player = new_local_player;
423
424     old_local_player->connected_locally = FALSE;
425     new_local_player->connected_locally = TRUE;
426
427     old_local_player->connected_network = FALSE;
428     new_local_player->connected_network = TRUE;
429   }
430
431   if (first_player.nr > MAX_PLAYERS)
432     Error(ERR_EXIT, "sorry, more than %d players not allowed", MAX_PLAYERS);
433
434   Error(ERR_NETWORK_CLIENT, "you get client # %d", new_client_nr);
435 }
436
437 static void Handle_OP_NUMBER_WANTED()
438 {
439   int client_nr_wanted = buffer[2];
440   int old_client_nr = buffer[0];
441   int new_client_nr = buffer[3];
442   int old_index_nr = old_client_nr - 1;
443   int new_index_nr = new_client_nr - 1;
444   int index_nr_wanted = client_nr_wanted - 1;
445   struct PlayerInfo *old_player = &stored_player[old_index_nr];
446   struct PlayerInfo *new_player = &stored_player[new_index_nr];
447
448   printf("OP_NUMBER_WANTED: %d\n", buffer[0]);
449
450   if (new_client_nr == client_nr_wanted)        /* switching succeeded */
451   {
452     struct NetworkClientPlayerInfo *player;
453
454     if (old_client_nr != client_nr_wanted)      /* client's nr has changed */
455       Error(ERR_NETWORK_CLIENT, "client %d switches to # %d",
456             old_client_nr, new_client_nr);
457     else if (old_client_nr == first_player.nr)  /* local player keeps his nr */
458       Error(ERR_NETWORK_CLIENT, "keeping client # %d", new_client_nr);
459
460     if (old_client_nr != new_client_nr)
461     {
462       /* set relevant player settings and change to new player */
463
464       old_player->connected_network = FALSE;
465       new_player->connected_network = TRUE;
466     }
467
468     player = getNetworkPlayer(old_client_nr);
469     player->nr = new_client_nr;
470
471     if (old_player == local_player)             /* local player switched */
472     {
473       local_player = new_player;
474
475       old_player->connected_locally = FALSE;
476       new_player->connected_locally = TRUE;
477     }
478   }
479   else if (old_client_nr == first_player.nr)    /* failed -- local player? */
480   {
481     char request[100];
482
483     sprintf(request, "Sorry! Player %d already exists! You are player %d!",
484             index_nr_wanted + 1, new_index_nr + 1);
485
486     Request(request, REQ_CONFIRM);
487
488     Error(ERR_NETWORK_CLIENT, "cannot switch -- you keep client # %d",
489           new_client_nr);
490   }
491 }
492
493 static void Handle_OP_PLAYER_NAME(unsigned int len)
494 {
495   struct NetworkClientPlayerInfo *player;
496   int player_nr = (int)buffer[0];
497
498   printf("OP_PLAYER_NAME: %d\n", player_nr);
499   player = getNetworkPlayer(player_nr);
500   buffer[len] = 0;
501   Error(ERR_NETWORK_CLIENT, "client %d calls itself \"%s\"",
502         buffer[0], &buffer[2]);
503   strncpy(player->name, (char *)&buffer[2], MAX_PLAYER_NAME_LEN);
504 }
505
506 static void Handle_OP_PLAYER_CONNECTED()
507 {
508   struct NetworkClientPlayerInfo *player, *last_player = NULL;
509   int new_client_nr = (int)buffer[0];
510   int new_index_nr = new_client_nr - 1;
511
512   printf("OP_PLAYER_CONNECTED: %d\n", new_client_nr);
513   Error(ERR_NETWORK_CLIENT, "new client %d connected", new_client_nr);
514
515   for (player = &first_player; player; player = player->next)
516   {
517     if (player->nr == new_client_nr)
518       Error(ERR_EXIT, "multiplayer server sent duplicate player id");
519
520     last_player = player;
521   }
522
523   last_player->next = player =
524     checked_malloc(sizeof(struct NetworkClientPlayerInfo));
525   player->nr = new_client_nr;
526   player->name[0] = '\0';
527   player->next = NULL;
528
529   stored_player[new_index_nr].connected_network = TRUE;
530 }
531
532 static void Handle_OP_PLAYER_DISCONNECTED()
533 {
534   struct NetworkClientPlayerInfo *player, *player_disconnected;
535   int player_nr = (int)buffer[0];
536   int index_nr = player_nr - 1;
537
538   printf("OP_PLAYER_DISCONNECTED: %d\n", player_nr);
539   player_disconnected = getNetworkPlayer(player_nr);
540   Error(ERR_NETWORK_CLIENT, "client %d (%s) disconnected",
541         player_nr, getNetworkPlayerName(buffer[0]));
542
543   for (player = &first_player; player; player = player->next)
544     if (player->next == player_disconnected)
545       player->next = player_disconnected->next;
546   free(player_disconnected);
547
548   stored_player[index_nr].connected_locally = FALSE;
549   stored_player[index_nr].connected_network = FALSE;
550 }
551
552 static void Handle_OP_START_PLAYING()
553 {
554   LevelDirTree *new_leveldir;
555   int new_level_nr;
556   unsigned int new_random_seed;
557   char *new_leveldir_identifier;
558
559   new_level_nr = (buffer[2] << 8) + buffer[3];
560   new_random_seed =
561     (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | (buffer[9]);
562   new_leveldir_identifier = (char *)&buffer[10];
563
564   new_leveldir = getTreeInfoFromIdentifier(leveldir_first,
565                                            new_leveldir_identifier);
566   if (new_leveldir == NULL)
567   {
568     Error(ERR_WARN, "no such level identifier: '%s'", new_leveldir_identifier);
569
570     new_leveldir = leveldir_first;
571     Error(ERR_WARN, "using default level set: '%s'", new_leveldir->identifier);
572   }
573
574   printf("OP_START_PLAYING: %d\n", buffer[0]);
575   Error(ERR_NETWORK_CLIENT,
576         "client %d starts game [level %d from level identifier '%s']\n",
577         buffer[0], new_level_nr, new_leveldir->identifier);
578
579   leveldir_current = new_leveldir;
580   level_nr = new_level_nr;
581
582   TapeErase();
583   LoadTape(level_nr);
584   LoadLevel(level_nr);
585
586   StartGameActions(FALSE, setup.autorecord, new_random_seed);
587 }
588
589 static void Handle_OP_PAUSE_PLAYING()
590 {
591   printf("OP_PAUSE_PLAYING: %d\n", buffer[0]);
592   Error(ERR_NETWORK_CLIENT, "client %d pauses game", buffer[0]);
593
594   tape.pausing = TRUE;
595   DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0);
596 }
597
598 static void Handle_OP_CONTINUE_PLAYING()
599 {
600   printf("OP_CONTINUE_PLAYING: %d\n", buffer[0]);
601   Error(ERR_NETWORK_CLIENT, "client %d continues game", buffer[0]);
602
603   tape.pausing = FALSE;
604   DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
605 }
606
607 static void Handle_OP_STOP_PLAYING()
608 {
609   printf("OP_STOP_PLAYING: %d [%d]\n", buffer[0], buffer[2]);
610   Error(ERR_NETWORK_CLIENT, "client %d stops game [%d]", buffer[0], buffer[2]);
611
612   if (game_status == GAME_MODE_PLAYING)
613   {
614     int client_nr = buffer[0];
615     int index_nr = client_nr - 1;
616     struct PlayerInfo *client_player = &stored_player[index_nr];
617     boolean stopped_by_remote_player = (!client_player->connected_locally);
618     char *message = (buffer[2] == NETWORK_STOP_BY_PLAYER ?
619                      "Network game stopped by player!" :
620                      buffer[2] == NETWORK_STOP_BY_ERROR ?
621                      "Network game stopped due to internal error!" :
622                      "Network game stopped!");
623
624     if (buffer[2] != NETWORK_STOP_BY_PLAYER || stopped_by_remote_player)
625       Request(message, REQ_CONFIRM | REQ_STAY_CLOSED);
626   }
627
628   SetGameStatus(GAME_MODE_MAIN);
629
630   DrawMainMenu();
631 }
632
633 static void Handle_OP_MOVE_PLAYER(unsigned int len)
634 {
635   int server_frame_counter;
636   int i;
637
638   if (!network_playing)
639     return;
640
641   server_frame_counter =
642     (buffer[2] << 24) | (buffer[3] << 16) | (buffer[4] << 8) | (buffer[5]);
643
644   if (server_frame_counter != FrameCounter)
645   {
646     Error(ERR_INFO, "client and servers frame counters out of sync");
647     Error(ERR_INFO, "frame counter of client is %d", FrameCounter);
648     Error(ERR_INFO, "frame counter of server is %d", server_frame_counter);
649     Error(ERR_INFO, "this should not happen -- please debug");
650
651     stop_network_game = TRUE;
652
653     return;
654   }
655
656   /* copy valid player actions */
657   for (i = 0; i < MAX_PLAYERS; i++)
658     stored_player[i].effective_action =
659       (i < len - 6 ? buffer[6 + i] : 0);
660
661   network_player_action_received = TRUE;
662 }
663
664 static void HandleNetworkingMessages()
665 {
666   unsigned int message_length;
667
668   stop_network_game = FALSE;
669
670   while (nread >= 4 && nread >= 4 + readbuffer[3])
671   {
672     message_length = readbuffer[3];
673     if (readbuffer[0] || readbuffer[1] || readbuffer[2])
674       Error(ERR_EXIT, "wrong network server line length");
675
676     memcpy(buffer, &readbuffer[4], message_length);
677     nread -= 4 + message_length;
678     memmove(readbuffer, readbuffer + 4 + message_length, nread);
679
680     switch (buffer[1])
681     {
682       case OP_BAD_PROTOCOL_VERSION:
683         Handle_OP_BAD_PROTOCOL_VERSION();
684         break;
685
686       case OP_YOUR_NUMBER:
687         Handle_OP_YOUR_NUMBER();
688         break;
689
690       case OP_NUMBER_WANTED:
691         Handle_OP_NUMBER_WANTED();
692         break;
693
694       case OP_PLAYER_NAME:
695         Handle_OP_PLAYER_NAME(message_length);
696         break;
697
698       case OP_PLAYER_CONNECTED:
699         Handle_OP_PLAYER_CONNECTED();
700         break;
701       
702       case OP_PLAYER_DISCONNECTED:
703         Handle_OP_PLAYER_DISCONNECTED();
704         break;
705
706       case OP_START_PLAYING:
707         Handle_OP_START_PLAYING();
708         break;
709
710       case OP_PAUSE_PLAYING:
711         Handle_OP_PAUSE_PLAYING();
712         break;
713
714       case OP_CONTINUE_PLAYING:
715         Handle_OP_CONTINUE_PLAYING();
716         break;
717
718       case OP_STOP_PLAYING:
719         Handle_OP_STOP_PLAYING();
720         break;
721
722       case OP_MOVE_PLAYER:
723         Handle_OP_MOVE_PLAYER(message_length);
724         break;
725
726       case OP_BROADCAST_MESSAGE:
727         printf("OP_BROADCAST_MESSAGE: %d\n", buffer[0]);
728         Error(ERR_NETWORK_CLIENT, "client %d sends message", buffer[0]);
729         break;
730     }
731   }
732
733   fflush(stdout);
734
735   /* in case of internal error, stop network game */
736   if (stop_network_game)
737     SendToServer_StopPlaying(NETWORK_STOP_BY_ERROR);
738 }
739
740 static char *HandleNetworkingPackets()
741 {
742   while (1)
743   {
744     /* ---------- check network server for activity ---------- */
745
746     int num_active_sockets = SDLNet_CheckSockets(rfds, 1);
747
748     if (num_active_sockets < 0)
749       return "Error checking network sockets!";
750
751     if (num_active_sockets == 0)
752       break;    // no active sockets, stop here
753
754     /* ---------- read packets from network server ---------- */
755
756     int num_bytes = SDLNet_TCP_Recv(sfd, readbuffer + nread, 1);
757
758     if (num_bytes < 0)
759       return "Error reading from network server!";
760
761     if (num_bytes == 0)
762       return "Connection to network server lost!";
763
764     nread += num_bytes;
765
766     HandleNetworkingMessages();
767   }
768
769   return NULL;
770 }
771
772 static void HandleNetworkingDisconnect()
773 {
774   int i;
775
776   SDLNet_TCP_DelSocket(rfds, sfd);
777   SDLNet_TCP_Close(sfd);
778
779   network_playing = FALSE;
780
781   network.enabled = FALSE;
782   network.connected = FALSE;
783
784   setup.network_mode = FALSE;
785
786   for (i = 0; i < MAX_PLAYERS; i++)
787     stored_player[i].connected_network = FALSE;
788 }
789
790 void HandleNetworking()
791 {
792   char *error_message = HandleNetworkingPackets();
793
794   if (error_message != NULL)
795   {
796     HandleNetworkingDisconnect();
797
798     if (game_status == GAME_MODE_PLAYING)
799     {
800       Request(error_message, REQ_CONFIRM | REQ_STAY_CLOSED);
801
802       SetGameStatus(GAME_MODE_MAIN);
803
804       DrawMainMenu();
805     }
806     else
807     {
808       Request(error_message, REQ_CONFIRM);
809     }
810   }
811 }
812
813 void DisconnectFromNetworkServer()
814 {
815   DrawNetworkText_Title("Terminating Network");
816   DrawNetworkText("Disconnecting from network server ...");
817
818   HandleNetworkingDisconnect();
819
820   DrawNetworkText_Success("Successfully disconnected!");
821
822   /* short time to recognize result of network initialization */
823   Delay(1000);
824 }