1 /*
2  * Copyright (C) 2000  Ross Combs (rocombs@cs.nmsu.edu)
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18 #define REALM_INTERNAL_ACCESS
19 #include "common/setup_before.h"
20 #include <stdio.h>
21 #ifdef HAVE_STDDEF_H
22 # include <stddef.h>
23 #else
24 # ifndef NULL
25 #  define NULL ((void *)0)
26 # endif
27 #endif
28 #ifdef STDC_HEADERS
29 # include <stdlib.h>
30 #else
31 # ifdef HAVE_MALLOC_H
32 #  include <malloc.h>
33 # endif
34 #endif
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #else
38 # ifdef HAVE_STRINGS_H
39 #  include <strings.h>
40 # endif
41 #endif
42 #include "compat/strrchr.h"
43 #include "compat/strdup.h"
44 #include "compat/strcasecmp.h"
45 #include <errno.h>
46 #include "compat/strerror.h"
47 #include "common/eventlog.h"
48 #include "common/list.h"
49 #include "common/util.h"
50 #include "common/addr.h"
51 #include "common/xalloc.h"
52 #include "connection.h"
53 #include "common/rcm.h"
54 #include "realm.h"
55 #ifdef HAVE_ASSERT_H
56 # include <assert.h>
57 #endif
58 #include "common/setup_after.h"
59 
60 
61 static t_list * realmlist_head=NULL;
62 
63 static t_realm * realm_create(char const * name, char const * description, unsigned int ip, unsigned int port);
64 static int realm_destroy(t_realm * realm);
65 
realm_create(char const * name,char const * description,unsigned int ip,unsigned int port)66 static t_realm * realm_create(char const * name, char const * description, unsigned int ip, unsigned int port)
67 {
68     t_realm * realm;
69 
70     if (!name)
71     {
72 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL name");
73 	return NULL;
74     }
75     if (!description)
76     {
77 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL description");
78 	return NULL;
79     }
80 
81     realm = xmalloc(sizeof(t_realm));
82     realm->name = NULL;
83     realm->description = NULL;
84 
85     if (realm_set_name(realm ,name)<0)
86     {
87         eventlog(eventlog_level_error,__FUNCTION__,"failed to set name for realm");
88 	xfree(realm);
89 	return NULL;
90     }
91     if (realm->description != NULL) xfree((void *)realm->description);
92     realm->description = xstrdup(description);
93     realm->ip = ip;
94     realm->port = port;
95     realm->conn = NULL;
96     realm->active = 0;
97     realm->player_number = 0;
98     realm->game_number = 0;
99     realm->sessionnum = 0;
100     realm->tcp_sock = 0;
101     rcm_init(&realm->rcm);
102 
103     eventlog(eventlog_level_info,__FUNCTION__,"created realm \"%s\"",name);
104     return realm;
105 }
106 
107 
realm_destroy(t_realm * realm)108 static int realm_destroy(t_realm * realm)
109 {
110     if (!realm)
111     {
112 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
113 	return -1;
114     }
115 
116     if (realm->active)
117     	realm_deactive(realm);
118 
119     xfree((void *)realm->name); /* avoid warning */
120     xfree((void *)realm->description); /* avoid warning */
121     xfree((void *)realm); /* avoid warning */
122 
123     return 0;
124 }
125 
126 
realm_get_name(t_realm const * realm)127 extern char const * realm_get_name(t_realm const * realm)
128 {
129     if (!realm)
130     {
131 	return NULL;
132     }
133     return realm->name;
134 }
135 
136 
realm_set_name(t_realm * realm,char const * name)137 extern int realm_set_name(t_realm * realm, char const * name)
138 {
139     char const      * temp;
140     t_realm const * temprealm;
141 
142     if (!realm)
143     {
144         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
145         return -1;
146     }
147 
148     if (name && (temprealm=realmlist_find_realm(name)))
149     {
150          if (temprealm == realm)
151               return 0;
152          else
153          {
154               eventlog(eventlog_level_error,__FUNCTION__,"realm %s does already exist in list",name);
155               return -1;
156          }
157     }
158 
159     if (name)
160 	temp=xstrdup(name);
161     else
162       temp = NULL;
163 
164     if (realm->name)
165       xfree((void *)realm->name); /* avoid warning */
166     realm->name = temp;
167 
168     return 0;
169 }
170 
171 
realm_get_description(t_realm const * realm)172 extern char const * realm_get_description(t_realm const * realm)
173 {
174     if (!realm)
175     {
176 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
177 	return NULL;
178     }
179     return realm->description;
180 }
181 
182 
realm_get_port(t_realm const * realm)183 extern unsigned short realm_get_port(t_realm const * realm)
184 {
185     if (!realm)
186     {
187         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
188         return 0;
189     }
190     return realm->port;
191 }
192 
193 
realm_get_ip(t_realm const * realm)194 extern unsigned int realm_get_ip(t_realm const * realm)
195 {
196     if (!realm)
197     {
198         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
199         return 0;
200     }
201     return realm->ip;
202 }
203 
204 
realm_get_active(t_realm const * realm)205 extern unsigned int realm_get_active(t_realm const * realm)
206 {
207     if (!realm)
208     {
209         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
210         return 0;
211     }
212     return realm->active;
213 }
214 
realm_set_active(t_realm * realm,unsigned int active)215 extern int realm_set_active(t_realm * realm, unsigned int active)
216 {
217     if (!realm)
218     {
219         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
220         return -1;
221     }
222 
223     realm->active=active;
224     return 0;
225 }
226 
realm_get_player_number(t_realm const * realm)227 extern unsigned int realm_get_player_number(t_realm const * realm)
228 {
229     if (!realm)
230     {
231         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
232         return 0;
233     }
234     return realm->player_number;
235 }
236 
realm_add_player_number(t_realm * realm,int number)237 extern int realm_add_player_number(t_realm * realm, int number)
238 {
239     if (!realm)
240     {
241         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
242         return -1;
243     }
244     realm->player_number += number;
245     return 0;
246 }
247 
realm_get_game_number(t_realm const * realm)248 extern unsigned int realm_get_game_number(t_realm const * realm)
249 {
250     if (!realm)
251     {
252         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
253         return 0;
254     }
255     return realm->game_number;
256 }
257 
realm_add_game_number(t_realm * realm,int number)258 extern int realm_add_game_number(t_realm * realm, int number)
259 {
260     if (!realm)
261     {
262         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
263         return -1;
264     }
265     realm->game_number += number;
266     return 0;
267 }
268 
realm_active(t_realm * realm,t_connection * c)269 extern int realm_active(t_realm * realm, t_connection * c)
270 {
271     if (!realm)
272     {
273         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
274         return -1;
275     }
276     if (!c)
277     {
278         eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
279         return -1;
280     }
281     if (realm->active)
282     {
283         eventlog(eventlog_level_debug,__FUNCTION__, "realm %s is already actived,destroy previous one",realm->name);
284         realm_deactive(realm);
285     }
286     realm->active=1;
287     realm->conn=c;
288     conn_set_realm(c,realm);
289     realm->sessionnum=conn_get_sessionnum(c);
290     realm->tcp_sock=conn_get_socket(c);
291     eventlog(eventlog_level_info,__FUNCTION__, "realm %s actived",realm->name);
292     return 0;
293 }
294 
realm_deactive(t_realm * realm)295 extern int realm_deactive(t_realm * realm)
296 {
297     t_connection * c;
298 
299     if (!realm)
300     {
301         eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
302         return -1;
303     }
304     if (!realm->active)
305     {
306         eventlog(eventlog_level_error,__FUNCTION__,"realm %s is not actived",realm->name);
307         return -1;
308     }
309     if ((c = realm_get_conn(realm)))
310         conn_set_state(c,conn_state_destroy);
311 
312     realm->active=0;
313     realm->sessionnum=0;
314     realm->tcp_sock=0;
315     /*
316     realm->player_number=0;
317     realm->game_number=0;
318     */
319     eventlog(eventlog_level_info,__FUNCTION__, "realm %s deactived",realm->name);
320     return 0;
321 }
322 
323 
realmlist_load(char const * filename)324 t_list * realmlist_load(char const * filename)
325 {
326     FILE *          fp;
327     unsigned int    line;
328     unsigned int    pos;
329     unsigned int    len;
330     t_addr *        raddr;
331     char *          temp, *temp2;
332     char *          buff;
333     char *          name;
334     char *          desc;
335     t_realm *       realm;
336     t_list *        list_head = NULL;
337 
338     if (!filename)
339     {
340         eventlog(eventlog_level_error,__FUNCTION__,"got NULL filename");
341         return NULL;
342     }
343 
344     if (!(fp = fopen(filename,"r")))
345     {
346         eventlog(eventlog_level_error,__FUNCTION__,"could not open realm file \"%s\" for reading (fopen: %s)",filename,pstrerror(errno));
347         return NULL;
348     }
349 
350     list_head = list_create();
351 
352     for (line=1; (buff = file_get_line(fp)); line++)
353     {
354         for (pos=0; buff[pos]=='\t' || buff[pos]==' '; pos++);
355         if (buff[pos]=='\0' || buff[pos]=='#')
356         {
357             continue;
358         }
359         if ((temp = strrchr(buff,'#')))
360         {
361 	    unsigned int endpos;
362 
363             *temp = '\0';
364 	    len = strlen(buff)+1;
365             for (endpos=len-1;  buff[endpos]=='\t' || buff[endpos]==' '; endpos--);
366             buff[endpos+1] = '\0';
367         }
368 
369 	/* skip any separators */
370 	for (temp = buff; *temp && (*temp == ' ' || *temp == '\t');temp++);
371 	if (*temp != '"') {
372 	    eventlog(eventlog_level_error,__FUNCTION__,"malformed line %u in file \"%s\" (no realmname)",line,filename);
373 	    continue;
374 	}
375 
376 	temp2 = temp + 1;
377 	/* find the next " */
378 	for (temp = temp2; *temp && *temp != '"';temp++);
379 	if (*temp != '"' || temp == temp2) {
380 	    eventlog(eventlog_level_error,__FUNCTION__,"malformed line %u in file \"%s\" (no realmname)",line,filename);
381 	    continue;
382 	}
383 
384 	/* save the realmname */
385 	*temp = '\0';
386         name = xstrdup(temp2);
387 
388 	/* eventlog(eventlog_level_trace, __FUNCTION__,"found realmname: %s",name); */
389 
390 	/* skip any separators */
391 	for(temp = temp + 1; *temp && (*temp == '\t' || *temp == ' ');temp++);
392 
393 	if (*temp == '"') { /* we have realm description */
394 	    temp2 = temp + 1;
395 	    /* find the next " */
396 	    for(temp = temp2;*temp && *temp != '"';temp++);
397 	    if (*temp != '"' || temp == temp2) {
398 		eventlog(eventlog_level_error,__FUNCTION__,"malformed line %u in file \"%s\" (no valid description)",line,filename);
399 		xfree(name);
400 		continue;
401 	    }
402 
403 	    /* save the description */
404 	    *temp = '\0';
405     	    desc = xstrdup(temp2);
406 
407 	    /* eventlog(eventlog_level_trace, __FUNCTION__,"found realm desc: %s",desc); */
408 
409 	    /* skip any separators */
410 	    for(temp = temp + 1; *temp && (*temp == ' ' || *temp == '\t');temp++);
411 	} else desc = xstrdup("\0");
412 
413 	temp2 = temp;
414 	/* find out where address ends */
415 	for(temp = temp2 + 1; *temp && *temp != ' ' && *temp != '\t';temp++);
416 
417 	if (*temp) *temp++ = '\0'; /* if is not the end of the file, end addr and move forward */
418 
419 	/* eventlog(eventlog_level_trace, __FUNCTION__,"found realm ip: %s",temp2); */
420 
421 	if (!(raddr = addr_create_str(temp2,0,BNETD_REALM_PORT))) /* 0 means "this computer" */ {
422 	    eventlog(eventlog_level_error,__FUNCTION__,"invalid address value for field 3 on line %u in file \"%s\"",line,filename);
423 	    xfree(name);
424 	    xfree(desc);
425 	    continue;
426 	}
427 
428 	if (!(realm = realm_create(name,desc,addr_get_ip(raddr),addr_get_port(raddr))))
429 	{
430 	    eventlog(eventlog_level_error,__FUNCTION__,"could not create realm");
431 	    addr_destroy(raddr);
432 	    xfree(name);
433 	    xfree(desc);
434 	    continue;
435 	}
436 
437 	addr_destroy(raddr);
438 	xfree(name);
439 	xfree(desc);
440 
441 	list_prepend_data(list_head,realm);
442     }
443     file_get_line(NULL); // clear file_get_line buffer
444     if (fclose(fp)<0)
445 	eventlog(eventlog_level_error,__FUNCTION__,"could not close realm file \"%s\" after reading (fclose: %s)",filename,pstrerror(errno));
446     return list_head;
447 }
448 
realmlist_reload(char const * filename)449 extern int realmlist_reload(char const * filename)
450 {
451     t_elem * new_curr;
452     t_elem * old_curr;
453     t_realm * new_realm;
454     t_realm * old_realm;
455     int match;
456     t_list * newlist = NULL;
457     t_list * oldlist = realmlist_head;
458 
459     realmlist_head = NULL;
460 
461     if (!(newlist = realmlist_load(filename)))
462         return -1;
463 
464     LIST_TRAVERSE(oldlist,old_curr)
465     {
466     	if (!(old_realm = elem_get_data(old_curr)))
467 	{
468 	  eventlog(eventlog_level_error,__FUNCTION__,"found NULL elem in list");
469 	  continue;
470 	}
471 
472 	match = 0;
473 
474 	LIST_TRAVERSE(newlist,new_curr)
475 	{
476     	    if (!(new_realm = elem_get_data(new_curr)))
477 	    {
478 	      eventlog(eventlog_level_error,__FUNCTION__,"found NULL elem in list");
479 	      continue;
480 	    }
481 
482 	    if (!strcmp(old_realm->name,new_realm->name))
483 	    {
484 		match = 1;
485 		rcm_chref(&old_realm->rcm,new_realm);
486 
487 		break;
488 	    }
489 
490 	}
491 	if (!match)
492 	  rcm_chref(&old_realm->rcm,NULL);
493 
494 	realm_destroy(old_realm);
495         list_remove_elem(oldlist,&old_curr);
496     }
497 
498     list_destroy(oldlist);
499 
500     realmlist_head = newlist;
501 
502     return 0;
503 }
504 
realmlist_create(char const * filename)505 extern int realmlist_create(char const * filename)
506 {
507     if (!(realmlist_head = realmlist_load(filename)))
508        return -1;
509 
510     return 0;
511 
512 }
513 
realmlist_unload(t_list * list_head)514 extern int realmlist_unload(t_list * list_head)
515 {
516     t_elem *  curr;
517     t_realm * realm;
518 
519     if (list_head)
520     {
521 	LIST_TRAVERSE(list_head,curr)
522 	{
523 	    if (!(realm = elem_get_data(curr)))
524 		eventlog(eventlog_level_error,__FUNCTION__,"found NULL realm in list");
525 	    else
526 	        realm_destroy(realm);
527 
528 	    list_remove_elem(list_head,&curr);
529 	}
530 	list_destroy(list_head);
531     }
532 
533     return 0;
534 }
535 
realmlist_destroy()536 extern int realmlist_destroy()
537 {
538 	int res;
539 
540 	res = realmlist_unload(realmlist_head);
541 	realmlist_head = NULL;
542 
543 	return res;
544 }
545 
realmlist(void)546 extern t_list * realmlist(void)
547 {
548     return realmlist_head;
549 }
550 
551 
realmlist_find_realm(char const * realmname)552 extern t_realm * realmlist_find_realm(char const * realmname)
553 {
554     t_elem const *  curr;
555     t_realm * realm;
556 
557     if (!realmname)
558     {
559 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL realmname");
560 	return NULL;
561     }
562 
563     LIST_TRAVERSE_CONST(realmlist_head,curr)
564     {
565 	realm = elem_get_data(curr);
566 	if (strcasecmp(realm->name,realmname)==0)
567 	    return realm;
568     }
569 
570     return NULL;
571 }
572 
realmlist_find_realm_by_ip(unsigned long ip)573 extern t_realm * realmlist_find_realm_by_ip(unsigned long ip)
574 {
575     t_elem const *  curr;
576     t_realm * realm;
577 
578     LIST_TRAVERSE_CONST(realmlist_head,curr)
579     {
580         realm = elem_get_data(curr);
581         if (realm->ip==ip)
582             return realm;
583     }
584     return NULL;
585 }
586 
realm_get_conn(t_realm * realm)587 extern t_connection * realm_get_conn(t_realm * realm)
588 {
589 	assert(realm);
590 
591 	return realm->conn;
592 }
593 
realm_get(t_realm * realm,t_rcm_regref * regref)594 extern t_realm * realm_get(t_realm * realm, t_rcm_regref * regref)
595 {
596 	rcm_get(&realm->rcm,regref);
597 	return realm;
598 }
599 
realm_put(t_realm * realm,t_rcm_regref * regref)600 extern void realm_put(t_realm * realm, t_rcm_regref * regref)
601 {
602 	rcm_put(&realm->rcm,regref);
603 }
604