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