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