1 /*
2 * file server.c - communication interface for the server
3 *
4 * $Id: server.c,v 1.79 2006/03/28 11:41:19 fzago Exp $
5 *
6 * Program XBLAST
7 * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2; or (at your option)
12 * any later version
13 *
14 * This program is distributed in the hope that it will be entertaining,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17 * Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include "xblast.h"
25
26 /*
27 * local variables
28 */
29
30 /* Server connections */
31 static XBComm *listenComm = NULL; /* XBCommListen - TCP listen for clients */
32 static XBComm *replyComm = NULL; /* XBCommReply - UDP LAN reply */
33 static XBComm **query = NULL; /* XBCommNewGame - UDP connection to central */
34
35 /* default server options */
36 static CFGGame cfgGame;
37
38 /* player actions received for expected gametime */
39 static PlayerAction playerAction[MAX_HOSTS][MAX_PLAYER];
40
41 /* level negotiation states per host */
42 static unsigned levelStatus[MAX_HOSTS];
43
44 /* levelwinners per host */
45 static unsigned levelWinner[MAX_HOSTS];
46 static char levelWinnerStr[3 * MAX_HOSTS + 1];
47 static unsigned currentWinner = TEAM_UNDEF;
48
49 /* server flag, unneeded ? */
50 static XBBool isServer = XBFalse;
51
52 /***************************
53 * starting/closing server *
54 ***************************/
55
56 /*
57 * start listening for clients
58 *
59 * should always be start for server!
60 */
61 XBBool
Server_StartListen(CFGGameHost * cfg)62 Server_StartListen (CFGGameHost * cfg)
63 {
64 unsigned char p;
65 /* init network/chat */
66 Dbg_Server ("clearing all network and chat data\n");
67 Network_Clear ();
68 Network_ClearEvents ();
69 Chat_Clear ();
70 /* listen on tcp-port for clients */
71 assert (listenComm == NULL);
72 listenComm = CommCreateListen (cfg, XBFalse);
73 if (NULL == listenComm) {
74 Dbg_Server ("failed to listen for clients on TCP port %u\n", cfg->port);
75 return XBFalse;
76 }
77 Dbg_Server ("listening for clients on port %u\n", cfg->port);
78 /* receive local host id */
79 Network_ReceiveLocalHostId (0);
80 /* get game config data from database Local/Server */
81 if (!RetrieveGame (CT_Local, atomServer, &cfgGame)) {
82 Dbg_Server ("failed to get local game config!\n");
83 Network_Clear ();
84 Network_ClearEvents ();
85 return XBFalse;
86 }
87 /* simulate game config receive from network */
88 StoreGame (CT_Remote, SERVERGAMECONFIG, &cfgGame);
89 /* now receive terminator like client */
90 if (!Server_ReceiveGameConfig (0, NULL)) {
91 Dbg_Server ("listen failed, local game config error\n");
92 Network_Clear ();
93 Network_ClearEvents ();
94 return XBFalse;
95 }
96 /* receive local player configs */
97 for (p = 0; p < cfgGame.players.num; p++) {
98 if (!Server_ReceivePlayerConfig (0, p, NULL)) {
99 Dbg_Server ("failed to setup local player #%u\n", p);
100 Network_Clear ();
101 Network_ClearEvents ();
102 return XBFalse;
103 }
104 }
105 /* receive ping */
106 Server_ReceivePing (0, 0);
107 /* allow clients to browse for games */
108 if (cfg->browseLan) {
109 assert (NULL == replyComm);
110 replyComm = Reply_CreateComm (16168, cfg, &cfgGame.setup);
111 if (NULL == replyComm) {
112 Dbg_Server ("failed to open reply socket, not visible in LAN\n");
113 }
114 }
115 Dbg_Server ("listening for LAN queries on UDP port %u\n", 16168);
116 /* force stop on old query sockets - unlikely that they are still active, but not impossible */
117 if (query != NULL) {
118 Dbg_Server ("removing old query sockets\n");
119 Server_StopNewGame ();
120 }
121 /* registering game at central */
122 if (cfg->central) {
123 Dbg_Server ("attempting to register game\n");
124 Server_StartCentralNewGame (cfg, &cfgGame.setup);
125 }
126 Dbg_Server ("marking as server\n");
127 isServer = XBTrue; /* needed for old code, remove some time */
128 assert (XBNT_None == Network_GetType ());
129 Network_SetType (XBNT_Server);
130 /* listen for local chat keys */
131 Chat_Listen (XBTrue);
132 /* that's all */
133 return XBTrue;
134 } /* Server_StartListen */
135
136 /*
137 * remove listen ports
138 */
139 void
Server_StopListen(void)140 Server_StopListen (void)
141 {
142 /* delete listen port */
143 assert (NULL != listenComm);
144 CommFinishListen (listenComm);
145 /* should trigger Server_ReceiveListenClose() */
146 assert (listenComm == NULL);
147 /* delete reply socket */
148 if (NULL != replyComm) {
149 CommDelete (replyComm);
150 replyComm = NULL;
151 Dbg_Server ("stopped listening for LAN queries\n");
152 }
153 } /* Server_StopListen */
154
155 /*
156 * listen socket is closed down
157 */
158 void
Server_ReceiveListenClose(XBBool exp)159 Server_ReceiveListenClose (XBBool exp)
160 {
161 listenComm = NULL;
162 if (exp) {
163 Dbg_Server ("stopped listening for clients\n");
164 }
165 else {
166 Dbg_Server ("unexpected shutdown of listen socket\n");
167 /* do something appropriate */
168 }
169 } /* Server_ReceiveListenClose */
170
171 /****************************
172 * connecting/disconnecting *
173 ****************************/
174
175 /*
176 * a client has connected to server
177 */
178 void
Server_Accept(unsigned id,const char * hostName,unsigned port)179 Server_Accept (unsigned id, const char *hostName, unsigned port)
180 {
181 CFGGameHost cfg;
182 time_t ltime;
183
184 assert (hostName != NULL);
185 assert (id > 0);
186 assert (id < MAX_HOSTS);
187 /* produce beep if wanted */
188 time (<ime);
189 if (cfgGame.host.beep) {
190 SND_Beep ();
191 }
192 fprintf (stderr, "\n%s client adr=%s:%u id=%u connected\n", ctime (<ime), hostName, port, id);
193 /* store in database */
194 Dbg_Server ("setting up initial game config for host #%u\n", id);
195 memset (&cfg, 0, sizeof (cfg));
196 cfg.name = hostName;
197 cfg.port = port;
198 StoreGameHost (CT_Remote, LOCALGAMECONFIG (id), &cfg);
199 /* attempt to start dgram */
200 if (NULL == D2C_CreateComm (id, S2C_LocalName (id), cfgGame.host.fixedUdpPort)) {
201 Dbg_Server ("failed to create udp socket for host #%u, disconnecting !!\n", id);
202 Server_StreamDisconnect (id);
203 return;
204 }
205 Dbg_Server ("created udp socket for host #%u on port %u\n", id, D2C_Port (id));
206 /* respond to client now */
207 Server_SendAllConfigs (id);
208 Server_SendDgramPort (id);
209 Server_QueryGameConfig (id);
210 Network_QueueEvent (XBNW_Accepted, id);
211 } /* Server_Accept */
212
213 /*
214 * initiate stream shut down - send the disconnect signal and mark waiting EOF
215 * the stream and its host slot will be freed on receivng eof/error
216 */
217 void
Server_StreamDisconnect(unsigned clientID)218 Server_StreamDisconnect (unsigned clientID)
219 {
220 assert (clientID > 0);
221 assert (clientID < MAX_HOSTS);
222 if (S2C_Connected (clientID)) {
223 Dbg_Server ("queueing TCP disconnect sequence to host #%u\n", clientID);
224 S2C_Disconnect (clientID);
225 }
226 } /* Server_StreamDisconnect */
227
228 /*
229 * makes dgram slot available for new clients
230 * the dgram data structure is completely removed
231 */
232 void
Server_DgramDisconnect(unsigned clientID)233 Server_DgramDisconnect (unsigned clientID)
234 {
235 assert (clientID > 0);
236 assert (clientID < MAX_HOSTS);
237 if (D2C_Connected (clientID)) {
238 Dbg_Server ("disconnecting UDP to host #%u\n", clientID);
239 D2C_Disconnect (clientID);
240 }
241 } /* Server_DgramDisconnect */
242
243 /*
244 * active freeing of the client slot
245 * informs other clients and local GUI
246 */
247 void
Server_SendDisconnect(unsigned clientID)248 Server_SendDisconnect (unsigned clientID)
249 {
250 if (clientID > 0) {
251 Server_StreamDisconnect (clientID);
252 Server_DgramDisconnect (clientID);
253 Server_SendDisconnectInfo (clientID);
254 Network_ClearHost (clientID);
255 Network_QueueEvent (XBNW_Disconnected, clientID);
256 }
257 else {
258 Server_SendDisconnectAll ();
259 }
260 } /* Server_SendDisconnect */
261
262 /*
263 * active shutdown of server
264 * all slots are cleared
265 */
266 void
Server_SendDisconnectAll(void)267 Server_SendDisconnectAll (void)
268 {
269 unsigned clientID;
270 /* disconnect from clients */
271 for (clientID = 1; clientID < MAX_HOSTS; clientID++) {
272 Server_StreamDisconnect (clientID);
273 Server_DgramDisconnect (clientID);
274 }
275 if (NULL != query) {
276 Dbg_Server ("queuing close to central, mark for shutdown after send\n");
277 Server_CloseNewGame ();
278 }
279 if (listenComm == NULL) {
280 Network_SetType (XBNT_None);
281 }
282 Network_Clear ();
283 Network_ClearEvents ();
284 Dbg_Server ("*** all data completely cleared ***\n");
285 Chat_Listen (XBFalse);
286 } /* Server_SendDisconnectAll */
287
288 /*
289 * disconnect all clients that are out
290 */
291 static void
Server_SendDisconnectOut(void)292 Server_SendDisconnectOut (void)
293 {
294 unsigned id;
295 for (id = 1; id < MAX_HOSTS; id++) {
296 if (!Network_HostIsIn (id)) {
297 Dbg_Server ("disconnecting host #%i, is out\n", id);
298 Server_SendDisconnect (id);
299 }
300 }
301 } /* Server_SendDisconnectOut */
302
303 /***************
304 * comm events *
305 ***************/
306
307 /*
308 * handle event on stream
309 */
310 XBBool
Server_StreamEvent(unsigned clientID,XBServerConstants code)311 Server_StreamEvent (unsigned clientID, XBServerConstants code)
312 {
313 assert (clientID > 0);
314 assert (clientID < MAX_HOSTS);
315 switch (code) {
316 case XBSC_IDInvalid:
317 Dbg_Server ("invalid id received from host #%u, ignoring\n", clientID);
318 return XBFalse;
319 case XBSC_DataInvalid:
320 Dbg_Server ("invalid data received from host #%u, ignoring\n", clientID);
321 return XBFalse;
322 case XBSC_COTInvalid:
323 Dbg_Server ("invalid cot received from host #%u, sending disconnect\n", clientID);
324 Server_StreamDisconnect (clientID);
325 Server_SendDisconnectInfo (clientID);
326 return XBFalse;
327 case XBSC_MissingData:
328 Dbg_Server ("host #%u has not requested data\n", clientID);
329 return XBFalse;
330 case XBSC_IOError:
331 Dbg_Server ("i/o error on stream to host #%u, disconnecting\n", clientID);
332 Server_SendDisconnectInfo (clientID);
333 break;
334 case XBSC_UnexpectedEOF:
335 Dbg_Server ("unexpected eof on stream to host #%u, disconnecting\n", clientID);
336 Server_SendDisconnectInfo (clientID);
337 break;
338 case XBSC_StreamWaiting:
339 Dbg_Server ("all queued data sent to host #%u\n", clientID);
340 return XBFalse;
341 case XBSC_StreamBusy:
342 /* Dbg_Server("data waits to be sent to host #%u\n", clientID); */
343 return XBFalse;
344 case XBSC_StreamClosed:
345 Dbg_Server ("stream to host #%u fully disconnected\n", clientID);
346 return XBFalse;
347 default:
348 Dbg_Server ("unknown event (%u) on stream to host #%u, disconnecting\n", code, clientID);
349 }
350 /* remove dgram if still there */
351 Server_DgramDisconnect (clientID);
352 /* clear host data */
353 Network_ClearHost (clientID);
354 /* queue event for GUI display */
355 Network_QueueEvent (XBNW_Error, clientID); /* more info for GUI */
356 return XBTrue;
357 } /* Server_StreamEvent */
358
359 /*
360 * handle event on dgram
361 */
362 XBBool
Server_DgramEvent(unsigned clientID,XBServerConstants code)363 Server_DgramEvent (unsigned clientID, XBServerConstants code)
364 {
365 assert (clientID > 0);
366 assert (clientID < MAX_HOSTS);
367 switch (code) {
368 case XBSC_GameTime:
369 Dbg_Server ("future gametimes from host #%u received, ignoring\n", clientID);
370 return XBFalse;
371 case XBSC_WriteError:
372 Dbg_Server ("write error on dgram to host #%u, disconnecting\n", clientID);
373 break;
374 case XBSC_ConnFailed:
375 Dbg_Server ("dgram failed to connect to host #%u, disconnecting\n", clientID);
376 break;
377 case XBSC_Timeout:
378 Dbg_Server ("dgram to host #%u timed out, disconnecting\n", clientID);
379 Server_DgramDisconnect (clientID);
380 break;
381 case XBSC_DgramClosed:
382 Dbg_Server ("dgram to host #%u removed\n", clientID);
383 return XBFalse;
384 default:
385 Dbg_Server ("unknown event (%u) on dgram to host #%u, disconnecting\n", code, clientID);
386 }
387 /* initiate disconnection of stream */
388 Server_StreamDisconnect (clientID);
389 Server_SendDisconnectInfo (clientID);
390 /* clear host data */
391 Network_ClearHost (clientID);
392 /* queue event for GUI display */
393 Network_QueueEvent (XBNW_Error, clientID);
394 return XBTrue;
395 } /* Server_DgramDisconnect */
396
397 /******************
398 * receiving data *
399 ******************/
400
401 /*
402 * game config received from host
403 */
404 XBBool
Server_ReceiveGameConfig(unsigned id,const char * line)405 Server_ReceiveGameConfig (unsigned id, const char *line)
406 {
407 unsigned num;
408 assert (id < MAX_HOSTS);
409 /* receive the data */
410 switch (Network_ReceiveGameConfig (id, line)) {
411 case XBGC_Unfinished:
412 return XBFalse;
413 case XBGC_Empty:
414 Dbg_Server ("host #%u sent empty game config, disconnect\n", id);
415 Server_SendDisconnect (id);
416 return XBFalse;
417 case XBGC_TooManyPlayers:
418 Dbg_Server ("host #%u sent too many players, disconnect\n", id);
419 Server_SendDisconnect (id);
420 return XBFalse;
421 case XBGC_NoVersion:
422 Dbg_Server ("host #%u sent no version, disconnect\n", id);
423 Server_SendDisconnect (id);
424 return XBFalse;
425 case XBGC_Local:
426 Dbg_Server ("host #%u sent local game config\n", id);
427 num = Network_CreateLocalPlayers (id);
428 if (num >= NUM_LOCAL_PLAYER) {
429 Dbg_Server ("failed to create local players, disconnect\n");
430 Server_SendDisconnect (id);
431 return XBFalse;
432 }
433 Dbg_Server ("created %u players at host #%u\n", num, id);
434 Server_SendGameConfig (id);
435 Server_QueryPlayerConfigs (id, num);
436 Server_ReceiveHostStateReq (0, id, XBHS_Wait);
437 Network_QueueEvent (XBNW_GameConfig, id);
438 return XBTrue;
439 case XBGC_Global:
440 Dbg_Server ("host #%u sent global game config\n", id);
441 if (id > 0) {
442 Dbg_Server ("ignoring global game config from client\n");
443 DeleteGameConfig (CT_Remote, LOCALGAMECONFIG (id));
444 return XBFalse;
445 }
446 num = Network_CreateGlobalPlayers (id);
447 if (num > MAX_PLAYER) {
448 Dbg_Server ("failed to create global players, stop\n");
449 Server_SendDisconnect (id);
450 Network_QueueEvent (XBNW_Error, id);
451 return XBFalse;
452 }
453 num = Network_GetMaskBytes ();
454 if (num == 0) {
455 Dbg_Server ("failed to set mask bytes, stop\n");
456 Server_SendDisconnect (id);
457 Network_QueueEvent (XBNW_Error, id);
458 return XBFalse;
459 }
460 D2C_SetMaskBytes (num);
461 Dbg_Server ("created %u global players from game config #%u\n", num, id);
462 return XBTrue;
463 case XBGC_Error:
464 Dbg_Server ("host #%u sent invalid game config, disconnect\n", id);
465 Server_SendDisconnect (id);
466 return XBFalse;
467 default:
468 break;
469 }
470 return XBFalse;
471 } /* Server_ReceiveGameConfig */
472
473 /*
474 * player config received from client
475 */
476 XBBool
Server_ReceivePlayerConfig(unsigned id,int player,const char * line)477 Server_ReceivePlayerConfig (unsigned id, int player, const char *line)
478 {
479 XBAtom atom, name, full;
480 CFGPlayer cfgPlayer;
481 if (id == 0) {
482 Dbg_Server ("local player config transfer #%u\n", player);
483 full = Network_GetPlayer (0, player);
484 if (full == ATOM_INVALID) {
485 Dbg_Server ("local player #%u not registered\n", player);
486 return XBFalse;
487 }
488 name = Network_GetPlayer2 (0, player);
489 if (name == ATOM_INVALID) {
490 Dbg_Server ("local player name #%u not registered\n", player);
491 return XBFalse;
492 }
493 if (!RetrievePlayer (CT_Local, name, cfgGame.players.teamColor[player], &cfgPlayer)) {
494 Dbg_Server ("incomplete data for player #%u\n", player);
495 return XBFalse;
496 }
497 StorePlayer (CT_Remote, full, &cfgPlayer);
498 line = NULL;
499 }
500 /* store player for config */
501 atom = Network_ReceivePlayerConfig (CT_Remote, id, player, line);
502 /* if atom is valid, data is complete */
503 if (ATOM_INVALID != atom) {
504 Dbg_Server ("player config for host #%u(%u) received\n", id, player);
505 /* send player config of id to other clients */
506 Server_SendPlayerConfig (id, player);
507 /* initial team state */
508 Server_ReceiveTeamStateReq (0, id, player, cfgGame.setup.teamMode ? XBTS_Red : XBTS_None);
509 return XBTrue;
510 }
511 return XBFalse;
512 } /* Server_ReceivePlayerConfig */
513
514 /*
515 * client has sent dgram port
516 */
517 void
Server_ReceiveDgramPort(unsigned id,unsigned short port)518 Server_ReceiveDgramPort (unsigned id, unsigned short port)
519 {
520 /* set port for datagram conection */
521 if (0 != port || cfgGame.host.allowNat) {
522 if (port == 0) {
523 Dbg_Server ("client at %s reports NAT, setting up dgram\n", S2C_HostName (id));
524 }
525 else {
526 Dbg_Server ("received dgram port %u for host #%u, connecting dgram\n", port, id);
527 }
528 if (!D2C_Connect (id, S2C_HostName (id), port)) {
529 Dbg_Server ("failed to connect dgram\n");
530 Server_SendDisconnect (id);
531 }
532 }
533 else {
534 Dbg_Server ("client has NAT, disallowed\n");
535 Server_SendDisconnect (id);
536 }
537 } /* Server_ReceiveDgramPort */
538
539 /*
540 * receive and resend host state changes, local use only
541 */
542 static void
Server_ReceiveHostState(unsigned id,XBHostState state)543 Server_ReceiveHostState (unsigned id, XBHostState state)
544 {
545 if (Network_ReceiveHostState (id, state)) {
546 Server_SendHostState (id, state);
547 }
548 else {
549 Dbg_Server ("received invalid host state\n");
550 }
551 } /* Server_ReceiveHostState */
552
553 /*
554 * return if host state request from id for host to state is granted
555 */
556 static XBBool
Server_GrantsHostRequest(unsigned id,unsigned host,XBHostState state)557 Server_GrantsHostRequest (unsigned id, unsigned host, XBHostState state)
558 {
559 /* never grant the None request */
560 if (state == XBHS_None) {
561 return XBFalse;
562 }
563 /* distinguish server and client requests */
564 if (id == 0) {
565 /* grant any server request unless request equals current */
566 return (Network_GetHostState (host) != state);
567 }
568 else if (id == host) {
569 /* grant certain client requests for self */
570 switch (Network_GetHostState (host)) {
571 case XBHS_Ready:
572 return (state == XBHS_In);
573 case XBHS_In:
574 return (state == XBHS_Ready);
575 default:
576 return XBFalse;
577 }
578 }
579 return XBFalse;
580 } /* Server_GrantsHostRequest */
581
582 /*
583 * receive host state request from id for host to state
584 */
585 void
Server_ReceiveHostStateReq(unsigned id,unsigned host,XBHostState state)586 Server_ReceiveHostStateReq (unsigned id, unsigned host, XBHostState state)
587 {
588 XBHostState *req;
589 /* translate In to Srv for server */
590 if (host == 0 && state == XBHS_In) {
591 state = XBHS_Server;
592 }
593 /* check if request is valid */
594 if (Network_ReceiveHostStateReq (id, host, state)) {
595 /* first send request data to all clients */
596 Server_SendHostStateReq (id, host, state);
597 /* check if request is granted */
598 if (Server_GrantsHostRequest (id, host, state)) {
599 Dbg_Server ("granting host request #%u->%u from #%u\n", host, state, id);
600 Server_ReceiveHostState (host, state);
601 }
602 /* reprocess host's request */
603 req = Network_GetHostStateReq (host);
604 if (Server_GrantsHostRequest (host, host, req[host])) {
605 Dbg_Server ("granting reprocessed host request #%u->%u from #%u\n", host, req[host],
606 host);
607 Server_ReceiveHostState (host, req[host]);
608 }
609 /* clients agree on a host state */
610 if (Network_HostReqClientsAgree (host, state)) {
611 /* all clients!=host request out for host, grant unless host = server */
612 if (state == XBHS_Out && id != 0) {
613 Dbg_Server ("granting disconnect request of clients for host #%u!!\n", host);
614 Server_SendDisconnect (host);
615 return;
616 }
617 }
618 /* check if all clients are ready */
619 if (Network_ClientsReady () && Network_GetHostState (0) == XBHS_Ready) {
620 Dbg_Server ("all hosts are ready, starting game!!\n");
621 Network_QueueEvent (XBNW_StartGame, 0);
622 }
623 }
624 else {
625 Dbg_Server ("received invalid host state request\n");
626 }
627 } /* Server_ReceiveHostStateReq */
628
629 /*
630 * receive and resend team state change, local use only
631 */
632 static void
Server_ReceiveTeamState(unsigned id,unsigned player,XBTeamState state)633 Server_ReceiveTeamState (unsigned id, unsigned player, XBTeamState state)
634 {
635 if (Network_ReceiveTeamState (id, player, state)) {
636 Server_SendTeamState (id, player, state);
637 }
638 else {
639 Dbg_Server ("received invalid team state\n");
640 }
641 } /* Server_ReceiveTeamState */
642
643 /*
644 * return if team request from id for host to state is granted
645 */
646 static XBBool
Server_GrantsTeamRequest(unsigned id,unsigned host,unsigned player,XBTeamState state)647 Server_GrantsTeamRequest (unsigned id, unsigned host, unsigned player, XBTeamState state)
648 {
649 if (id == 0) {
650 /* grant any server request for server */
651 Dbg_Server ("granting team request #%u: #%u(%u)->%u\n", id, host, player, state);
652 return XBTrue;
653 }
654 else if (Network_TeamReqClientsAgree (host, player, state)) {
655 /* grant client request if they agree */
656 Dbg_Server ("granting joint team request #%u(%u)->%u\n", host, player, state);
657 return XBTrue;
658 }
659 return XBFalse;
660 } /* Server_GrantsTeamRequest */
661
662 /*
663 * receive team state request from id for host:player to state
664 */
665 void
Server_ReceiveTeamStateReq(unsigned id,unsigned host,unsigned player,XBTeamState state)666 Server_ReceiveTeamStateReq (unsigned id, unsigned host, unsigned player, XBTeamState state)
667 {
668 unsigned i, p;
669 /* first check for valid request */
670 if (!Network_ReceiveTeamStateReq (id, host, player, state)) {
671 Dbg_Server ("received invalid team state request\n");
672 }
673 /* send valid request data to all hosts */
674 Server_SendTeamStateReq (id, host, player, state);
675 /* process request */
676 if (!Server_GrantsTeamRequest (id, host, player, state)) {
677 Dbg_Server ("team request #%u: #%u(%u)->%u denied\n", id, host, player, state);
678 return;
679 }
680 /* check if player is requested out, no mode change */
681 if (state == XBTS_Out) {
682 Dbg_Server ("setting player %u(%u) out\n", host, player);
683 Server_ReceiveTeamState (host, player, state);
684 return;
685 }
686 /* check for change to chaos mode */
687 if (cfgGame.setup.teamMode && (state == XBTS_None)) {
688 /* change to chaos, first set new team defaults */
689 Network_SetDefaultTeams (host, player);
690 /* set requested host/player explicitly to none */
691 Server_ReceiveTeamState (host, player, XBTS_None);
692 /* set all players with valid team to none */
693 for (i = 0; i < MAX_HOSTS; i++) {
694 for (p = 0; p < NUM_LOCAL_PLAYER; p++) {
695 state = Network_GetTeamState (i, p);
696 if (state > XBTS_None && state < XBTS_Out) {
697 Server_ReceiveTeamState (i, p, XBTS_None);
698 }
699 }
700 }
701 Dbg_Server ("changed to chaos mode!\n");
702 cfgGame.setup.teamMode = XBFalse;
703 return;
704 }
705 /* check for change to team mode */
706 if (!cfgGame.setup.teamMode && (state > XBTS_None)) {
707 /* change to default teams */
708 for (i = 0; i < MAX_HOSTS; i++) {
709 for (p = 0; p < NUM_LOCAL_PLAYER; p++) {
710 if (Network_GetTeamState (i, p) == XBTS_None) {
711 Server_ReceiveTeamState (i, p, Network_GetDefaultTeam (i, p));
712 }
713 }
714 }
715 Dbg_Server ("changed to team mode!\n");
716 cfgGame.setup.teamMode = XBTrue;
717 return;
718 }
719 /* no team mode change */
720 Dbg_Server ("setting player %u(%u) = %u\n", host, player, state);
721 Server_ReceiveTeamState (host, player, state);
722 } /* Server_ReceiveTeamStateReq */
723
724 /*
725 * server received chat from a client
726 */
727 void
Server_ReceiveChat(XBChat * chat)728 Server_ReceiveChat (XBChat * chat)
729 {
730 Chat_Receive (chat);
731 Server_SendChat (chat);
732 } /* Server_ReceiveChat */
733
734 /*
735 * ping received, tell network
736 */
737 void
Server_ReceivePing(unsigned id,int ping)738 Server_ReceivePing (unsigned id, int ping)
739 {
740 Dbg_Server ("received ping from host #%u\n", id);
741 Network_ReceivePing (id, ping);
742 } /* Server_ReceivePing */
743
744 /*
745 * client has reached a sync point
746 */
747 void
Server_ReceiveSync(unsigned id,XBNetworkEvent event)748 Server_ReceiveSync (unsigned id, XBNetworkEvent event)
749 {
750 /* inform application */
751 Dbg_Server ("host #%u reached sync point %u\n", id, event);
752 Network_QueueEvent (event, id);
753 } /* Server_ReceiveSync */
754
755 /*
756 * receive a level check result from a client
757 */
758 void
Server_ReceiveLevelCheck(unsigned id,unsigned stat)759 Server_ReceiveLevelCheck (unsigned id, unsigned stat)
760 {
761 Dbg_Server ("receiving level status at %u = %u\n", id, stat);
762 levelStatus[id] = stat;
763 Network_QueueEvent (XBNW_LevelConfig, id);
764 } /* Server_ReceiveLevelCheck */
765
766 /*
767 * received keys from one client
768 */
769 void
Server_ReceivePlayerAction(unsigned id,int gameTime,const PlayerAction * keys)770 Server_ReceivePlayerAction (unsigned id, int gameTime, const PlayerAction * keys)
771 {
772 int i;
773
774 assert (id > 0);
775 assert (id < MAX_HOSTS);
776 assert (playerAction != NULL);
777
778 /* Dbg_Server("received action from host #%u\n", id); */
779 for (i = 0; i < MAX_PLAYER; i++) {
780 if (keys[i].dir != GoDefault) {
781 playerAction[id][i].dir = keys[i].dir;
782 }
783 if (keys[i].bomb) {
784 playerAction[id][i].bomb = XBTrue;
785 }
786 if (keys[i].special) {
787 playerAction[id][i].special = XBTrue;
788 }
789 if (keys[i].pause) {
790 playerAction[id][i].pause = XBTrue;
791 }
792 if (keys[i].abort != ABORT_NONE) {
793 playerAction[id][i].abort = keys[i].abort;
794 }
795 if (keys[i].suicide) {
796 playerAction[id][i].suicide = XBTrue;
797 }
798 /* Skywalker */
799 if (keys[i].laola) {
800 playerAction[id][i].laola = XBTrue;
801 }
802 else {
803 playerAction[id][i].laola = XBFalse;
804 if (keys[i].looser) {
805 playerAction[id][i].looser = XBTrue;
806 }
807 else {
808 playerAction[id][i].looser = XBFalse;
809 }
810 }
811 /* */
812 }
813 } /* Server_ReceivePlayerAction */
814
815 /*
816 * received level finish from clients
817 */
818 void
Server_ReceiveFinish(unsigned id)819 Server_ReceiveFinish (unsigned id)
820 {
821 Dbg_Server ("FINISH from host #%u\n", id);
822 } /* Server_ReceiveFinish */
823
824 /*
825 * receive the winner team from a client
826 */
827 void
Server_ReceiveWinnerTeam(unsigned id,unsigned team)828 Server_ReceiveWinnerTeam (unsigned id, unsigned team)
829 {
830 assert (id < MAX_HOSTS);
831 Dbg_Server ("receiving winner at %u = %u\n", id, team);
832 /* update winner table */
833 levelWinner[id] = team;
834 /* update string */
835 switch (team) {
836 case TEAM_NOWINNER:
837 memcpy (levelWinnerStr + 3 * id, "DR", 2);
838 break;
839 case TEAM_LOCALASYNC:
840 memcpy (levelWinnerStr + 3 * id, "LA", 2);
841 break;
842 default:
843 memcpy (levelWinnerStr + 3 * id, TempString ("%2x", team), 2);
844 break;
845 }
846 /* update current winner */
847 if (currentWinner == TEAM_UNDEF) {
848 currentWinner = team;
849 }
850 else if (currentWinner != team) {
851 currentWinner = TEAM_ASYNC;
852 }
853 /* queue event for game_server sync */
854 Network_QueueEvent (XBNW_SyncLevelResult, id);
855 } /* Server_ReceiveWinnerTeam */
856
857 /************************
858 * local data retrieval *
859 ************************/
860
861 /*
862 * get server flag
863 */
864 XBBool
GetIsServer(void)865 GetIsServer (void)
866 {
867 return isServer;
868 } /* GetIsServer */
869
870 /*
871 * set server flag
872 */
873 void
SetIsServer(XBBool value)874 SetIsServer (XBBool value)
875 {
876 isServer = value;
877 } /* SetIsServer */
878
879 /*
880 * retrieve host state from client
881 */
882 XBHostState
Server_GetHostState(unsigned id)883 Server_GetHostState (unsigned id)
884 {
885 return Network_GetHostState (id);
886 } /* Server_GetHostState */
887
888 /*
889 * retrieve host state requests for client
890 */
891 XBHostState *
Server_GetHostStateReq(unsigned id)892 Server_GetHostStateReq (unsigned id)
893 {
894 return Network_GetHostStateReq (id);
895 } /* Server_GetHostStateReq */
896
897 /*
898 * retrieve team state form client, player
899 */
900 XBTeamState
Server_GetTeamState(unsigned id,unsigned player)901 Server_GetTeamState (unsigned id, unsigned player)
902 {
903 return Network_GetTeamState (id, player);
904 } /* Server_GetTeamState */
905
906 /*
907 * retrieve host state requests from client
908 */
909 XBTeamState *
Server_GetTeamStateReq(unsigned id,unsigned player)910 Server_GetTeamStateReq (unsigned id, unsigned player)
911 {
912 return Network_GetTeamStateReq (id, player);
913 } /* Server_GetTeamStateReq */
914
915 /*
916 * last ping time of client
917 */
918 int
Server_GetPingTime(unsigned clientID)919 Server_GetPingTime (unsigned clientID)
920 {
921 return Network_GetPingTime (clientID);
922 } /* Server_GetPingTime */
923
924 /*
925 * check level status list for rejections
926 */
927 XBBool
Server_LevelApproved(void)928 Server_LevelApproved (void)
929 {
930 unsigned i;
931 for (i = 0; i < MAX_HOSTS; i++) {
932 if (levelStatus[i] != 255) {
933 if (levelStatus[i] == 0) {
934 Dbg_Server ("level rejected by clients\n");
935 return XBFalse;
936 }
937 }
938 }
939 Dbg_Server ("level approved by clients\n");
940 return XBTrue;
941 } /* Server_LevelApproved */
942
943 /*
944 * read player keys from local buffer
945 */
946 void
Server_GetPlayerAction(unsigned id,int player,PlayerAction * action)947 Server_GetPlayerAction (unsigned id, int player, PlayerAction * action)
948 {
949 assert (id > 0);
950 assert (id < MAX_HOSTS);
951 assert (player < MAX_PLAYER);
952 assert (playerAction != NULL);
953 /* copy data */
954 *action = playerAction[id][player];
955 } /* Server_GetPlayerAction */
956
957 /*
958 * check winner list for async
959 */
960 XBBool
Server_LevelAsync(void)961 Server_LevelAsync (void)
962 {
963 if (currentWinner != TEAM_ASYNC) {
964 Dbg_Server ("level results match!\n");
965 return XBFalse;
966 }
967 else {
968 Dbg_Server ("level results asynced (%s)!\n", levelWinnerStr);
969 return XBTrue;
970 }
971 } /* Server_LevelAsync */
972
973 /**********************
974 * local data setting *
975 **********************/
976
977 /*
978 * clear level status list for level checking
979 */
980 void
Server_ClearLevelStatus(void)981 Server_ClearLevelStatus (void)
982 {
983 unsigned i;
984 Dbg_Server ("clearing level negotiation status\n");
985 for (i = 0; i < MAX_HOSTS; i++) {
986 levelStatus[i] = 255;
987 } /* undefined value */
988 } /* Server_ClearLevelStatus */
989
990 /*
991 * set the level status for a single client
992 */
993 void
Server_SetLevelStatus(unsigned id,XBBool val)994 Server_SetLevelStatus (unsigned id, XBBool val)
995 {
996 assert (id < MAX_HOSTS);
997 levelStatus[id] = val ? 1 : 0;
998 Dbg_Server ("level is %s by %u\n", val ? "accepted" : "rejected", id);
999 } /* Server_SetLevelStatus */
1000
1001 /*
1002 * reset datagrams connections for new level
1003 */
1004 void
Server_ResetPlayerAction(void)1005 Server_ResetPlayerAction (void)
1006 {
1007 unsigned client;
1008
1009 for (client = 1; client < MAX_HOSTS; client++) {
1010 if (D2C_Connected (client)) {
1011 D2C_Reset (client);
1012 }
1013 }
1014 Dbg_Server ("reset frames for all hosts\n");
1015 } /* Server_ResetPlayerAction */
1016
1017 /*
1018 * clear player action data
1019 */
1020 void
Server_ClearPlayerAction(void)1021 Server_ClearPlayerAction (void)
1022 {
1023 unsigned id;
1024 int player;
1025
1026 for (id = 0; id < MAX_HOSTS; id++) {
1027 for (player = 0; player < MAX_PLAYER; player++) {
1028 playerAction[id][player].player = player;
1029 playerAction[id][player].dir = GoDefault;
1030 playerAction[id][player].bomb = XBFalse;
1031 playerAction[id][player].special = XBFalse;
1032 playerAction[id][player].pause = XBFalse;
1033 playerAction[id][player].suicide = XBFalse;
1034 playerAction[id][player].abort = ABORT_NONE;
1035 }
1036 }
1037 /* Dbg_Server("cleared action for all hosts\n"); */
1038 } /* Server_ClearPlayerAction */
1039
1040 /*
1041 * clear the winner list for async checking
1042 */
1043 void
Server_ClearLevelWinners(void)1044 Server_ClearLevelWinners (void)
1045 {
1046 unsigned i;
1047 Dbg_Server ("clearing winner list\n");
1048 for (i = 0; i < MAX_HOSTS; i++) {
1049 levelWinner[i] = TEAM_UNDEF;
1050 currentWinner = TEAM_UNDEF;
1051 sprintf (levelWinnerStr + 3 * i, "-- ");
1052 }
1053 } /* Server_ClearLevelWinners */
1054
1055 /******************
1056 * queue data out *
1057 ******************/
1058
1059 /*
1060 * queue all current game configs to client
1061 */
1062 void
Server_SendAllConfigs(unsigned id)1063 Server_SendAllConfigs (unsigned id)
1064 {
1065 unsigned client;
1066 unsigned player;
1067 unsigned rclient;
1068 XBHostState *hReq;
1069 XBTeamState *tReq;
1070 XBAtom atom;
1071 assert (id > 0);
1072 assert (id < MAX_HOSTS);
1073 for (client = 0; client < MAX_HOSTS; client++) {
1074 if (client == 0 || S2C_Connected (client)) {
1075 /* send game configs to client */
1076 S2C_SendGameConfig (id, client, LOCALGAMECONFIG (client));
1077 S2C_SendHostState (id, client, Network_GetHostState (client));
1078 hReq = Network_GetHostStateReq (client);
1079 for (rclient = 0; rclient < MAX_HOSTS; rclient++) {
1080 if (rclient == 0 || S2C_Connected (rclient)) {
1081 S2C_SendHostStateReq (id, rclient, client, hReq[rclient]);
1082 }
1083 }
1084 /* send player configs to client */
1085 for (player = 0; player < NUM_LOCAL_PLAYER; player++) {
1086 atom = Network_GetPlayer (client, player);
1087 if (ATOM_INVALID != atom) {
1088 S2C_SendPlayerConfig (id, client, player, atom);
1089 S2C_SendTeamState (id, client, player, Network_GetTeamState (client, player));
1090 tReq = Network_GetTeamStateReq (client, player);
1091 for (rclient = 0; rclient < MAX_HOSTS; rclient++) {
1092 if (rclient == 0 || S2C_Connected (rclient)) {
1093 S2C_SendTeamStateReq (id, rclient, client, player, tReq[rclient]);
1094 }
1095 }
1096 }
1097 }
1098 Dbg_Server ("Queued data for host #%u to %u\n", client, id);
1099 }
1100 }
1101 } /* Server_SendAllConfigs */
1102
1103 /*
1104 * queue dgram port to client
1105 */
1106 void
Server_SendDgramPort(unsigned id)1107 Server_SendDgramPort (unsigned id)
1108 {
1109 assert (id > 0);
1110 assert (id < MAX_HOSTS);
1111 S2C_SendDgramPort (id, D2C_Port (id));
1112 Dbg_Server ("queueing dgram port number to host #%u\n", id);
1113 } /* Server_SendDgramPort */
1114
1115 /*
1116 * queue request for game config to client
1117 */
1118 void
Server_QueryGameConfig(unsigned id)1119 Server_QueryGameConfig (unsigned id)
1120 {
1121 assert (id > 0);
1122 assert (id < MAX_HOSTS);
1123 S2C_QueryGameConfig (id);
1124 Dbg_Server ("queueing game config request to host #%u\n", id);
1125 } /* Server_QueryGameConfig */
1126
1127 /*
1128 * queue game config of client to all hosts
1129 */
1130 void
Server_SendGameConfig(unsigned id)1131 Server_SendGameConfig (unsigned id)
1132 {
1133 unsigned client;
1134 XBAtom atom;
1135 assert (id < MAX_HOSTS);
1136 atom = (id == 0) ? SERVERGAMECONFIG : LOCALGAMECONFIG (id);
1137 for (client = 1; client < MAX_HOSTS; client++) {
1138 if (S2C_Connected (client)) {
1139 S2C_SendGameConfig (client, id, atom);
1140 }
1141 }
1142 Dbg_Server ("queueing game config #%u to clients\n", id);
1143 } /* Server_SendGameConfig */
1144
1145 /*
1146 * queue request for player config to client
1147 */
1148 void
Server_QueryPlayerConfigs(unsigned id,unsigned cnt)1149 Server_QueryPlayerConfigs (unsigned id, unsigned cnt)
1150 {
1151 unsigned player;
1152 assert (id < MAX_HOSTS);
1153 if (id > 0) {
1154 for (player = 0; player < cnt; player++) {
1155 DeletePlayerConfig (CT_Demo, Network_GetPlayer (id, player));
1156 S2C_QueryPlayerConfig (id, player);
1157 }
1158 Dbg_Server ("queueing %u player config requests to host #%u\n", cnt, id);
1159 }
1160 } /* Server_QueryPlayerConfigs */
1161
1162 /*
1163 * queue player config of client id:player to all hosts
1164 */
1165 void
Server_SendPlayerConfig(unsigned id,unsigned player)1166 Server_SendPlayerConfig (unsigned id, unsigned player)
1167 {
1168 unsigned client;
1169 XBAtom atom;
1170 assert (id < MAX_HOSTS);
1171 atom = Network_GetPlayer (id, player);
1172 assert (ATOM_INVALID != atom);
1173 for (client = 1; client < MAX_HOSTS; client++) {
1174 if (S2C_Connected (client)) {
1175 S2C_SendPlayerConfig (client, id, player, atom);
1176 }
1177 }
1178 Dbg_Server ("queueing player config #%u:%u to hosts\n", id, player);
1179 } /* Server_SendPlayerConfig */
1180
1181 /*
1182 * requeue a received chat to connected clients
1183 */
1184 void
Server_SendChat(XBChat * chat)1185 Server_SendChat (XBChat * chat)
1186 {
1187 unsigned client;
1188 for (client = 1; client < MAX_HOSTS; client++) {
1189 if (S2C_Connected (client)) {
1190 S2C_SendChat (client, chat);
1191 }
1192 }
1193 Dbg_Server ("requeuing chat to clients\n");
1194 } /* Server_SendChat */
1195
1196 /*
1197 * server system message on chat
1198 */
1199 void
Server_SysChat(const char * txt)1200 Server_SysChat (const char *txt)
1201 {
1202 XBChat *chat = Chat_CreateSys ();
1203 assert (NULL != txt);
1204 Chat_SetText (chat, txt);
1205 Server_ReceiveChat (chat);
1206 } /* Server_SysChat */
1207
1208 /*
1209 * queue host state to all clients and sync local data
1210 */
1211 void
Server_SendHostState(unsigned id,XBHostState state)1212 Server_SendHostState (unsigned id, XBHostState state)
1213 {
1214 unsigned clientID;
1215 assert (id < MAX_HOSTS);
1216 Network_ReceiveHostState (id, state);
1217 for (clientID = 1; clientID < MAX_HOSTS; clientID++) {
1218 if (S2C_Connected (clientID)) {
1219 S2C_SendHostState (clientID, id, state);
1220 }
1221 }
1222 Dbg_Server ("queued host state for host #%u=%u to hosts\n", id, state);
1223 } /* Server_SendHostState */
1224
1225 /*
1226 * queue team state to all clients and sync local data
1227 */
1228 void
Server_SendTeamState(unsigned id,unsigned player,XBTeamState team)1229 Server_SendTeamState (unsigned id, unsigned player, XBTeamState team)
1230 {
1231 unsigned clientID;
1232 assert (id < MAX_HOSTS);
1233 assert (player < MAX_HOSTS);
1234 Network_ReceiveTeamState (id, player, team);
1235 for (clientID = 1; clientID < MAX_HOSTS; clientID++) {
1236 if (S2C_Connected (clientID)) {
1237 S2C_SendTeamState (clientID, id, player, team);
1238 }
1239 }
1240 Dbg_Server ("queued team state for host #%u(%u)=%u to hosts\n", id, player, team);
1241 } /* Server_SendTeamState */
1242
1243 /*
1244 * queue host state request from id for host to state and sync local data
1245 */
1246 void
Server_SendHostStateReq(unsigned id,unsigned host,XBHostState state)1247 Server_SendHostStateReq (unsigned id, unsigned host, XBHostState state)
1248 {
1249 unsigned clientID;
1250 assert (id < MAX_HOSTS);
1251 assert (host < MAX_HOSTS);
1252 for (clientID = 1; clientID < MAX_HOSTS; clientID++) {
1253 if (S2C_Connected (clientID)) {
1254 S2C_SendHostStateReq (clientID, id, host, state);
1255 }
1256 }
1257 Dbg_Server ("queued host request #%u->%u by #%u to hosts\n", host, state, id);
1258 } /* Server_SendHostStateReq */
1259
1260 /*
1261 * queue team state request from id for host:player to state and sync local data
1262 */
1263 void
Server_SendTeamStateReq(unsigned id,unsigned host,unsigned player,XBTeamState team)1264 Server_SendTeamStateReq (unsigned id, unsigned host, unsigned player, XBTeamState team)
1265 {
1266 unsigned clientID;
1267 assert (id < MAX_HOSTS);
1268 assert (host < MAX_HOSTS);
1269 assert (player < MAX_HOSTS);
1270 for (clientID = 1; clientID < MAX_HOSTS; clientID++) {
1271 if (S2C_Connected (clientID)) {
1272 S2C_SendTeamStateReq (clientID, id, host, player, team);
1273 }
1274 }
1275 Dbg_Server ("queued requested team state for player #%u(%u)->%u by #%u to hosts\n", host,
1276 player, team, id);
1277 } /* Server_SendTeamStateReq */
1278
1279 /*
1280 * queue disconnect info to clients
1281 */
1282 void
Server_SendDisconnectInfo(unsigned clientID)1283 Server_SendDisconnectInfo (unsigned clientID)
1284 {
1285 unsigned id;
1286 unsigned cnt = 0;
1287 for (id = 1; id < MAX_HOSTS; id++) {
1288 if (S2C_Connected (id)) {
1289 cnt++;
1290 S2C_HostDisconnected (id, clientID);
1291 }
1292 }
1293 if (cnt) {
1294 Dbg_Server ("queued disconnect of host #%u to %u hosts\n", clientID, cnt);
1295 }
1296 } /* SendDisconnectInfo */
1297
1298 /*
1299 * queue start game to single client
1300 */
1301 void
Server_SendStart(void)1302 Server_SendStart (void)
1303 {
1304 unsigned client;
1305 Server_StopListen ();
1306 Server_SendDisconnectOut ();
1307 Dbg_Server ("disconnecting all hosts that are out\n");
1308 Server_SendGameConfig (0);
1309 for (client = 1; client < MAX_HOSTS; client++) {
1310 if (S2C_Connected (client)) {
1311 S2C_StartGame (client);
1312 Dbg_Server ("queued start to host #%u\n", client);
1313 }
1314 }
1315 } /* Server_SendStart */
1316
1317 /*
1318 * queue random seed to clients
1319 */
1320 void
Server_SendRandomSeed(void)1321 Server_SendRandomSeed (void)
1322 {
1323 unsigned client;
1324 unsigned seed = GetRandomSeed ();
1325 for (client = 1; client < MAX_HOSTS; client++) {
1326 if (S2C_Connected (client)) {
1327 S2C_SendRandomSeed (client, seed);
1328 }
1329 }
1330 Dbg_Server ("queued random seed %u to hosts\n", seed);
1331 } /* Server_SendRandomSeed */
1332
1333 /*
1334 * queue level data to all clients
1335 */
1336 void
Server_SendLevel(const DBRoot * level)1337 Server_SendLevel (const DBRoot * level)
1338 {
1339 unsigned client;
1340 for (client = 1; client < MAX_HOSTS; client++) {
1341 if (S2C_Connected (client)) {
1342 S2C_SendLevelConfig (client, level);
1343 }
1344 }
1345 Dbg_Server ("queued level data to hosts\n");
1346 } /* Server_SendLevel */
1347
1348 /*
1349 * queue level activation to all clients
1350 */
1351 void
Server_SendLevelActivate(void)1352 Server_SendLevelActivate (void)
1353 {
1354 unsigned clientID;
1355 /* to all connected client */
1356 for (clientID = 1; clientID < MAX_HOSTS; clientID++) {
1357 if (S2C_Connected (clientID)) {
1358 S2C_SendLevelActivate (clientID);
1359 }
1360 }
1361 Dbg_Server ("queued level activation to hosts\n");
1362 } /* Server_SendLevelActivate */
1363
1364 /*
1365 * queue level reset to all clients
1366 */
1367 void
Server_SendLevelReset(void)1368 Server_SendLevelReset (void)
1369 {
1370 unsigned clientID;
1371 /* to all connected client */
1372 for (clientID = 1; clientID < MAX_HOSTS; clientID++) {
1373 if (S2C_Connected (clientID)) {
1374 S2C_SendLevelReset (clientID);
1375 }
1376 }
1377 Dbg_Server ("queued level reset to hosts\n");
1378 } /* Server_SendLevelReset */
1379
1380 /*
1381 * queue player action to client
1382 */
1383 void
Server_SendPlayerAction(int gameTime,const PlayerAction * playerAction)1384 Server_SendPlayerAction (int gameTime, const PlayerAction * playerAction)
1385 {
1386 unsigned client;
1387 for (client = 1; client < MAX_HOSTS; client++) {
1388 if (D2C_Connected (client)) {
1389 D2C_SendPlayerAction (client, gameTime, playerAction);
1390 }
1391 }
1392 /* Dbg_Server("queued actions for gt=%u to hosts\n", gameTime); */
1393 } /* Server_SendPlayerAction */
1394
1395 /*
1396 * queue finish player actions (= end of level) to clients
1397 */
1398 void
Server_FinishPlayerAction(int gameTime)1399 Server_FinishPlayerAction (int gameTime)
1400 {
1401 unsigned client;
1402 for (client = 1; client < MAX_HOSTS; client++) {
1403 if (D2C_Connected (client)) {
1404 D2C_SendFinish (client, gameTime);
1405 }
1406 }
1407 Dbg_Server ("queued FINISH to hosts\n");
1408 } /* Server_FinishPlayerAction */
1409
1410 /*
1411 * flush last player actions
1412 */
1413 XBBool
Server_FlushPlayerAction(void)1414 Server_FlushPlayerAction (void)
1415 {
1416 XBBool result;
1417 unsigned client;
1418
1419 result = XBTrue;
1420 for (client = 1; client < MAX_HOSTS; client++) {
1421 if (D2C_Connected (client)) {
1422 if (!D2C_Flush (client)) {
1423 result = XBFalse;
1424 }
1425 }
1426 }
1427 Dbg_Server ("flushing actions: (%s needed)\n", result ? "not" : "");
1428 return result;
1429 } /* Server_FlushPlayerAction */
1430
1431 /*
1432 * tell clients that all clients have reached sync point
1433 */
1434 void
Server_SendSync(XBNetworkEvent event)1435 Server_SendSync (XBNetworkEvent event)
1436 {
1437 unsigned clientID;
1438
1439 /* to all connected client */
1440 for (clientID = 1; clientID < MAX_HOSTS; clientID++) {
1441 if (S2C_Connected (clientID)) {
1442 S2C_Sync (clientID, event);
1443 }
1444 }
1445 Dbg_Server ("queued sync %u to hosts\n", event);
1446 } /* Server_SendSync */
1447
1448 /*
1449 * queue a level sync result to all clients
1450 */
1451 void
Server_SendLevelSync(void)1452 Server_SendLevelSync (void)
1453 {
1454 unsigned id;
1455 /* to all connected client */
1456 for (id = 1; id < MAX_HOSTS; id++) {
1457 if (S2C_Connected (id)) {
1458 S2C_SendLevelSync (id);
1459 }
1460 }
1461 Dbg_Server ("queued LevelSync to clients\n");
1462 } /* Server_SendLevelSync */
1463
1464 /*
1465 * queue a level async signal to all clients
1466 */
1467 void
Server_SendLevelAsync(void)1468 Server_SendLevelAsync (void)
1469 {
1470 unsigned id;
1471 /* to all connected client */
1472 for (id = 1; id < MAX_HOSTS; id++) {
1473 if (S2C_Connected (id)) {
1474 S2C_SendLevelAsync (id);
1475 }
1476 }
1477 Server_SysChat (TempString ("level async ! (%s)", levelWinnerStr));
1478 Dbg_Server ("queued LevelAsync to clients\n");
1479 } /* Server_SendLevelAsync */
1480
1481 /***********************
1482 * central connections *
1483 ***********************/
1484
1485 /*
1486 * create connection to central for game info
1487 */
1488 void
Server_StartCentralNewGame(const CFGGameHost * cfg,const CFGGameSetup * setup)1489 Server_StartCentralNewGame (const CFGGameHost * cfg, const CFGGameSetup * setup)
1490 {
1491 #ifdef OLDIFCODE
1492 size_t numInter;
1493 const XBSocketInterface *inter;
1494 size_t i, j;
1495 #endif
1496 CFGCentralSetup centralSetup;
1497
1498 assert (NULL == query);
1499 Dbg_Server ("attempting to register game\n");
1500 #ifndef OLDIFCODE
1501 RetrieveCentralSetup (¢ralSetup);
1502 if (NULL == centralSetup.name) {
1503 Dbg_Server ("no central defined!\n");
1504 return;
1505 }
1506 /* alloc a single communication to central */
1507 query = calloc (2, sizeof (XBComm *));
1508 assert (NULL != query);
1509 /* let system choose the interface to central */
1510 Dbg_Server ("connecting to central %s:%u\n", centralSetup.name, centralSetup.port);
1511 query[0] = NewGame_CreateComm (NULL, centralSetup.port, centralSetup.name, cfg, setup);
1512 if (NULL == query[0]) {
1513 Dbg_Server ("failed to establish socket to central, game not visible in central\n");
1514 free (query);
1515 return;
1516 }
1517 Dbg_Server ("socket to central established\n");
1518 #else
1519 inter = Socket_GetInterfaces (&numInter);
1520 if (NULL == inter) {
1521 Dbg_Server ("no interfaces found!\n");
1522 return;
1523 }
1524 Dbg_Server ("interfaces found = %u\n", numInter);
1525 RetrieveCentralSetup (¢ralSetup);
1526 if (NULL == centralSetup.name) {
1527 Dbg_Server ("no central defined!\n");
1528 return;
1529 }
1530 /* alloc 1 pointer (to central) */
1531 query = calloc (1 + numInter, sizeof (XBComm *));
1532 assert (NULL != query);
1533 Dbg_Server ("connecting to central %s:%u\n", centralSetup.name, centralSetup.port);
1534 /* start query on at most one device */
1535 /* FIXXX used to be i=1 worked on linux */
1536 #ifdef W32
1537 Dbg_Server ("W32\n");
1538 #ifdef CYG
1539 for (i = 0, j = 0; (j == 0) && (i < numInter); i++) {
1540 #else
1541 for (i = 1, j = 0; (j == 0) && (i < numInter); i++) {
1542 #endif
1543 #else
1544 Dbg_Server ("Linux\n");
1545 for (i = 1, j = 0; (j == 0) && (i < numInter); i++) {
1546 #endif
1547 if (NULL !=
1548 (query[j] =
1549 NewGame_CreateComm (inter[i].addrDevice, centralSetup.port, centralSetup.name, cfg,
1550 setup))) {
1551 Dbg_Server ("established query to %s on interface %u\n", centralSetup.name, i);
1552 j++;
1553 }
1554 }
1555 /* make sure not more than one device is used, would clash with close routines */
1556 assert (j == 1);
1557 #endif
1558 /* queue initial data to central */
1559 Server_RestartNewGame (1, "");
1560 } /* Server_StartCentralNewGame */
1561
1562 /*
1563 * queue game info to central
1564 */
1565 /* GAMEONFIX */
1566 void
1567 Server_RestartNewGame (int num, const char *score)
1568 {
1569 if (NULL != query) {
1570 struct timeval tv;
1571 int i;
1572 gettimeofday (&tv, NULL);
1573 for (i = 0; query[i] != NULL; i++) {
1574 NewGame_Send (query[i], &tv, num, score);
1575 Dbg_Server ("queued game data to central\n");
1576 }
1577 }
1578 } /* Server_RestartQuery */
1579
1580 /* GAMEONFIX */
1581
1582 /*
1583 * queue request to central for removing game info
1584 */
1585 void
1586 Server_CloseNewGame (void)
1587 {
1588 if (NULL != query) {
1589 struct timeval tv;
1590 int i;
1591 gettimeofday (&tv, NULL);
1592 for (i = 0; query[i] != NULL; i++) {
1593 NewGame_Close (query[i], &tv);
1594 Dbg_Server ("queued game close to central\n");
1595 }
1596 }
1597 } /* Server_CloseNewGame */
1598
1599 /*
1600 * delete open connection to central
1601 */
1602 void
1603 Server_StopNewGame (void)
1604 {
1605 size_t i;
1606 /* delete communications */
1607 assert (NULL != query);
1608 for (i = 0; query[i] != NULL; i++) {
1609 assert (i == 0);
1610 Dbg_Server ("forcing stop of previous newgame\n");
1611 CommDelete (query[i]);
1612 }
1613 } /* Server_StopQuery */
1614
1615 /*
1616 * receive close event from query
1617 */
1618 void
1619 Server_ReceiveNewGameClose (void)
1620 {
1621 assert (NULL != query);
1622 free (query);
1623 query = NULL;
1624 Dbg_Server ("removed newgame sockets to central\n");
1625 } /**/
1626
1627 /*
1628 * end of file server.c
1629 */
1630