From 0d0650008f7b532bfd7c06d9a2139fda5e1b3e7a Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Thu, 2 Feb 2006 16:41:56 +0100 Subject: [PATCH] Version 0.51 - added configfile parser, added configfile support to subsystems - plugins: replaced con/destructor with dlsym() peeking --- ChangeLog | 4 + Makefile.am | 2 +- Makefile.in | 2 +- TODO | 9 +- configure | 20 ++--- configure.in | 4 +- hlswmaster.conf | 33 +++++++ include/configfile.h | 24 +++++ include/hlswmaster.h | 25 +++--- include/plugin.h | 12 ++- plugins/doom3.c | 16 +--- plugins/gamespy1.c | 16 +--- plugins/gamespy2.c | 16 +--- plugins/hlswproxy.c | 29 +++--- plugins/q3engine.c | 16 +--- plugins/quake2.c | 15 +--- plugins/ut.c | 16 +--- src/Makefile.am | 4 +- src/Makefile.in | 6 +- src/client.c | 38 ++++---- src/config.c | 208 +++++++++++++++++++++++++++++++++++++++++++ src/daemon.c | 79 ---------------- src/logging.c | 59 ++++++------ src/main.c | 47 +++++----- src/plugin.c | 110 ++++++++++++++--------- src/scanner.c | 43 ++++++--- src/serverlist.c | 14 +-- 27 files changed, 533 insertions(+), 334 deletions(-) create mode 100644 hlswmaster.conf create mode 100644 include/configfile.h create mode 100644 src/config.c delete mode 100644 src/daemon.c diff --git a/ChangeLog b/ChangeLog index 3803b92..73ee35b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +* Sun 27 Mar 2005 Olaf Rempel 0.51 +- added configfile parser, added configfile support to subsystems +- plugins: replaced con/destructor with dlsym() peeking + * Sat 26 Mar 2005 Olaf Rempel 0.50 - added autoconf/automake/libtool support - plugins: replaced _init() / _fini() with ((constructor)) / ((destructor)) diff --git a/Makefile.am b/Makefile.am index eaf162a..9c877e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,4 +2,4 @@ AUTOMAKE_OPTIONS = foreign no-dependencies SUBDIRS = src plugins tools -EXTRA_DIST = autogen.sh TODO +EXTRA_DIST = TODO autogen.sh hlswmaster.conf diff --git a/Makefile.in b/Makefile.in index 4e86d9a..ec75f16 100644 --- a/Makefile.in +++ b/Makefile.in @@ -174,7 +174,7 @@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ AUTOMAKE_OPTIONS = foreign no-dependencies SUBDIRS = src plugins tools -EXTRA_DIST = autogen.sh TODO +EXTRA_DIST = TODO autogen.sh hlswmaster.conf all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive diff --git a/TODO b/TODO index ca6760d..5fa1e7b 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,7 @@ -- eigene daemon() funktion rauswerfen und dann libc daemon() benutzen -- configfile parser bauen & benutzen -- logging ausbauen -- plugins im dev und auf live system finden -- auf mehreren interfaces gleichzeitig scannen +- daemonize & userwechsel +- signalhandler fuer config reread +- signalhandler listen-flush + neuscannen +- auf mehreren/allen interfaces gleichzeitig scannen - threads ueberwachen - threadpool fuer client-thread? - ratelimit fuer scanner diff --git a/configure b/configure index f066d64..7a92801 100644 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.59 for hlswmaster 0.50. +# Generated by GNU Autoconf 2.59 for hlswmaster 0.51. # # Report bugs to >. # @@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='hlswmaster' PACKAGE_TARNAME='hlswmaster' -PACKAGE_VERSION='0.50' -PACKAGE_STRING='hlswmaster 0.50' +PACKAGE_VERSION='0.51' +PACKAGE_STRING='hlswmaster 0.51' PACKAGE_BUGREPORT='Olaf Rempel ' # Factoring default headers for most tests. @@ -953,7 +953,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures hlswmaster 0.50 to adapt to many kinds of systems. +\`configure' configures hlswmaster 0.51 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1019,7 +1019,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of hlswmaster 0.50:";; + short | recursive ) echo "Configuration of hlswmaster 0.51:";; esac cat <<\_ACEOF @@ -1160,7 +1160,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -hlswmaster configure 0.50 +hlswmaster configure 0.51 generated by GNU Autoconf 2.59 Copyright (C) 2003 Free Software Foundation, Inc. @@ -1174,7 +1174,7 @@ cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by hlswmaster $as_me 0.50, which was +It was created by hlswmaster $as_me 0.51, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ @@ -1818,7 +1818,7 @@ fi # Define the identity of the package. PACKAGE=hlswmaster - VERSION=0.50 + VERSION=0.51 cat >>confdefs.h <<_ACEOF @@ -21419,7 +21419,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by hlswmaster $as_me 0.50, which was +This file was extended by hlswmaster $as_me 0.51, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -21482,7 +21482,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -hlswmaster config.status 0.50 +hlswmaster config.status 0.51 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.in b/configure.in index ba4fc7f..94ee321 100644 --- a/configure.in +++ b/configure.in @@ -1,8 +1,8 @@ dnl projekname, version, bugsto -AC_INIT(hlswmaster, 0.50, [Olaf Rempel ]) +AC_INIT(hlswmaster, 0.51, [Olaf Rempel ]) dnl same for automake -AM_INIT_AUTOMAKE(hlswmaster, 0.50) +AM_INIT_AUTOMAKE(hlswmaster, 0.51) dnl do not rebuild configure AM_MAINTAINER_MODE diff --git a/hlswmaster.conf b/hlswmaster.conf new file mode 100644 index 0000000..f65ac78 --- /dev/null +++ b/hlswmaster.conf @@ -0,0 +1,33 @@ +[global] +# broadcast scan source IP & PORT (udp) +scan_ip 0.0.0.0 +scan_port 7130 + +# broadcast scan every X seconds +scan_interval 30 + +# serverlist rebuild every X seconds +serverlist_interval 5 + +# server timeout after X seconds +serverlist_timeout 120 + +# master answers with this source IP +master_ip 0.0.0.0 + +# load these plugins +plugin plugins/.libs/hlswproxy.so +plugin plugins/.libs/q3engine.so +plugin plugins/.libs/quake2.so +plugin plugins/.libs/gamespy1.so +plugin plugins/.libs/gamespy2.so +plugin plugins/.libs/doom3.so +plugin plugins/.libs/ut.so + +# logging +# logfile hlswmaster.log + +[hlswproxy] +scan_ip 10.10.0.1 +scan_ip 10.10.0.2 + diff --git a/include/configfile.h b/include/configfile.h new file mode 100644 index 0000000..d58a458 --- /dev/null +++ b/include/configfile.h @@ -0,0 +1,24 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include "list.h" + +struct conf_section { + struct list_head list; + char name[32]; + struct list_head tupel; +}; + +struct conf_tupel { + struct list_head list; + char *option; + char *parameter; +}; + +int config_parse(char *config); +struct conf_section * config_get_section(char *name); +char * config_get_parameter(struct conf_section *section, char *option); +char * config_get_string(char *section, char *option, char *def); +int config_get_int(char *section, char *option, int def); + +#endif /* _CONFIG_H */ diff --git a/include/hlswmaster.h b/include/hlswmaster.h index 95be6bc..84b09ba 100644 --- a/include/hlswmaster.h +++ b/include/hlswmaster.h @@ -3,6 +3,7 @@ #include "list.h" #include "netpkt.h" +#include "configfile.h" struct game_server { struct list_head list; @@ -15,34 +16,30 @@ struct game_server { } __attribute__ ((packed)); -/* daemon.c */ -void daemonize(char *pw_name); - /* logging.c */ -void log_open(char *logfile); -void log_close(); +int log_open(); void log_print(const char *fmt, ... ); /* plugin.c */ int plugin_load(char *name); -int plugin_unload(char *name); -int plugins_scan(void); +int plugin_load_all(); +int plugin_unload_all(); +int plugins_scan(); int plugins_parse(struct net_pkt *pkt); int plugins_gc(unsigned long timeout); /* scanner.c */ void pkt_queue(struct net_pkt *pkt); -int scan_init(void); -void scan_exit(void); -void scan_transmit(void); -void scan_receive(void); +int scan_init(); +void scan_transmit(); +void scan_receive(); /* serverlist.c */ -void server_collector(void); +void server_collector(); /* client.c */ int client_pkt_add(struct game_server *server); -int client_pkt_commit(void); -void client_handler(void); +int client_pkt_commit(); +void client_handler(); #endif /* _HLSWMASTER_H */ diff --git a/include/plugin.h b/include/plugin.h index 5cfa3a5..eccde07 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -2,6 +2,7 @@ #define _PLUGIN_H #include "netpkt.h" +#include "configfile.h" #include "list.h" extern int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2); @@ -26,19 +27,16 @@ extern unsigned short pkt_getport(struct net_pkt *pkt); extern int pkt_atoi(struct net_pkt *pkt, void *p); struct hlswmaster_plugin { - /* must be first */ struct list_head list; - char name[32]; - - int (*init)(struct list_head *config); + char name[32]; + void *dlref; + + int (*init)(struct conf_section *config); int (*fini)(void); int (*scan)(void); int (*parse)(struct net_pkt *pkt); int (*gc)(int timeout); }; -extern void register_plugin(struct hlswmaster_plugin *me); -extern void unregister_plugin(struct hlswmaster_plugin *me); - #endif /* _PLUGIN_H */ diff --git a/plugins/doom3.c b/plugins/doom3.c index d54f74b..faf5d06 100644 --- a/plugins/doom3.c +++ b/plugins/doom3.c @@ -20,7 +20,7 @@ #include #include "plugin.h" -struct scan_ports port_arr[] = { +static struct scan_ports port_arr[] = { { 27666, 27673, 38 }, /* Doom 3 */ { 0,0,0 } }; @@ -28,12 +28,12 @@ struct scan_ports port_arr[] = { static char scanmsg[] = "\xff\xffgetInfo"; static char replymsg[] = "\xff\xffinfoResponse"; -int scan(void) { +static int scan(void) { pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg)); return 1; } -int parse(struct net_pkt *pkt) { +static int parse(struct net_pkt *pkt) { int gameid; if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg))) @@ -46,16 +46,8 @@ int parse(struct net_pkt *pkt) { return 1; } -static struct hlswmaster_plugin plugin = { +struct hlswmaster_plugin plugin = { .name = "doom3", .scan = &scan, .parse = &parse, }; - -void __attribute__ ((constructor)) init(void) { - register_plugin(&plugin); -} - -void __attribute__ ((destructor)) fini(void) { - unregister_plugin(&plugin); -} diff --git a/plugins/gamespy1.c b/plugins/gamespy1.c index 3e9a1c2..68c0da2 100644 --- a/plugins/gamespy1.c +++ b/plugins/gamespy1.c @@ -20,7 +20,7 @@ #include #include "plugin.h" -struct scan_ports port_arr[] = { +static struct scan_ports port_arr[] = { { 22000, 22010, 16 }, /* Battlefield 1942 */ { 0, 0, 0 } }; @@ -29,12 +29,12 @@ static char scanmsg[] = "\\info\\"; static char bf1942_reply[] = "\\gameId\\BF1942\\"; static char hostport_search[] = "\\hostport\\"; -int scan(void) { +static int scan(void) { pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg)); return 1; } -int parse(struct net_pkt *pkt) { +static int parse(struct net_pkt *pkt) { int gameid, port; void *p; @@ -62,16 +62,8 @@ int parse(struct net_pkt *pkt) { return 1; } -static struct hlswmaster_plugin plugin = { +struct hlswmaster_plugin plugin = { .name = "gamespy1", .scan = &scan, .parse = &parse, }; - -void __attribute__ ((constructor)) init(void) { - register_plugin(&plugin); -} - -void __attribute__ ((destructor)) fini(void) { - unregister_plugin(&plugin); -} diff --git a/plugins/gamespy2.c b/plugins/gamespy2.c index 2882c93..5889c9a 100644 --- a/plugins/gamespy2.c +++ b/plugins/gamespy2.c @@ -20,7 +20,7 @@ #include #include "plugin.h" -struct scan_ports port_arr[] = { +static struct scan_ports port_arr[] = { { 2302, 2302, 30 }, /* halo */ { 0,0,0 } }; @@ -28,12 +28,12 @@ struct scan_ports port_arr[] = { static char scanmsg[] = { 0xFE, 0xFD, 0x00, 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00, 0x00 }; static char replymsg[] = { 0x00, 0xDE, 0xAD, 0xBE, 0xEF }; -int scan(void) { +static int scan(void) { pkt_send_portarr(NULL, port_arr, scanmsg, sizeof(scanmsg)); return 1; } -int parse(struct net_pkt *pkt) { +static int parse(struct net_pkt *pkt) { int gameid; if (!(gameid = pkt_check_portarr(pkt, port_arr))) @@ -46,16 +46,8 @@ int parse(struct net_pkt *pkt) { return 1; } -static struct hlswmaster_plugin plugin = { +struct hlswmaster_plugin plugin = { .name = "gamespy2", .scan = &scan, .parse = &parse, }; - -void __attribute__ ((constructor)) init(void) { - register_plugin(&plugin); -} - -void __attribute__ ((destructor)) fini(void) { - unregister_plugin(&plugin); -} diff --git a/plugins/hlswproxy.c b/plugins/hlswproxy.c index 83bd32d..739416e 100644 --- a/plugins/hlswproxy.c +++ b/plugins/hlswproxy.c @@ -23,19 +23,19 @@ static char scanmsg[] = "\xff\xff\xff\xffHLSWLANSEARCH"; -struct _entry { +static struct _entry { u_int16_t gameid; u_int32_t ip; u_int16_t port1; u_int16_t port2; } __attribute__ ((packed)); -int scan(void) { +static int scan(void) { pkt_send(NULL, 7140, scanmsg, sizeof(scanmsg)); return 1; } -int parse(struct net_pkt *pkt) { +static int parse(struct net_pkt *pkt) { struct _entry *server; if (pkt_getport(pkt) != 7140) return 0; @@ -49,16 +49,21 @@ int parse(struct net_pkt *pkt) { return 1; } -static struct hlswmaster_plugin plugin = { +static int init(struct conf_section *section) { + struct conf_tupel *tupel; + list_for_each_entry(tupel, §ion->tupel, list) + if (!strcmp(tupel->option, "scan_ip")) + log_print("hlswproxy: will scan %s", tupel->parameter); +} + +static int fini() { + +} + +struct hlswmaster_plugin plugin = { .name = "hlswproxy", .scan = &scan, .parse = &parse, + .init = &init, + .fini = &fini, }; - -void __attribute__ ((constructor)) init(void) { - register_plugin(&plugin); -} - -void __attribute__ ((destructor)) fini(void) { - unregister_plugin(&plugin); -} diff --git a/plugins/q3engine.c b/plugins/q3engine.c index aa96ce5..42d363b 100644 --- a/plugins/q3engine.c +++ b/plugins/q3engine.c @@ -20,7 +20,7 @@ #include #include "plugin.h" -struct scan_ports port_arr[] = { +static struct scan_ports port_arr[] = { { 27960, 27969, 6 }, /* Quake3(6), Elite Force(7), Enemy Territory(25) */ { 28960, 28963, 31 }, /* Call of Duty(31), Call of Duty: United Offensive (42) */ { 0,0,0 } @@ -35,12 +35,12 @@ static char et_reply[] = "\\version\\ET "; static char cod_reply[] = "\\gamename\\Call of Duty\\"; static char coduo_reply[] = "\\gamename\\CoD:United Offensive\\"; -int scan(void) { +static int scan(void) { pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg)); return 1; } -int parse(struct net_pkt *pkt) { +static int parse(struct net_pkt *pkt) { int gameid; if (!(gameid = pkt_check_portarr(pkt, port_arr))) @@ -82,16 +82,8 @@ int parse(struct net_pkt *pkt) { return 1; } -static struct hlswmaster_plugin plugin = { +struct hlswmaster_plugin plugin = { .name = "q3engine", .scan = &scan, .parse = &parse, }; - -void __attribute__ ((constructor)) init(void) { - register_plugin(&plugin); -} - -void __attribute__ ((destructor)) fini(void) { - unregister_plugin(&plugin); -} diff --git a/plugins/quake2.c b/plugins/quake2.c index 6818d14..ed97262 100644 --- a/plugins/quake2.c +++ b/plugins/quake2.c @@ -22,13 +22,12 @@ static char scanmsg[] = "\xff\xff\xff\xffinfo 34"; -int scan(void) { +static int scan(void) { pkt_send(NULL, 27910, scanmsg, strlen(scanmsg)); return 1; } -/* TODO: src port checken */ -int parse(struct net_pkt *pkt) { +static int parse(struct net_pkt *pkt) { if (pkt_getport(pkt) != 27910) return 0; @@ -39,16 +38,8 @@ int parse(struct net_pkt *pkt) { return 1; } -static struct hlswmaster_plugin plugin = { +struct hlswmaster_plugin plugin = { .name = "quake2", .scan = &scan, .parse = &parse, }; - -void __attribute__ ((constructor)) init(void) { - register_plugin(&plugin); -} - -void __attribute__ ((destructor)) fini(void) { - unregister_plugin(&plugin); -} diff --git a/plugins/ut.c b/plugins/ut.c index d4dfbb6..98fce1d 100644 --- a/plugins/ut.c +++ b/plugins/ut.c @@ -20,7 +20,7 @@ #include #include "plugin.h" -struct scan_ports port_arr[] = { +static struct scan_ports port_arr[] = { { 8777, 8786, 5 }, /* Unreal Tournament (5), Ravenshield (-) */ { 0,0,0 } }; @@ -29,12 +29,12 @@ static char scanmsg[] = "REPORTQUERY"; static char ut_reply[] = "ut "; static char rvs_reply[] = "rvnshld 0"; -int scan(void) { +static int scan(void) { pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg)); return 1; } -int parse(struct net_pkt *pkt) { +static int parse(struct net_pkt *pkt) { int gameid, port; void *p; @@ -61,16 +61,8 @@ int parse(struct net_pkt *pkt) { return 1; } -static struct hlswmaster_plugin plugin = { +struct hlswmaster_plugin plugin = { .name = "ut", .scan = &scan, .parse = &parse, }; - -void __attribute__ ((constructor)) init(void) { - register_plugin(&plugin); -} - -void __attribute__ ((destructor)) fini(void) { - unregister_plugin(&plugin); -} diff --git a/src/Makefile.am b/src/Makefile.am index 08f5098..797847e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies INCLUDES = -I../include bin_PROGRAMS = hlswmaster -hlswmaster_SOURCES = client.c daemon.c logging.c main.c plugin.c plugin_helper.c scanner.c serverlist.c \ - ../include/hlswmaster.h ../include/list.h ../include/netpkt.h ../include/plugin.h +hlswmaster_SOURCES = client.c config.c logging.c main.c plugin.c plugin_helper.c scanner.c serverlist.c \ + ../include/configfile.h ../include/hlswmaster.h ../include/list.h ../include/netpkt.h ../include/plugin.h hlswmaster_LDADD = -ldl -lpthread hlswmaster_LDFLAGS = -rdynamic diff --git a/src/Makefile.in b/src/Makefile.in index 8dca93c..5c1cc1f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -51,7 +51,7 @@ CONFIG_CLEAN_FILES = am__installdirs = "$(DESTDIR)$(bindir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) -am_hlswmaster_OBJECTS = client.$(OBJEXT) daemon.$(OBJEXT) \ +am_hlswmaster_OBJECTS = client.$(OBJEXT) config.$(OBJEXT) \ logging.$(OBJEXT) main.$(OBJEXT) plugin.$(OBJEXT) \ plugin_helper.$(OBJEXT) scanner.$(OBJEXT) serverlist.$(OBJEXT) hlswmaster_OBJECTS = $(am_hlswmaster_OBJECTS) @@ -173,8 +173,8 @@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ AUTOMAKE_OPTIONS = foreign no-dependencies INCLUDES = -I../include -hlswmaster_SOURCES = client.c daemon.c logging.c main.c plugin.c plugin_helper.c scanner.c serverlist.c \ - ../include/hlswmaster.h ../include/list.h ../include/netpkt.h ../include/plugin.h +hlswmaster_SOURCES = client.c config.c logging.c main.c plugin.c plugin_helper.c scanner.c serverlist.c \ + ../include/configfile.h ../include/hlswmaster.h ../include/list.h ../include/netpkt.h ../include/plugin.h hlswmaster_LDADD = -ldl -lpthread hlswmaster_LDFLAGS = -rdynamic diff --git a/src/client.c b/src/client.c index 183f8bc..585cc06 100644 --- a/src/client.c +++ b/src/client.c @@ -28,6 +28,7 @@ #include #include "hlswmaster.h" +#include "configfile.h" #include "plugin.h" #include "list.h" @@ -70,19 +71,19 @@ static inline int cpkt_not_full(const struct client_pkt *a, void *b) { * @return struct client_pkt * or NULL on error */ static struct client_pkt * client_pkt_add_real(struct list_head *list) { - struct client_pkt *new; + struct client_pkt *pkt; - if (!(new = malloc(sizeof(struct client_pkt) + MAX_PKT_LEN))) - return NULL; - - INIT_LIST_HEAD(&new->list); - - /* kopier den hlsw header in das client paket */ - memcpy(new->buf, HLSW_HEADER, HLSW_HEADER_LEN); - new->size = HLSW_HEADER_LEN; - - list_add_tail(&new->list, list); - return new; + pkt = malloc(sizeof(struct client_pkt) + MAX_PKT_LEN); + if (pkt) { + INIT_LIST_HEAD(&pkt->list); + + /* kopier den hlsw header in das client paket */ + memcpy(pkt->buf, HLSW_HEADER, HLSW_HEADER_LEN); + pkt->size = HLSW_HEADER_LEN; + + list_add_tail(&pkt->list, list); + } + return pkt; } /** @@ -118,6 +119,10 @@ int client_pkt_add(struct game_server *server) { int client_pkt_commit() { struct list_head old_list, *pkt, *tmp; + /* wenn die liste leer ist, HLSW-header verschicken */ + if (list_empty(&client_pkt_prepare)) + client_pkt_add_real(&client_pkt_prepare); + pthread_mutex_lock(&pkt_list_lock); /* old_list wird head der real list */ @@ -141,23 +146,24 @@ int client_pkt_commit() { /** * client_handler() * empfaengt und beantwortet die HLSW Anfragen - * - * TODO: src-ip configurierbar machen (config file?) */ void client_handler(void) { struct client_pkt *pkt; struct sockaddr_in dst; int sock, i; - unsigned char buf[32]; + unsigned char buf[32], *ip; if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { log_print("client_handler(): socket()"); return; } + ip = config_get_string("global", "master_ip", "0.0.0.0"); + log_print("starting client_handler thread"); + dst.sin_family = AF_INET; dst.sin_port = htons(7140); - inet_aton("0.0.0.0", &dst.sin_addr); + inet_aton(ip, &dst.sin_addr); if (bind(sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) { log_print("client_handler(): bind()"); diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..c462057 --- /dev/null +++ b/src/config.c @@ -0,0 +1,208 @@ +/*************************************************************************** + * Copyright (C) 03/2005 by Olaf Rempel * + * razzor@kopf-tisch.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include +#include +#include +#include + +#include "hlswmaster.h" +#include "configfile.h" +#include "list.h" + +//#define DEBUG 1 + +/* liste der geladenen plugins */ +LIST_HEAD(config_list); + +static struct conf_section * config_add_section(char *name) { + struct conf_section *section; + + if (!name) + return NULL; + + section = malloc(sizeof(struct conf_section)); + if (section) { + INIT_LIST_HEAD(§ion->list); + INIT_LIST_HEAD(§ion->tupel); + + strncpy(section->name, name, sizeof(section->name)); + list_add_tail(§ion->list, &config_list); + } + return section; +} + +static int config_add_tupel(struct conf_section *section, char *option, char *parameter) { + struct conf_tupel *tupel; + + if (!section || !option || !parameter) + return 0; + + if (!(tupel = malloc(sizeof(struct conf_tupel)))) + return 0; + + INIT_LIST_HEAD(&tupel->list); + + tupel->option = strdup(option); + tupel->parameter = strdup(parameter); + + list_add_tail(&tupel->list, §ion->tupel); + return 1; +} + +/** + * config_parse() + * parsed die configfile + * + * @param char *config + * @return false bei fehler + */ +int config_parse(char *config) { + struct conf_section *section = NULL; + FILE *fz; + int i = 0, ret = 1; + char *row, *tok, *tok2; + + if (!config) + return 0; + + if (!(row = malloc(1024))) + return 0; + + if (!(fz = fopen(config, "r"))) { + log_print("config_parse(): %s", config); + return 0; + } + + while (fgets(row, 1024, fz)) { + i++; + if (row[0] == '#' || row[0] <= ' ') { + continue; + + } else if (row[0] == '[') { + tok = strtok(row +1, " ]\n"); + section = config_add_section(tok); + if (!section) { + log_print("config_parse(): invalid section in row %d", i); + ret = 0; + break; + } + continue; + + } else if (!section) { + log_print("config_parse(): missing section in row %d", i); + ret = 0; + break; + } + + if ((tok = strtok(row, " \n")) && (tok2 = strtok(NULL, " \n"))) + if (!config_add_tupel(section, tok, tok2)) + log_print("config_parse(): invalid row %d", i); + } + + fclose(fz); + free(row); + +#ifdef DEBUG + { + struct conf_section *section; + struct conf_tupel *tupel; + + list_for_each_entry(section, &config_list, list) + list_for_each_entry(tupel, §ion->tupel, list) + printf("%s: %s = %s\n", section->name, tupel->option, tupel->parameter); + } +#endif + + return ret; +} + +/** + * config_get_section() + * gibt einen pointer auf die erste section mit dem + * angegebenen namen zurueck + * wenn nicht vorhanden NULL + * + * @param char *name + * @return struct conf_section * + */ +struct conf_section * config_get_section(char *name) { + struct conf_section *section; + + list_for_each_entry(section, &config_list, list) { + if (!strcmp(section->name, name)) + return section; + } + return NULL; +} + +/** + * config_get_parameter() + * gibt den parameter der ersten passenden option + * in einer section zurueck + * + * @param struct conf_section *section + * @param char *option + * @return char * + */ +char * config_get_parameter(struct conf_section *section, char *option) { + struct conf_tupel *tupel; + + list_for_each_entry(tupel, §ion->tupel, list) { + if (!strcmp(tupel->option, option)) + return tupel->parameter; + } + return NULL; +} + +/** + * config_get_string() + * gibt den parameter des section/option tupels zurueck + * wenn nicht vorhanden, wird def zurueckgegeben + * @param char *section + * @param chat *option + * @param char *def + * @return char * + */ +char * config_get_string(char *section, char *option, char *def) { + struct conf_section *tmp; + char *ret; + + tmp = config_get_section(section); + if (tmp && (ret = config_get_parameter(tmp, option))) + return ret; + + return def; +} + +/** + * config_get_int() + * gibt den parameter des section/option tupels zurueck + * wenn nicht vorhanden, wird def zurueckgegeben + * @param char *section + * @param char *option + * @param int def + * @return int + */ +int config_get_int(char *section, char *option, int def) { + char *ret; + + ret = config_get_string(section, option, NULL); + return ret ? atoi(ret) : def; +} diff --git a/src/daemon.c b/src/daemon.c deleted file mode 100644 index c13c922..0000000 --- a/src/daemon.c +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - * Copyright (C) 03/2005 by Olaf Rempel * - * razzor@kopf-tisch.de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -#include -#include -#include -#include - -#include "hlswmaster.h" - -/** - * daemonize() - * macht den Prozess zu einen Daemon - * und fuehrt ihn unterem user aus - * - * @param char *pw_name - * - * TODO: hier schon logging benutzen? stderr? wann exit/return? - */ -void daemonize(char *pw_name) { - int fail = 0; - pid_t pid; - struct passwd *pwl; - - if ((pid = fork()) < 0) { - log_print("daemonize(): fork()"); - exit(-1); - - } else if (pid != 0) { - /* Elternprozess beenden */ - exit(0); - - } else { - /* Kindprozess weiterlaufen lassen */ - if (setsid() == -1) { - log_print("daemonize: setsid()"); - exit(-1); - } - - umask(0) ; - - if (pw_name != NULL) { - if((pwl = getpwnam(pw_name)) == NULL) { - log_print("mkdaemon(): getpwnam(\"%s\")", pw_name); - exit(-1); - } - - if (setgid(pwl->pw_gid) != 0) { - log_print("mkdaemon(): setgid()"); - fail = 1; - } - - if (setuid(pwl->pw_uid) != 0) { - log_print("mkdaemon(): setuid()"); - fail = 1; - } - - if (fail == 0) { - log_print("user changed to: %s, pid: %d", pw_name, getpid()); - } - } - } -} diff --git a/src/logging.c b/src/logging.c index 9a1ed2d..34a9e88 100644 --- a/src/logging.c +++ b/src/logging.c @@ -24,34 +24,10 @@ #include #include +#include "configfile.h" + static FILE *log_fd = NULL; -/** - * log_close() - * schliesst das logfile - */ -void log_close() { - fclose(log_fd); -} - -/** - * log_open() - * oeffnet ein logfile - * wenn der prozess sich beendet, wird das logfile auch wieder geschlossen - * - * @param char *logfile - */ -void log_open(char *logfile) { - if ((log_fd = fopen(logfile, "a" )) == NULL) { - fprintf(stderr, "log_open(\"%s\"): %s\n", logfile, strerror(errno)); - exit(-1); - } - if (atexit(log_close) != 0) { - fprintf(stderr, "log_open(): atexit(): %s\n", strerror(errno)); - exit(-1); - } -} - /** * log_print() * schreibt eine Zeile ins Logfile oder auf stderr @@ -88,3 +64,34 @@ void log_print(const char *fmt, ...) { errno = 0; fflush(log_fd); } + +/** + * log_close() + * schliesst das logfile + */ +static void log_close() { + fclose(log_fd); +} + +/** + * log_init() + * oeffnet das logfile + * wenn der prozess sich beendet, wird das logfile auch wieder geschlossen + */ +int log_init() { + char *logfile; + + logfile = config_get_string("global", "logfile", NULL); + if (logfile) { + if ((log_fd = fopen(logfile, "a" )) == NULL) { + log_print("log_open('%s'): %s", logfile); + return 0; + } + if (atexit(log_close) != 0) { + log_print("log_open(): atexit()"); + return 0; + } + } + log_print("=========================="); + return 1; +} diff --git a/src/main.c b/src/main.c index 7d892bf..c1ee298 100644 --- a/src/main.c +++ b/src/main.c @@ -22,7 +22,6 @@ #include #include #include - #include #include "hlswmaster.h" @@ -30,39 +29,37 @@ static struct option opts[] = { {"config", 1, 0, 'c'}, {"user", 1, 0, 'u'}, - {"debug", 1, 0, 'd'}, - {"no-daemon", 0, 0, 'f'}, + {"debug", 0, 0, 'd'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; int main(int argc, char *argv[]) { - int arg = 0, code = 0; pthread_t thread1, thread2, thread3, thread4; - + int arg = 0, code = 0; + char *config = NULL, *user = NULL, *logfile; + while (code != -1) { - code = getopt_long(argc, argv, "c:u:d:fh", opts, &arg); + code = getopt_long(argc, argv, "c:u:dh", opts, &arg); switch (code) { case 'c': /* config */ + config = optarg; break; case 'u': /* user */ + user = optarg; break; case 'd': /* debug */ break; - case 'f': /* no-daemon */ - break; - case 'h': /* help */ printf("Usage: hlsw-master [options]\n" "Options: \n" " --config -c configfile use this configfile\n" " --user -u username change uid to username\n" - " --debug -d debuglevel level: 0 - 7\n" - " --no-daemon -f do not fork\n" + " --debug -d do not fork, and log to stderr\n" " --help -h this help\n" "\n"); exit(0); @@ -77,26 +74,30 @@ int main(int argc, char *argv[]) { } } + /* parse config file */ + if (!config_parse(config)) + exit(-1); - plugin_load("plugins/.libs/hlswproxy.so"); - plugin_load("plugins/.libs/q3engine.so"); - plugin_load("plugins/.libs/quake2.so"); - plugin_load("plugins/.libs/gamespy1.so"); - plugin_load("plugins/.libs/gamespy2.so"); - plugin_load("plugins/.libs/doom3.so"); - plugin_load("plugins/.libs/ut.so"); + /* start logging */ + if (!log_init()) + exit(-1); - scan_init(); + /* init scan engine */ + if (!scan_init()) + exit(-1); -// scan_transmit(); + /* load plugins */ + plugin_load_all(); + + /* startup threads */ pthread_create(&thread1, NULL, (void *)&scan_transmit, NULL); pthread_create(&thread2, NULL, (void *)&scan_receive, NULL); pthread_create(&thread3, NULL, (void *)&server_collector, NULL); pthread_create(&thread4, NULL, (void *)&client_handler, NULL); - sleep(9999); - - scan_exit(); + /* wait till dawn */ + while (1) + sleep(3600); return 0; } diff --git a/src/plugin.c b/src/plugin.c index f36a6cb..bc0868e 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -23,6 +23,7 @@ #include "hlswmaster.h" #include "plugin.h" +#include "configfile.h" #include "netpkt.h" #include "list.h" @@ -34,33 +35,87 @@ static pthread_mutex_t plugin_lock = PTHREAD_MUTEX_INITIALIZER; /** * plugin_load() - * laedt ein plugin + * laedt ein shared object, + * fuehrt wenn vorhanden init() aus + * und haengt den plugin an das ende der liste * * @param char *name * @return false on error - * - * TODO: pfadname als parameter (config-file?) - * TODO: referenz speichern? wo? wie? */ int plugin_load(char *name) { + struct hlswmaster_plugin *plugin; void *tmp; + struct conf_section *section; - if (!(tmp = dlopen(name, RTLD_NOW))) - log_print("unable to load plugin '%s'", name); + dlerror(); + if ((tmp = dlopen(name, RTLD_NOW))) { + if ((plugin = dlsym(tmp, "plugin"))) { + plugin->dlref = tmp; + + section = config_get_section(plugin->name); + + log_print("loading plugin '%s'", plugin->name); + if (!plugin->init || (plugin->init(section))) { + pthread_mutex_lock(&plugin_lock); + list_add_tail(&plugin->list, &plugin_list); + pthread_mutex_unlock(&plugin_lock); + + return 1; + } + log_print("failed to load '%s'", name); + dlclose(tmp); + return 0; + } + log_print("%s", dlerror()); + dlclose(tmp); + } + return 0; +} + + +/** + * plugin_load_all() + * laedt alle in der config angegebenen plugins + * + * @return false on error + */ +int plugin_load_all() { + struct conf_section *section; + struct conf_tupel *tupel; + + section = config_get_section("global"); + if (section) { + list_for_each_entry(tupel, §ion->tupel, list) + if (!strcmp(tupel->option, "plugin")) + plugin_load(tupel->parameter); + } return 1; } + /** - * plugin_unload() - * entfernt ein plugin + * plugin_unload_all() + * entfernt alle plugins aus der liste, + * ruft wenn vorhanden fini() auf + * und entlaed das shared object * - * @param char *name * @return false on error - * - * TODO: implementieren? oder lieber nicht? */ -int plugin_unload(char *name) { +int plugin_unload_all() { + struct hlswmaster_plugin *plugin, *tmp; + + pthread_mutex_lock(&plugin_lock); + list_for_each_entry_safe(plugin, tmp, &plugin_list, list) { + list_del(&plugin->list); + + if (plugin->fini) + plugin->fini(); + + log_print("plugin '%s' unloaded", plugin->name); + dlclose(plugin->dlref); + } + pthread_mutex_unlock(&plugin_lock); return 1; } @@ -112,7 +167,7 @@ int plugins_parse(struct net_pkt *pkt) { * @param unsigned long timeout * @return true * - * TODO: wird noch nicht benutzt + * TODO: wird noch nicht benutzt, welcher thread soll das machen? */ int plugins_gc(unsigned long timeout) { struct hlswmaster_plugin *plugin; @@ -125,32 +180,3 @@ int plugins_gc(unsigned long timeout) { pthread_mutex_unlock(&plugin_lock); return 1; } - -/** - * register_plugin() - * wird von den Plugins beim laden (durch _init())aufgerufen - * - * @param struct hlswmaster_plugin *me - */ -void register_plugin(struct hlswmaster_plugin *me) { - if (!me->init || (me->init(NULL))) { - pthread_mutex_lock(&plugin_lock); - list_add_tail((struct list_head *)me, &plugin_list); - pthread_mutex_unlock(&plugin_lock); - } -} - -/** - * register_plugin() - * wird von den Plugins beim entfernen (durch fini) aufgerufen - * - * @param struct hlswmaster_plugin *me - */ -void unregister_plugin(struct hlswmaster_plugin *me) { - pthread_mutex_lock(&plugin_lock); - list_del((struct list_head *)me); - pthread_mutex_unlock(&plugin_lock); - - if (me->fini) - me->fini(); -} diff --git a/src/scanner.c b/src/scanner.c index e449f3c..2d70607 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -30,6 +30,7 @@ #include "list.h" #include "netpkt.h" +#include "configfile.h" #include "hlswmaster.h" LIST_HEAD(send_queue); @@ -37,7 +38,7 @@ LIST_HEAD(send_queue); static int scan_sock; /** - * _pkt_queue() + * pkt_queue() * packt ein paket in die sender queue * @param struct net_pkt *pkt */ @@ -51,11 +52,14 @@ void pkt_queue(struct net_pkt *pkt) { * arbeitet die sender queue ab * * TODO: ratelimiting - * TODO: interval als parameter (config file?) */ void scan_transmit(void) { struct net_pkt *pkt, *tmp; + int interval; + interval = config_get_int("global", "scan_interval", 30); + log_print("starting tx scan thread (%ds interval)", interval); + while (1) { plugins_scan(); @@ -68,7 +72,7 @@ void scan_transmit(void) { usleep(10000); } - sleep(30); + sleep(interval); } } @@ -82,6 +86,8 @@ void scan_receive(void) { fd_set fdsel, fdcpy; int recvsize, i; + log_print("starting rx scan thread"); + FD_ZERO(&fdsel); FD_SET(scan_sock, &fdsel); @@ -113,25 +119,34 @@ void scan_receive(void) { } } +/** + * schliesst den server scan socket + */ +static void scan_close() { + close(scan_sock); +} + /** * scan_init() * initialisiert den socket fuer den server scan * @return false on error - * - * TODO: src ip als parameter (config-file?) */ int scan_init() { struct sockaddr_in dst; - int i = 1; + int i = 1, port; + char *ip; if ((scan_sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { log_print("scan_init(): socket()"); return 0; } + ip = config_get_string("global", "scan_ip", "0.0.0.0"); + port = config_get_int("global", "scan_port", 7130); + dst.sin_family = AF_INET; - dst.sin_port = htons(7130); - inet_aton("0.0.0.0", &dst.sin_addr); + dst.sin_port = htons(port); + inet_aton(ip, &dst.sin_addr); if (bind(scan_sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) { log_print("scan_init(): bind()"); @@ -142,13 +157,13 @@ int scan_init() { log_print("scan_init(): setsockopt()"); return 0; } + + if (atexit(scan_close) != 0) { + log_print("scan_init(): atexit()"); + return 0; + } + log_print("scan socket initialized (%s:%d)", ip, port); return 1; } -/** - * schliesst den server scan socket - */ -void scan_exit() { - close(scan_sock); -} diff --git a/src/serverlist.c b/src/serverlist.c index 18bc385..5a12a54 100644 --- a/src/serverlist.c +++ b/src/serverlist.c @@ -105,16 +105,18 @@ int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2) * server_collector() * loescht alte server aus der liste * baut aus den verbleibenden die client_liste auf - * - * TODO: timeout und intervall als config parameter (config file?) */ void server_collector(void) { struct game_server *server, *tmp; - unsigned long now, timeout = 60; + unsigned long now; + int timeout, interval; + timeout = config_get_int("global", "serverlist_timeout", 60); + interval = config_get_int("global", "serverlist_interval", 5); + + log_print("starting serverlist thread (%ds interval / %ds timeout)", interval, timeout); + while (1) { - sleep(5); - now = time(NULL); pthread_mutex_lock(&server_list_lock); list_for_each_entry_safe(server, tmp, &server_list, list) { @@ -136,5 +138,7 @@ void server_collector(void) { pthread_mutex_unlock(&server_list_lock); client_pkt_commit(); + + sleep(interval); } }