1 /* $Id: ogcache-client.c,v 1.7 2005-03-28 16:26:40 stpohle Exp $
2  * OpenGameCache-Client: this file will hold the protocol for the gameserver communication
3  */
4 
5 #include "basic.h"
6 #include "bomberclone.h"
7 #include "udp.h"
8 #include "ogcache-client.h"
9 
10 int ogc_sock = -1;
11 struct game_entry ogc_array[MAX_OGC_ENTRYS];
12 char ogc_host[LEN_OGCHOST+1];
13 char ogc_port[LEN_OGCPORT+1];
14 char ogc_game[LEN_GAME+1];
15 int ogc_ai_family;
16 struct _sockaddr ogc_addr;
17 int ogc_browsing = 0;
18 int ogc_lasttimeout = 0;
19 
20 /* fill out the whole gameentry */
fill_gameentry(char * pos,struct game_entry * ge)21 static void fill_gameentry (char *pos, struct game_entry *ge) {
22 	char *pos_next;		/* pointer to the next seperator */
23 	int i = 0;
24 
25 	while (pos != NULL)
26 	{
27 		/* search and test the next seperator */
28 		pos_next = strchr (pos, '\t');
29 		if (pos_next == NULL)
30 			pos_next = strchr (pos, '\n');
31 		/* if we found a return delete it..
32 		 * if we found the tab delete it */
33 		if (pos_next != NULL)
34 		{
35 			if (pos_next[0] == '\n')
36 			{	/* RETURN found */
37 				pos_next[0] = '\0';
38 				pos_next = NULL;
39 			}
40 			else
41 				pos_next[0] = '\0';
42 		}
43 
44 		/* fill the struct with our data */
45 		switch (i)
46 		{
47 		case (0):	/* serial */
48 			ge->serial = atoi (pos);
49 			break;
50 		case (1):	/* host */
51 			strncpy (ge->host, pos, LEN_OGCHOST);
52 			break;
53 		case (2):	/* port */
54 			strncpy (ge->port, pos, LEN_OGCPORT);
55 			break;
56 		case (3):	/* game */
57 			strncpy (ge->game, pos, LEN_GAME);
58 			break;
59 		case (4):	/* version */
60 			strncpy (ge->version, pos, LEN_VERSION);
61 			break;
62 		case (5):	/* nettype */
63 			if (strcmp (pos, "IPv6") == 0)
64 				ge->ai_family = PF_INET6;
65 			else
66 				ge->ai_family = PF_INET;
67 			break;
68 		case (6):	/* netname */
69 			strncpy (ge->gamename, pos, LEN_GAMENAME);
70 			break;
71 		case (7):	/* state */
72 			strncpy (ge->status, pos, LEN_STATUS);
73 			break;
74 		case (8):	/* curplayers */
75 			ge->curplayers = atoi (pos);
76 			break;
77 		case (9):	/* maxplayers */
78 			ge->maxplayers = atoi (pos);
79 			break;
80 		default:
81 			return;
82 		}
83 
84 		/* increase i for the next entry */
85 		i++;
86 		if (pos_next != NULL)
87 			pos = pos_next + 1;
88 		else
89 			pos = NULL;
90 	}
91 
92 	d_printf ("fill_gameentry [Serial:%d, Addr:%s:%s, Game:%s, Gamename:%s\n", ge->serial, ge->host, ge->port, ge->game, ge->gamename);
93 };
94 
95 
96 /* add a game to the list or update one */
ogc_listadd(char * data)97 static int ogc_listadd (char *data) {
98 	struct game_entry ge;
99 	int i;
100 
101 	/* fill out the entry and check if there was a problem */
102 	fill_gameentry (data, &ge);
103 	if (ge.serial == -1) return 0;
104 
105 	for (i = 0; (i < MAX_OGC_ENTRYS && ogc_array[i].serial != -1 && ogc_array[i].serial != ge.serial); i++);
106 
107 	if (i < MAX_OGC_ENTRYS && ogc_array[i].serial == ge.serial)
108 		ogc_array[i] = ge;
109 	else if (i < MAX_OGC_ENTRYS && ogc_array[i].serial == -1)
110 		ogc_array[i] = ge;
111 
112 	return 1;
113 };
114 
115 
116 /* delete the game from the list */
ogc_listdel(char * data)117 static int ogc_listdel (char *data) {
118 	int i, serial, res = 0;
119 
120 	serial = atoi (data);
121 
122 	for (i = 0; i < MAX_OGC_ENTRYS; i++)
123 		if (ogc_array[i].serial == serial) {
124 			ogc_array[i].serial = -1;
125 			res = 1;
126 		}
127 
128 	return res;
129 };
130 
131 
132 /* work with the incoming packet */
ogc_do_inpacket(char * in,int len,struct _sockaddr * addr)133 static int ogc_do_inpacket (char *in, int len, struct _sockaddr *addr) {
134 	char *param_start = strchr (in, ':');
135 	int i = 0;
136 
137 	/* set param_start at the place where the first parameter is
138 	 * and if there is a : delete this one */
139 	if (param_start == NULL) {
140 		if ((param_start = strchr (in, '\n')) != NULL) {
141 			param_start[0] = '\0';
142 			param_start = NULL;
143 		}
144 	}
145 	else {
146 		param_start[0] = '\0';
147 		param_start++;
148 	}
149 
150 	/*
151      *	work with the incoming data
152 	 */
153 	if (strcmp (in, "ENTRY") == 0)
154 		i = ogc_listadd (param_start);
155 
156 	else if (strcmp (in, "DELENTRY") == 0)
157 		i = ogc_listdel (param_start);
158 
159 	return i;
160 };
161 
162 
163 
164 /* start a new listen server to get the list */
ogc_init(char * localport,char * server,char * port,char * game,int ai_family)165 int ogc_init (char *localport, char *server, char *port, char *game, int ai_family) {
166 	int i;
167 
168 	ogc_sock = -1;
169 
170 	ogc_sock = udp_server (localport, ai_family);
171 	d_printf ("ogc_init (Localport: %s, Server %s:%s Game %s socket=%d)\n", localport, server, port, game, ogc_sock);
172 	if (ogc_sock <= 0)
173 		return 0;
174 
175 	strncpy (ogc_host, server, LEN_OGCHOST);
176 	strncpy (ogc_port, port, LEN_OGCPORT);
177 	strncpy (ogc_game, game, LEN_GAME);
178 	ogc_ai_family = ai_family;
179 
180 	d_printf ("ogc_host:%s ogc_port:%s ogc_game:%s ogc_ai_family:%d\n", ogc_host, ogc_port, ogc_game, ogc_ai_family);
181 	if (dns_filladdr (ogc_host, LEN_OGCHOST, ogc_port, LEN_OGCPORT, ogc_ai_family, &ogc_addr) < 0) {
182 		udp_close (ogc_sock);
183 		ogc_sock = -1;
184 		return 0;
185 	}
186 
187 	for (i = 0; i < MAX_OGC_ENTRYS; i++)
188 		ogc_array[i].serial = -1;
189 
190 	return 1;
191 };
192 
193 
194 
195 /* send the status of the curent game to the game cache */
ogc_sendgamestatus(int sock,char * game,char * version,char * gamename,int curplayers,int maxplayers,char * status)196 int ogc_sendgamestatus (int sock, char *game, char *version, char *gamename,
197 						int curplayers, int maxplayers, char *status) {
198 	char data[BUF_SIZE];
199 
200 	if (sock <= 0 || ogc_sock <= 0) return 0;
201 	sprintf (data, "GAME:%s\t%s\t%s", game, version, gamename);
202 	if (ogc_ai_family == PF_INET)
203 		sprintf (data, "%s\tIPv4", data);
204 	else
205 		sprintf (data, "%s\tIPv6", data);
206 	sprintf (data, "%s\t%d\t%d\t%s", data, curplayers, maxplayers, status);
207 
208 	udp_send (sock, data, strlen (data), &ogc_addr, ogc_ai_family);
209 
210 	return 1;
211 };
212 
213 
214 /* send to the gamecache that this game has quit */
ogc_sendgamequit(int sock)215 int ogc_sendgamequit (int sock) {
216 	char data[BUF_SIZE];
217 
218 	if (sock <= 0 || ogc_sock <= 0) return 0;
219 
220 	sprintf (data, "QUIT:");
221 	udp_send (sock, data, strlen (data), &ogc_addr, ogc_ai_family);
222 
223 	return 1;
224 };
225 
226 
227 /* send to the gamecache that this browser does not anymore exist */
ogc_shutdown()228 void ogc_shutdown () {
229 	if (ogc_sock <= 0)
230 		return;
231 
232 	d_printf ("ogc_shutdown\n");
233 	if (ogc_browsing)
234 		ogc_browsestop ();
235 	udp_close (ogc_sock);
236 
237 	ogc_sock = -1;
238 };
239 
240 
241 
242 /* check the socket for incoming data and work
243  * with them if there are any */
ogc_loop()244 int ogc_loop () {
245 	int len, i = 0;
246 	char in[BUF_SIZE];
247 	struct _sockaddr inaddr;
248 
249 	if (ogc_sock <= 0)
250 		return -1;
251 
252 	len = udp_get (ogc_sock, in, BUF_SIZE, &inaddr, ogc_ai_family);
253 
254 	if (len > 0) {  /* we have got something */
255 		d_printf ("ogc_got: %s\n", in);
256 		i = ogc_do_inpacket (in, len, &inaddr);
257 	}
258 
259 	if (ogc_browsing && (time (NULL) - ogc_lasttimeout) > 30)
260 		ogc_browsestart ();
261 
262 	return i;
263 };
264 
265 
266 /* send to the gamecache that we want
267  * to browse through the open games */
ogc_browsestart()268 void ogc_browsestart () {
269 	char data[BUF_SIZE];
270 
271 	d_printf ("ogc_browsestart\n");
272 
273 	if (ogc_sock <= 0)
274 		return;
275 
276 	sprintf (data, "LISTGAMES:%s", ogc_game);
277 
278 	udp_send (ogc_sock, data, strlen (data), &ogc_addr, ogc_ai_family);
279 	ogc_browsing = 1;
280 
281 	ogc_lasttimeout = time (NULL);
282 };
283 
284 
285 /* send the gamecache that we don't want to watch the list no more */
ogc_browsestop()286 void ogc_browsestop () {
287 	char data[BUF_SIZE];
288 
289 	d_printf ("ogc_browsestop\n");
290 
291 	ogc_browsing = 0;
292 	if (ogc_sock <= 0)
293 		return;
294 
295 	sprintf (data, "LISTQUIT:");
296 
297 	udp_send (ogc_sock, data, strlen (data), &ogc_addr, ogc_ai_family);
298 };
299