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