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