1 /*
2 * file com_newGame.c - client newGamees for local network game
3 *
4 * $Id: com_newgame.c,v 1.20 2006/02/24 21:29:16 fzago Exp $
5 *
6 * Program XBLAST
7 * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
8 * Added by Koen De Raedt for central support
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published
12 * by the Free Software Foundation; either version 2; or (at your option)
13 * any later version
14 *
15 * This program is distributed in the hope that it will be entertaining,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
18 * Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25 #include "xblast.h"
26
27 /*
28 * local types
29 */
30 typedef struct
31 {
32 XBCommBrowse browse;
33 char *addrBroadcast; /* ip of receiver */
34 unsigned short port; /* port of receiver */
35 unsigned char serial; /* serial */
36 unsigned short gameport; /* server port */
37 int gameID; /* game id at central, initially -1 */
38 char *game; /* game name */
39 int numLives; /* number of lives */
40 int numWins; /* numberof wins */
41 int frameRate; /* frame rate, =0 for running games */
42 struct timeval tvSend; /* time of last queueing */
43 XBBool shutdown; /* flag for shutdown when queue emptied */
44 unsigned int replies; /* counter for replies */
45 } XBCommNewGame;
46
47 /*
48 * central sent Reply
49 */
50 static void
HandleReply(XBCommNewGame * qComm,const XBBrowseTeleNewGameOK * tele,const char * host)51 HandleReply (XBCommNewGame * qComm, const XBBrowseTeleNewGameOK * tele, const char *host)
52 {
53 long msec;
54 struct timeval tv;
55 /* calculate sping time */
56 gettimeofday (&tv, NULL);
57 msec =
58 (tv.tv_sec - qComm->tvSend.tv_sec) * 1000L + (tv.tv_usec - qComm->tvSend.tv_usec) / 1000L;
59 /* update received id and reply counter */
60 qComm->gameID = tele->gameID;
61 qComm->replies++;
62 Dbg_Out ("NEWGAME: receive id=%i from %s (%ld msec, cnt=%u)\n", tele->gameID, host, msec,
63 qComm->replies);
64 } /* HandleReply */
65
66 /*
67 * handle received data
68 */
69 static void
ReceiveNewGame(XBCommBrowse * bComm,const XBBrowseTele * tele,const char * host,unsigned short port)70 ReceiveNewGame (XBCommBrowse * bComm, const XBBrowseTele * tele, const char *host,
71 unsigned short port)
72 {
73 assert (NULL != bComm);
74 assert (NULL != tele);
75 assert (NULL != host);
76 switch (tele->type) {
77 case XBBT_NewGameOK:
78 HandleReply ((XBCommNewGame *) bComm, &tele->newGameOK, host);
79 break;
80 default:
81 Dbg_Newgame ("ignoring invalid response\n");
82 break;
83 }
84 } /* ReceiveNewGame */
85
86 /*
87 * handle event
88 */
89 static XBBool
EventNewGame(XBCommBrowse * bComm,XBBrowseEvent ev)90 EventNewGame (XBCommBrowse * bComm, XBBrowseEvent ev)
91 {
92 XBCommNewGame *qComm = (XBCommNewGame *) bComm;
93 switch (ev) {
94 case XBBE_Wait:
95 Dbg_Newgame ("all data sent, %s\n", qComm->shutdown ? "shutting down" : "continuing");
96 return qComm->shutdown;
97 case XBBE_Dgram:
98 Dbg_Newgame ("received invalid datagram, ignoring\n");
99 break;
100 case XBBE_Browse:
101 Dbg_Newgame ("received invalid browse, ignoring\n");
102 break;
103 case XBBE_Write:
104 Dbg_Newgame ("new data waits to be sent\n");
105 break;
106 case XBBE_Close:
107 Dbg_Newgame ("browse shutdown complete\n");
108 break;
109 default:
110 Dbg_Newgame ("unknown browse event, ignoring!\n");
111 }
112 return XBFalse;
113 } /* EventNewGame */
114
115 /*
116 * handle delete
117 */
118 static XBCommResult
DeleteNewGame(XBComm * comm)119 DeleteNewGame (XBComm * comm)
120 {
121 XBCommNewGame *qComm = (XBCommNewGame *) comm;
122 assert (NULL != qComm);
123 Browse_Finish (&qComm->browse);
124 assert (NULL != qComm->addrBroadcast);
125 free (qComm->addrBroadcast);
126 assert (NULL != qComm->game);
127 free (qComm->game);
128 free (qComm);
129 Dbg_Newgame ("comm instance removed\n");
130 /* tell server to null query socket */
131 Server_ReceiveNewGameClose ();
132 return XCR_OK;
133 } /* DeleteNewGame */
134
135 /*
136 * create NewGame communication to central on given device
137 */
138 XBComm *
NewGame_CreateComm(const char * addrDevice,unsigned short port,const char * addrBroadcast,const CFGGameHost * cfg,const CFGGameSetup * setup)139 NewGame_CreateComm (const char *addrDevice, unsigned short port, const char *addrBroadcast,
140 const CFGGameHost * cfg, const CFGGameSetup * setup)
141 {
142 XBSocket *pSocket;
143 XBCommNewGame *cComm;
144 assert (NULL != addrBroadcast);
145 /* create socket and bind to given interface */
146 pSocket = Net_BindUdp (addrDevice, 0);
147 if (NULL == pSocket) {
148 Dbg_Newgame ("failed to open udp socket on device %s\n",
149 (addrDevice == NULL) ? "(auto)" : addrDevice);
150 return NULL;
151 }
152 #ifndef sun
153 /* some sun's don't like connected udp sockets and sendto */
154 if (!Net_ConnectUdp (pSocket, addrBroadcast, port)) {
155 Socket_Close (pSocket);
156 Dbg_Newgame ("failed to connect UDP socket to central %s:%u\n", addrBroadcast, port);
157 return NULL;
158 }
159 #endif
160 Dbg_Newgame ("created udp socket on %s:%u to central %s:%u\n",
161 Socket_HostName (pSocket, XBFalse), Socket_HostPort (pSocket, XBFalse),
162 Socket_HostName (pSocket, XBTrue), Socket_HostPort (pSocket, XBTrue));
163 /* create communication data structure */
164 cComm = calloc (1, sizeof (*cComm));
165 assert (NULL != cComm);
166 /* set values */
167 Browse_CommInit (&cComm->browse, COMM_NewGame, pSocket, ReceiveNewGame, EventNewGame,
168 DeleteNewGame);
169 cComm->port = port;
170 cComm->serial = 0;
171 cComm->gameID = -1;
172 cComm->addrBroadcast = DupString (addrBroadcast);
173 cComm->tvSend.tv_sec = 0;
174 cComm->tvSend.tv_usec = 0;
175 cComm->gameport = cfg->port;
176 cComm->game = DupString (cfg->game);
177 cComm->numLives = setup->numLives;
178 cComm->numWins = setup->numWins;
179 cComm->frameRate = setup->frameRate;
180 cComm->shutdown = XBFalse;
181 cComm->replies = 0;
182 /* that's all ? */
183 return &cComm->browse.comm;
184 } /* NewGame_CreateComm */
185
186 /*
187 * prepend waiting/scores to game name
188 */
189 static void
PrependData(int num,const char * score,char * name)190 PrependData (int num, const char *score, char *name)
191 {
192 char tempString[48];
193 int len;
194 /* create string to prepend */
195 if (num > 0) {
196 /* server is waiting */
197 sprintf (tempString, "%d:", num);
198 }
199 else {
200 /* game is busy */
201 if (strlen (score) < 48) {
202 strcpy (tempString, score);
203 }
204 }
205 /* append base name, max 48 bytes */
206 len = strlen (tempString);
207 strncpy (tempString + len, name, 48 - len);
208 /* ensure that new string is null-terminated */
209 tempString[47] = (char)'\0';
210 /* set as new basename */
211 strncpy (name, tempString, 48);
212 } /* PrependData */
213
214 /*
215 * queue current game data to central
216 */
217 void
NewGame_Send(XBComm * comm,const struct timeval * tv,int num,const char * score)218 NewGame_Send (XBComm * comm, const struct timeval *tv, int num, const char *score)
219 {
220 XBBrowseTeleNewGame tele;
221 XBCommNewGame *qComm = (XBCommNewGame *) comm;
222 assert (NULL != qComm);
223 assert (NULL != tv);
224 /* create browse telegram */
225 tele.any.type = XBBT_NewGame;
226 tele.any.serial = ++qComm->serial;
227 tele.gameID = qComm->gameID;
228 tele.port = qComm->gameport;
229 tele.version[0] = VERSION_MAJOR;
230 tele.version[1] = VERSION_MINOR;
231 tele.version[2] = VERSION_PATCH;
232 tele.numLives = qComm->numLives;
233 tele.numWins = qComm->numWins;
234 tele.frameRate = (num > 0) ? qComm->frameRate : 0;
235 strncpy (tele.game, qComm->game, sizeof (tele.game));
236 PrependData (num, score, tele.game);
237 /* queue data */
238 Browse_Send (&qComm->browse, qComm->addrBroadcast, qComm->port, XBFalse, &tele.any);
239 /* mark time */
240 qComm->tvSend = *tv;
241 Dbg_Newgame ("queued new game data #%u to central %s:%hu\n", qComm->serial,
242 qComm->addrBroadcast, qComm->port);
243 } /* NewGame_Send */
244
245 /*
246 * queue close request to central
247 */
248 void
NewGame_Close(XBComm * comm,const struct timeval * tv)249 NewGame_Close (XBComm * comm, const struct timeval *tv)
250 {
251 XBBrowseTeleNewGameOK tele;
252 XBCommNewGame *qComm = (XBCommNewGame *) comm;
253 assert (NULL != qComm);
254 assert (NULL != tv);
255 /* create browse telegram */
256 tele.any.type = XBBT_NewGameOK;
257 tele.any.serial = ++qComm->serial;
258 tele.gameID = qComm->gameID;
259 /* queue data */
260 Browse_Send (&qComm->browse, qComm->addrBroadcast, qComm->port, XBFalse, &tele.any);
261 /* mark time */
262 qComm->tvSend = *tv;
263 /* mark for shutdown */
264 qComm->shutdown = XBTrue;
265 Dbg_Newgame ("queued close #%u to central at %s:%hu, marking for shutdown\n", qComm->serial,
266 qComm->addrBroadcast, qComm->port);
267 } /* NewGame_Poll */
268
269 /*
270 * end of file com_newGame.c
271 */
272