1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or
5  *  (at your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *  GNU Library General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  */
16 
17 #include "hugod.h"
18 
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include "netplay.h"
22 #include <getopt.h>
23 #include "gtk_main-server.h"
24 
25 #define DEBUG
26 
27 #if defined(GTK)
28 static const int GTK_SERVER_SOCKET_RATIO = 100;
29 static int gtk_iteration = 1;
30 #endif
31 
32 #if !defined(GTK)
printf_screen(char * format,...)33 void printf_screen (char* format, ...)
34 {
35   char buf[256];
36   GtkTextView* textview_status = NULL;
37 
38   va_list ap;
39   va_start (ap, format);
40   vsprintf (buf, format, ap);
41   va_end (ap);
42 
43   vprintf(format, ap);
44 }
45 #endif
46 
47 
48 /*!
49  * Sets the global options from the command line arguments
50  * \param argc number of command line arguments
51  * \param argv content of command line arguments
52  * \param global_option pointer to the global option structure
53  * \return 0 in case of success
54  */
55 int
read_arguments(int argc,char * argv[],global_option_type * global_option)56 read_arguments (int argc, char *argv[], global_option_type * global_option)
57 {
58   int option;
59 
60   for (;;)
61     {
62       option = getopt (argc, argv, "p:P:il");
63 
64       if (option == -1)
65 	{
66 	  break;
67 	}
68 
69       switch (option)
70 	{
71 	case 'p':
72 	  if ((atoi (optarg) >= MAX_NUMBER_PLAYER)
73 	      || (atoi (optarg) < MIN_NUMBER_PLAYER))
74 	    {
75 	      printf_screen ("Error: invalid number of players (%d not in [1-5])\n",
76 			     atoi (optarg));
77 	      return 1;
78 	    }
79 	  printf_screen("Opening %d slot%s\n", atoi(optarg), atoi(optarg) > 1 ? "s": "");
80 	  global_option->number_player = atoi (optarg);
81 	  break;
82 	case 'P':
83 	  global_option->server_port = atoi (optarg);
84 	  break;
85 	case 'i':
86 	  printf_screen("Setting INTERNET protocol\n");
87 	  global_option->type_server = INTERNET_PROTOCOL_TYPE;
88 	  break;
89 	case 'l':
90 	  printf_screen("Setting LAN protocol\n");
91 	  global_option->type_server = LAN_PROTOCOL_TYPE;
92 	  break;
93 	case '?':
94 	  // getopt already output an error version, it's enough
95 	  break;
96 	default:
97 	  printf_screen("Unknown command line option : %c\n", option);
98 	  break;
99 	}
100     }
101 
102   return 0;
103 
104 }
105 
106 /*!
107  * Side effect free minimum computation
108  */
109 static int
min(int lhs,int rhs)110 min (int lhs, int rhs)
111 {
112   return (lhs < rhs) ? lhs : rhs;
113 }
114 
115 /*!
116  * main loop. Accept contribution from clients and dispatch digest of
117  * the frame to all clients
118  */
119 void
serve_dispatch(global_option_type * global_option)120 serve_dispatch (global_option_type * global_option)
121 {
122 
123   global_status_type global_status;
124   int client_index;
125 
126   /*
127    * Initialize global_status fields
128    */
129   global_status.frame_number = 1;
130   global_status.number_identified_players = 0;
131   global_status.number_allocation_request = 0;
132 #if defined(GTK)
133 	gtk_stop_asked = FALSE;
134 #endif
135 
136   for (client_index = 0; client_index < MAX_NUMBER_PLAYER; client_index++)
137     {
138       global_status.player_status[client_index] = UNIDENTIFIED;
139     }
140 
141   global_status.server_socket = SDLNet_UDP_Open (global_option->server_port);
142   if (global_status.server_socket == NULL)
143     {
144       printf_screen ("Couldn't open UDP socket on port %d.\nCheck privileges and availability.\n",
145 		     global_option->server_port);
146       return;
147     }
148 
149   /* global_status.server_socket is ready to serve our needs :) */
150 
151   global_status.current_packet = SDLNet_AllocPacket (CLIENT_PACKET_SIZE);
152 
153   if (global_status.current_packet == NULL)
154     {
155       SDLNet_UDP_Close (global_status.server_socket);
156       printf_screen ("Failed to allocate a buffer for receiving client packets (size: %d bytes) (Not enough memory ?)",
157 		     CLIENT_PACKET_SIZE);
158       return;
159     }
160 
161   global_status.digest_packet = SDLNet_AllocPacket (SERVER_PACKET_SIZE);
162 
163   if (global_status.digest_packet == NULL)
164     {
165       SDLNet_UDP_Close (global_status.server_socket);
166       SDLNet_FreePacket (global_status.digest_packet);
167       printf_screen ("Failed to allocate a buffer for sending packets (size: %d bytes) (Not enough memory ?)",
168 		     SERVER_PACKET_SIZE);
169       return;
170     }
171 
172   /* Allocate enough space for a single socket */
173   global_status.server_socket_set = SDLNet_AllocSocketSet (1);
174 
175   if (global_status.server_socket_set == NULL)
176     {
177       SDLNet_UDP_Close (global_status.server_socket);
178       SDLNet_FreePacket (global_status.current_packet);
179       SDLNet_FreePacket (global_status.digest_packet);
180       printf_screen ("Couldn't allocate a socket set (not enough memory ?).\n");
181       return;
182     }
183 
184   if (SDLNet_UDP_AddSocket (global_status.server_socket_set, global_status.server_socket) !=
185       1)
186     {
187       SDLNet_UDP_Close (global_status.server_socket);
188       SDLNet_FreePacket (global_status.current_packet);
189       SDLNet_FreePacket (global_status.digest_packet);
190       SDLNet_FreeSocketSet (global_status.server_socket_set);
191       printf_screen ("Error when adding socket to socket set.\n");
192       return;
193     }
194 
195   /* Identification loop */
196 
197   /*
198    * We're expecting identification packets until we've filled all slots, then
199    * we can proceed to the real meat
200    */
201 
202   for (;;)
203     {
204 
205       int number_ready_socket;
206 
207 #if defined(DEBUG)
208       printf_screen ("Waiting for identification\n");
209 #endif
210 
211 
212       if (read_incoming_server_packet (&global_status))
213 	{
214 	  identify_client (&global_status, global_option);
215 
216 	  if (count_remaining_slot (&global_status, global_option) == 0)
217 	    {
218 	      /* Perfect, we've finished the identification of all slots */
219 	      break;
220 	    }
221 
222 	  printf_screen("%d slots open.\n", count_remaining_slot (&global_status, global_option));
223 
224 	  /* Going back to the identification loop */
225 	  continue;
226 
227 	}
228 
229 #if defined(GTK)
230 
231       gtk_iteration = GTK_SERVER_SOCKET_RATIO;
232 
233       do {
234 	number_ready_socket =
235 	  SDLNet_CheckSockets (global_status.server_socket_set, SERVER_SOCKET_TIMEOUT / GTK_SERVER_SOCKET_RATIO);
236 
237 	while (gtk_events_pending())
238 	{
239 	  if (gtk_main_iteration())
240 	  {
241 	  	gtk_stop_asked = TRUE;
242 	  }
243 	}
244       } while ( (number_ready_socket == 0) && (--gtk_iteration != 0) && !gtk_stop_asked);
245 #else
246 
247       number_ready_socket =
248 	SDLNet_CheckSockets (global_status.server_socket_set, SERVER_SOCKET_TIMEOUT);
249 
250 #endif
251 
252 	if (gtk_stop_asked)
253 	{
254 		break;
255 	}
256 
257       if (number_ready_socket == -1)
258 	{
259 	  printf_screen ("Error in socket waiting (disconnection ?).\n");
260 	  break;
261 	}
262 
263       if (number_ready_socket == 1)
264 	{
265 
266 #if defined(DEBUG)
267 	  printf_screen ("Got a packet\n");
268 #endif
269 
270 	  /* We're awaiting a packet in the server socket */
271 	  if (read_incoming_server_packet (&global_status))
272 	    {
273 
274 	      /*
275 	       * If we haven't identified all clients yet, we're trying to use the current packet
276 	       * to improve our knowledge of the typography
277 	       */
278 	      identify_client (&global_status, global_option);
279 
280 	      if (count_remaining_slot (&global_status, global_option) == 0)
281 		{
282 		  /* Perfect, we've finished the identification of all slots */
283 		  break;
284 		}
285 
286 	      printf_screen("%d slots open.\n", count_remaining_slot (&global_status, global_option));
287 
288 	    }
289     }
290 
291 
292 	}
293 
294 	if (!gtk_stop_asked)
295 	{
296 
297   printf_screen ("Identification finished\n");
298 
299 #if defined(DEBUG)
300   for (client_index = 0; client_index < MAX_NUMBER_PLAYER; client_index++)
301     {
302       printf_screen ("Mapping[%d] = { { 0x%08X, %d }, %d }\n", client_index,
303 		     global_status.input_mapping[client_index].address.host,
304 		     global_status.input_mapping[client_index].address.port,
305 		     global_status.input_mapping[client_index].remote_input_device);
306     }
307 #endif
308 
309   switch (global_option->type_server)
310     {
311     case LAN_PROTOCOL_TYPE:
312       serve_clients_lan_protocol(&global_status, global_option);
313       break;
314     case INTERNET_PROTOCOL_TYPE:
315       serve_clients_internet_protocol(&global_status, global_option);
316       break;
317     default:
318       printf_screen("Internal error, unknown internal server type : %d\n", global_option->type_server);
319       break;
320     }
321   } // gtk_stop_asked
322 
323   /*
324    * Free resources
325    */
326   SDLNet_FreePacket (global_status.current_packet);
327   SDLNet_FreePacket (global_status.digest_packet);
328   SDLNet_FreeSocketSet (global_status.server_socket_set);
329   SDLNet_UDP_Close (global_status.server_socket);
330   global_status.server_socket = NULL;
331 
332 }
333 
334 int
main(int argc,char * argv[])335 main (int argc, char *argv[])
336 {
337   global_option_type global_option;	//!< Application global options
338 
339   global_option.server_port = DEFAULT_SERVER_PORT;
340   global_option.number_player = MAX_NUMBER_PLAYER;
341   global_option.type_server = LAN_PROTOCOL_TYPE;
342 
343 #if defined(DEBUG)
344   fprintf (stderr, "DEBUG mode is ON\n");
345 #endif
346 
347   if (read_arguments (argc, argv, &global_option) != 0)
348     {
349       fprintf (stderr, "Error reading arguments\n");
350       return 2;
351     }
352 
353   if (SDL_Init (0) == -1)
354     {
355       fprintf (stderr, "SDL_Init: %s\n", SDL_GetError ());
356       return 1;
357     }
358 
359   if (init_network () != 0)
360     {
361       fprintf (stderr, "Error initializing network\n");
362       return 1;
363     }
364 
365 #if defined(GTK)
366 
367 	if (argc == 1)
368 	{
369 		// No option given starts the GUI
370 		build_gtk_interface(argc, argv);
371 		return;
372 	}
373 
374 #endif
375 
376   serve_dispatch (&global_option);
377 
378   shutdown_network ();
379 
380   SDL_Quit();
381 
382   return 0;
383 
384 }
385