diff --git a/ChangeLog b/ChangeLog index 73ee35b..d62f2c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,15 @@ +* Thu 31 Mar 2005 Olaf Rempel 0.52 +- games added: avp2, bfv, igi2, jk2, jk3, rtcw, ut2k3, ut2k4 +- sendqueue removed (no need to do ratelimiting) +- serverlist.c + scanner.c merged, removing one thread +- daemonize & run-as-user support + * 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 +- supported games: bf1942, cod, cod:uo, d3, ef, et, halo, q2, q3, ut - added autoconf/automake/libtool support - plugins: replaced _init() / _fini() with ((constructor)) / ((destructor)) diff --git a/NEWS b/NEWS index 63002f1..76664a4 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1 @@ -ENDLICH IST ES SOWEIT!!!!!11 - +no news. diff --git a/README b/README index bed040b..0666458 100644 --- a/README +++ b/README @@ -1,15 +1,21 @@ -das uebliche: +linux HLSWMASTER +================ + +install: $ ./configure -$ make +$ make all +$ make install -dann fuer den master: -$ src/hlswmaster +hlswmaster.conf anpassen (evtl. plugin pfade) -oder fuer den Client: +$ src/hlswmaster -c hlswmaster.conf + +Es gibt auch einen kleinen Konsolen Client: $ tools/masterquery --help -make install gibt es schon, laeuft auch, aber der master findet -seine dann seine plugins nicht :) -ore +plugin interface: +================= +siehe plugins/skel.c + diff --git a/TODO b/TODO index 5fa1e7b..d055a5f 100644 --- a/TODO +++ b/TODO @@ -1,14 +1,33 @@ -- daemonize & userwechsel +- evtl. noch natives ut2k3/ut2k4 protocol einbauen + laut hlsw wiki/changelog geht gamespy "nicht immer" - signalhandler fuer config reread - signalhandler listen-flush + neuscannen - auf mehreren/allen interfaces gleichzeitig scannen + geht das ueberhaupt? ohne root rechte? - threads ueberwachen - threadpool fuer client-thread? -- ratelimit fuer scanner -- statistiken? +- statistiken? webserver? gamespy-export? - Makefile: stripping binarys? und natuerlich: -- weitere spiele finden -- vorhandene parser debuggen +- weitere spiele finden: + Halflife + Quake 1 + Command & Conquer Renegade + Medal of Honor: Allied Assault + Rune + Never Winter Nights + Medal of Honor: Allied Assault Spearhead + Operation Flashpoint + Operation Flashpoint Resistance + Devastation + Elite Force 2 + Medal of Honor: Allied Assault Breakthrough + Tribes 2 + Savage: The Battle for Newerth + Pain Killer + Halflife 2 + Tribes Vengeance + +- vorhandene parser debuggen & verbessern diff --git a/configure b/configure index 7a92801..96436d7 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.51. +# Generated by GNU Autoconf 2.59 for hlswmaster 0.52. # # 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.51' -PACKAGE_STRING='hlswmaster 0.51' +PACKAGE_VERSION='0.52' +PACKAGE_STRING='hlswmaster 0.52' 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.51 to adapt to many kinds of systems. +\`configure' configures hlswmaster 0.52 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.51:";; + short | recursive ) echo "Configuration of hlswmaster 0.52:";; 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.51 +hlswmaster configure 0.52 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.51, which was +It was created by hlswmaster $as_me 0.52, 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.51 + VERSION=0.52 cat >>confdefs.h <<_ACEOF @@ -21419,7 +21419,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by hlswmaster $as_me 0.51, which was +This file was extended by hlswmaster $as_me 0.52, 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.51 +hlswmaster config.status 0.52 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 94ee321..1682d07 100644 --- a/configure.in +++ b/configure.in @@ -1,8 +1,8 @@ dnl projekname, version, bugsto -AC_INIT(hlswmaster, 0.51, [Olaf Rempel ]) +AC_INIT(hlswmaster, 0.52, [Olaf Rempel ]) dnl same for automake -AM_INIT_AUTOMAKE(hlswmaster, 0.51) +AM_INIT_AUTOMAKE(hlswmaster, 0.52) dnl do not rebuild configure AM_MAINTAINER_MODE diff --git a/hlswmaster.conf b/hlswmaster.conf index f65ac78..c20dac8 100644 --- a/hlswmaster.conf +++ b/hlswmaster.conf @@ -1,19 +1,22 @@ [global] # broadcast scan source IP & PORT (udp) -scan_ip 0.0.0.0 -scan_port 7130 +#scan_ip 0.0.0.0 +#scan_port 7130 # broadcast scan every X seconds -scan_interval 30 +#scan_interval 30 # serverlist rebuild every X seconds -serverlist_interval 5 +#serverlist_interval 5 # server timeout after X seconds -serverlist_timeout 120 +#serverlist_timeout 30 + +# plugin data timeout every X seconds +#plugin_timeout 30 # master answers with this source IP -master_ip 0.0.0.0 +#master_ip 0.0.0.0 # load these plugins plugin plugins/.libs/hlswproxy.so @@ -22,10 +25,9 @@ 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 +logfile hlswmaster.log [hlswproxy] scan_ip 10.10.0.1 diff --git a/include/hlswmaster.h b/include/hlswmaster.h index 84b09ba..057ff41 100644 --- a/include/hlswmaster.h +++ b/include/hlswmaster.h @@ -3,7 +3,6 @@ #include "list.h" #include "netpkt.h" -#include "configfile.h" struct game_server { struct list_head list; @@ -17,7 +16,7 @@ struct game_server { } __attribute__ ((packed)); /* logging.c */ -int log_open(); +int log_init(char *logfile); void log_print(const char *fmt, ... ); /* plugin.c */ @@ -29,14 +28,10 @@ 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 scan_transmit(); +void scan_control(); void scan_receive(); -/* serverlist.c */ -void server_collector(); - /* client.c */ int client_pkt_add(struct game_server *server); int client_pkt_commit(); diff --git a/include/netpkt.h b/include/netpkt.h index b0d9ecd..0b42ad8 100644 --- a/include/netpkt.h +++ b/include/netpkt.h @@ -5,11 +5,7 @@ #include #include -#include "list.h" - struct net_pkt { - struct list_head list; - struct sockaddr_in addr; unsigned int size; unsigned char buf[0]; diff --git a/include/plugin.h b/include/plugin.h index eccde07..007f15d 100644 --- a/include/plugin.h +++ b/include/plugin.h @@ -5,27 +5,6 @@ #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); - -struct scan_ports { - unsigned short portlo; - unsigned short porthi; - unsigned short gameid; -}; - -extern int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size); -extern int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size); - -extern int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr); -extern int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size); -extern void * pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size); - -extern int server_add_pkt(unsigned int gameid, struct net_pkt *pkt); - -extern char * pkt_ntoa(struct net_pkt *pkt); -extern unsigned short pkt_getport(struct net_pkt *pkt); -extern int pkt_atoi(struct net_pkt *pkt, void *p); - struct hlswmaster_plugin { struct list_head list; diff --git a/include/plugin_helper.h b/include/plugin_helper.h new file mode 100644 index 0000000..e4f5036 --- /dev/null +++ b/include/plugin_helper.h @@ -0,0 +1,29 @@ +#ifndef _PLUGIN_HELPER_H +#define _PLUGIN_HELPER_H + +#include "netpkt.h" +#include "list.h" +#include "plugin.h" + +extern int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2); + +struct scan_ports { + unsigned short portlo; + unsigned short porthi; + unsigned short gameid; +}; + +extern int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size); +extern int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size); + +extern int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr); +extern int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size); +extern void * pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size); + +extern int server_add_pkt(unsigned int gameid, struct net_pkt *pkt); + +extern char * pkt_ntoa(struct net_pkt *pkt); +extern unsigned short pkt_getport(struct net_pkt *pkt); +extern int pkt_atoi(struct net_pkt *pkt, void *p); + +#endif /* _PLUGIN_HELPER_H */ diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 50eccc7..c81ab37 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1,8 +1,10 @@ AUTOMAKE_OPTIONS = foreign no-dependencies +EXTRA_DIST = skel.c + INCLUDES = -I../include -pkgdata_LTLIBRARIES = doom3.la gamespy1.la gamespy2.la hlswproxy.la q3engine.la quake2.la ut.la +pkgdata_LTLIBRARIES = doom3.la gamespy1.la gamespy2.la hlswproxy.la q3engine.la quake2.la doom3_la_SOURCES = doom3.c doom3_la_LDFLAGS = -module -avoid-version @@ -21,6 +23,3 @@ q3engine_la_LDFLAGS = -module -avoid-version quake2_la_SOURCES = quake2.c quake2_la_LDFLAGS = -module -avoid-version - -ut_la_SOURCES = ut.c -ut_la_LDFLAGS = -module -avoid-version diff --git a/plugins/Makefile.in b/plugins/Makefile.in index 1e92d63..2247891 100644 --- a/plugins/Makefile.in +++ b/plugins/Makefile.in @@ -14,7 +14,7 @@ @SET_MAKE@ -SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) $(gamespy2_la_SOURCES) $(hlswproxy_la_SOURCES) $(q3engine_la_SOURCES) $(quake2_la_SOURCES) $(ut_la_SOURCES) +SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) $(gamespy2_la_SOURCES) $(hlswproxy_la_SOURCES) $(q3engine_la_SOURCES) $(quake2_la_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ @@ -74,9 +74,6 @@ q3engine_la_OBJECTS = $(am_q3engine_la_OBJECTS) quake2_la_LIBADD = am_quake2_la_OBJECTS = quake2.lo quake2_la_OBJECTS = $(am_quake2_la_OBJECTS) -ut_la_LIBADD = -am_ut_la_OBJECTS = ut.lo -ut_la_OBJECTS = $(am_ut_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = am__depfiles_maybe = @@ -90,10 +87,10 @@ LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) \ $(gamespy2_la_SOURCES) $(hlswproxy_la_SOURCES) \ - $(q3engine_la_SOURCES) $(quake2_la_SOURCES) $(ut_la_SOURCES) + $(q3engine_la_SOURCES) $(quake2_la_SOURCES) DIST_SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) \ $(gamespy2_la_SOURCES) $(hlswproxy_la_SOURCES) \ - $(q3engine_la_SOURCES) $(quake2_la_SOURCES) $(ut_la_SOURCES) + $(q3engine_la_SOURCES) $(quake2_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -197,8 +194,9 @@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ AUTOMAKE_OPTIONS = foreign no-dependencies +EXTRA_DIST = skel.c INCLUDES = -I../include -pkgdata_LTLIBRARIES = doom3.la gamespy1.la gamespy2.la hlswproxy.la q3engine.la quake2.la ut.la +pkgdata_LTLIBRARIES = doom3.la gamespy1.la gamespy2.la hlswproxy.la q3engine.la quake2.la doom3_la_SOURCES = doom3.c doom3_la_LDFLAGS = -module -avoid-version gamespy1_la_SOURCES = gamespy1.c @@ -211,8 +209,6 @@ q3engine_la_SOURCES = q3engine.c q3engine_la_LDFLAGS = -module -avoid-version quake2_la_SOURCES = quake2.c quake2_la_LDFLAGS = -module -avoid-version -ut_la_SOURCES = ut.c -ut_la_LDFLAGS = -module -avoid-version all: all-am .SUFFIXES: @@ -285,8 +281,6 @@ q3engine.la: $(q3engine_la_OBJECTS) $(q3engine_la_DEPENDENCIES) $(LINK) -rpath $(pkgdatadir) $(q3engine_la_LDFLAGS) $(q3engine_la_OBJECTS) $(q3engine_la_LIBADD) $(LIBS) quake2.la: $(quake2_la_OBJECTS) $(quake2_la_DEPENDENCIES) $(LINK) -rpath $(pkgdatadir) $(quake2_la_LDFLAGS) $(quake2_la_OBJECTS) $(quake2_la_LIBADD) $(LIBS) -ut.la: $(ut_la_OBJECTS) $(ut_la_DEPENDENCIES) - $(LINK) -rpath $(pkgdatadir) $(ut_la_LDFLAGS) $(ut_la_OBJECTS) $(ut_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) diff --git a/plugins/doom3.c b/plugins/doom3.c index faf5d06..c611443 100644 --- a/plugins/doom3.c +++ b/plugins/doom3.c @@ -18,7 +18,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include -#include "plugin.h" +#include "plugin_helper.h" static struct scan_ports port_arr[] = { { 27666, 27673, 38 }, /* Doom 3 */ @@ -36,11 +36,11 @@ static int scan(void) { static int parse(struct net_pkt *pkt) { int gameid; - if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg))) - return 0; - if (!(gameid = pkt_check_portarr(pkt, port_arr))) return 0; + + if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg))) + return 0; server_add_pkt(gameid, pkt); return 1; diff --git a/plugins/gamespy1.c b/plugins/gamespy1.c index 68c0da2..b45d207 100644 --- a/plugins/gamespy1.c +++ b/plugins/gamespy1.c @@ -18,15 +18,25 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include -#include "plugin.h" +#include "plugin_helper.h" static struct scan_ports port_arr[] = { - { 22000, 22010, 16 }, /* Battlefield 1942 */ + { 7777, 7788, 5 }, /* ut(5), ut2k3(14), ut2k4(33) */ + { 22000, 22010, 16 }, /* bf1942(16) */ + { 23000, 23010, 35 }, /* bfv(35) */ + { 26001, 26011, 19 }, /* igi2(19) */ + { 27888, 27888, 17 }, /* avp2(17) (nur der standart-port..) */ { 0, 0, 0 } }; -static char scanmsg[] = "\\info\\"; -static char bf1942_reply[] = "\\gameId\\BF1942\\"; +static char scanmsg[] = "\\status\\"; +static char ut_reply[] = "\\gamename\\ut\\"; +static char ut2k3_reply[] = "\\gamename\\ut2\\"; +static char ut2k4_reply[] = "\\gamename\\ut2004\\"; +static char bf1942_reply[] = "\\gamename\\bfield1942\\"; +static char bfv_reply[] = "\\game_id\\bfvietnam\\"; +static char avp2_reply[] = "\\gamename\\avp2\\"; +static char igi2_reply[] = "\\gamename\\projectigi2r\\"; static char hostport_search[] = "\\hostport\\"; static int scan(void) { @@ -37,26 +47,64 @@ static int scan(void) { static int parse(struct net_pkt *pkt) { int gameid, port; void *p; - + if (!(gameid = pkt_check_portarr(pkt, port_arr))) return 0; switch (gameid) { - case 16: /* battlefield 1942 */ + case 5:/* unreal tournament 2k3 */ + if (pkt_memmem(pkt, 0, ut_reply, strlen(ut_reply))) + gameid = 5; + + /* unreal tournament 2k3 */ + else if (pkt_memmem(pkt, 0, ut2k3_reply, strlen(ut2k3_reply))) + gameid = 14; + + /* unreal tournament 2k4 */ + else if (pkt_memmem(pkt, 0, ut2k4_reply, strlen(ut2k4_reply))) + gameid = 33; + + else + return 0; + break; + + case 16:/* battlefield 1942 */ if (!pkt_memmem(pkt, 0, bf1942_reply, strlen(bf1942_reply))) return 0; + break; - p = pkt_memmem(pkt, 0, hostport_search, strlen(hostport_search)); - if (!p) + case 17:/* alien vs. predator 2 */ + if (!pkt_memmem(pkt, 0, avp2_reply, strlen(avp2_reply))) + return 0; + break; + + case 19:/* project igi2 covert strike */ + if (!pkt_memmem(pkt, 0, igi2_reply, strlen(igi2_reply))) + return 0; + break; + + case 35:/* battlefield vietnam */ + if (!pkt_memmem(pkt, 0, bfv_reply, strlen(bfv_reply))) return 0; - - port = pkt_atoi(pkt, p + strlen(hostport_search)); - server_add(gameid, pkt->addr.sin_addr.s_addr, port, ntohs(pkt->addr.sin_port)); break; default: + return 0; + } + + /* hostport angabe suchen */ + p = pkt_memmem(pkt, 0, hostport_search, strlen(hostport_search)); + if (p) { + port = pkt_atoi(pkt, p + strlen(hostport_search)); + } + + /* wenn ein hostport angegeben wurde, und das nicht der src port ist + ** beide ports in die serverliste uebernehmen + */ + if (p && port != ntohs(pkt->addr.sin_port)) { + server_add(gameid, pkt->addr.sin_addr.s_addr, port, ntohs(pkt->addr.sin_port)); + } else { server_add_pkt(gameid, pkt); - break; } return 1; diff --git a/plugins/gamespy2.c b/plugins/gamespy2.c index 5889c9a..205e850 100644 --- a/plugins/gamespy2.c +++ b/plugins/gamespy2.c @@ -18,10 +18,10 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include -#include "plugin.h" +#include "plugin_helper.h" static struct scan_ports port_arr[] = { - { 2302, 2302, 30 }, /* halo */ + { 2302, 2302, 30 }, /* halo(30) */ { 0,0,0 } }; diff --git a/plugins/hlswproxy.c b/plugins/hlswproxy.c index 739416e..79e01e8 100644 --- a/plugins/hlswproxy.c +++ b/plugins/hlswproxy.c @@ -19,19 +19,29 @@ ***************************************************************************/ #include #include -#include "plugin.h" +#include +#include +#include +#include -static char scanmsg[] = "\xff\xff\xff\xffHLSWLANSEARCH"; +#include "plugin_helper.h" -static struct _entry { +struct _entry { u_int16_t gameid; u_int32_t ip; u_int16_t port1; u_int16_t port2; } __attribute__ ((packed)); +static struct in_addr *ip_arr = NULL; +static int ip_arr_size = 0; + +static char scanmsg[] = "\xff\xff\xff\xffHLSWLANSEARCH"; + static int scan(void) { - pkt_send(NULL, 7140, scanmsg, sizeof(scanmsg)); + int i; + for (i = 0; i < ip_arr_size; i++) + pkt_send(&ip_arr[i], 7140, scanmsg, sizeof(scanmsg)); return 1; } @@ -51,13 +61,33 @@ static int parse(struct net_pkt *pkt) { static int init(struct conf_section *section) { struct conf_tupel *tupel; + int i = 0; list_for_each_entry(tupel, §ion->tupel, list) if (!strcmp(tupel->option, "scan_ip")) - log_print("hlswproxy: will scan %s", tupel->parameter); + i++; + + if (i == 0 || !(ip_arr = malloc(sizeof(struct in_addr) * i))) + return 0; + + i = 0; + list_for_each_entry(tupel, §ion->tupel, list) { + if (!strcmp(tupel->option, "scan_ip")) { + if (inet_pton(AF_INET, tupel->parameter, &ip_arr[i]) <= 0) { + log_print(" invalid ip: %s", tupel->parameter); + } else { + log_print(" adding %s", tupel->parameter); + i++; + } + } + } + ip_arr_size = i; + log_print(" added %d master server(s)", i); + return 1; } static int fini() { - + if (ip_arr_size > 0 && ip_arr) + free(ip_arr); } struct hlswmaster_plugin plugin = { diff --git a/plugins/q3engine.c b/plugins/q3engine.c index 42d363b..9571966 100644 --- a/plugins/q3engine.c +++ b/plugins/q3engine.c @@ -18,11 +18,13 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include -#include "plugin.h" +#include "plugin_helper.h" 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) */ + { 27960, 27969, 6 }, /* q3(6), ef(7), et25), rtcw(8) */ + { 28070, 28070, 12 }, /* jk2(12) TODO: UNTESTED */ + { 28960, 28963, 31 }, /* cod(31), cod:uo(42) */ + { 29070, 29070, 27 }, /* jk3(27) TODO: UNTESTED */ { 0,0,0 } }; @@ -30,8 +32,11 @@ static char scanmsg[] = "\xff\xff\xff\xffgetStatus"; static char replymsg[] = "\xff\xff\xff\xffstatusResponse"; static char q3_reply[] = "\\version\\Q3 "; -static char ef_reply[] = "\\version\\ST:V "; +static char ef_reply[] = "\\version\\ST:V HM "; +static char rtcw_reply[] = "\\version\\Wolf "; static char et_reply[] = "\\version\\ET "; +static char jk2_reply[] = "\\version\\JK2MP "; +static char jk3_reply[] = "\\version\\JAmp "; static char cod_reply[] = "\\gamename\\Call of Duty\\"; static char coduo_reply[] = "\\gamename\\CoD:United Offensive\\"; @@ -50,13 +55,16 @@ static int parse(struct net_pkt *pkt) { return 0; switch (gameid) { - case 6: /* q3, ef, et */ + case 6: /* q3, ef, et, rtcw */ if (pkt_memmem(pkt, 0, q3_reply, strlen(q3_reply))) { gameid = 6; } else if (pkt_memmem(pkt, 0, ef_reply, strlen(ef_reply))) { gameid = 7; + } else if (pkt_memmem(pkt, 0, rtcw_reply, strlen(rtcw_reply))) { + gameid = 8; + } else if (pkt_memmem(pkt, 0, et_reply, strlen(et_reply))) { gameid = 25; @@ -65,6 +73,16 @@ static int parse(struct net_pkt *pkt) { } break; + case 12: /* jedi knight 2 */ + if (!pkt_memmem(pkt, 0, jk2_reply, strlen(jk2_reply))) + return 0; + break; + + case 27: /* jedi knight 3 */ + if (!pkt_memmem(pkt, 0, jk3_reply, strlen(jk3_reply))) + return 0; + break; + case 31: /* cod, cod:uo */ if (pkt_memmem(pkt, 0, cod_reply, strlen(cod_reply))) { gameid = 31; diff --git a/plugins/quake2.c b/plugins/quake2.c index ed97262..f49d1bd 100644 --- a/plugins/quake2.c +++ b/plugins/quake2.c @@ -18,7 +18,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include -#include "plugin.h" +#include "plugin_helper.h" static char scanmsg[] = "\xff\xff\xff\xffinfo 34"; diff --git a/plugins/skel.c b/plugins/skel.c new file mode 100644 index 0000000..44018cb --- /dev/null +++ b/plugins/skel.c @@ -0,0 +1,159 @@ +/*************************************************************************** + * 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 "plugin_helper.h" + +/** + * scan() + * wird periodisch aufgerufen um server querys loszuschicken. + * + * @return int false bei fehler + */ +static int scan(void) { + char myscan[] = "hallo" + /* sendet an 255.255.255.255:8888 'hallo' */ + pkt_send(NULL, 8888, myscan, strlen(myscan)); + + /* sendet an 255.255.255.255:8888 'hallo\x00' */ + pkt_send(NULL, 8888, myscan, sizeof(myscan)); + + /* sendet an 192.168.1.100:8888 'hallo' */ + struct in_addr tmp; + inet_aton("192.168.1.100", &tmp) + pkt_send(&tmp, 8888, myscan, strlen(myscan)); + + /* an portrange(s) senden */ + struct scan_ports port_arr[] = { + { 27960, 27963, 0 }, /* von 27960-27963 scannen */ + { 28960, 28963, 0 }, /* und von 28960-28963 */ + { 0,0,0 } + }; + pkt_send_portarr(NULL, &port_arr, myscan, strlen(myscan)); + + return 1; +} + +/** + * parse() + * wird beim Empfang von Paketen aufgerufen um die Antworten zu parsen. + * Wenn das Paket fuer diesen Plugin einen Sinn ergibt, + * wird true zurueckgegeben. + * + * @param struct net_pkt *pkt - Pointer auf das empfangene Paket + * @return int true wenn das Plugin das Paket parsen konnte + */ +static int parse(struct net_pkt *pkt) { + /* checken ob das paket vom richtigen port kommt: */ + if (pkt_getport(pkt) != 27910) + return 0; + + /* bei einem port_arr checken ob es von einem der angefragten ports kommt */ + int gameid; + if (!(gameid = pkt_check_portarr(pkt, port_arr))) + return 0; + /* gameid enthaelt nun den dritten wert einer passenden port_arr zeile */ + + + /* paketinhalt checken (packet = "good morning dave\x00") */ + char mycmp1[] = "good"; + if (pkt_memcmp(pkt, 0, mycmp1, strlen(mycmp1))) + return 0; + + /* paketinhalt mit offset */ + char mycmp2[] = "morning"; + if (pkt_memcmp(pkt, 5, mycmp2, strlen(mycmp2))) + return 0; + + /* suchen ob paketinhalt vorhanden ist (packet = "blablablablabla\hostport\7777\blablabla") */ + char mymem[] = "\\hostport\\"; + void *p + p = pkt_memmem(pkt, 0, mymem, strlen(mymem)); + if (!p) + return 0; + + /* ints aus paket parsen: */ + p += strlen(mymem); + port2 = pkt_atoi(pkt, p); + + /* src ip des pakets */ + printf("server found: %s\n", pkt_ntoa(pkt)); + + /* server zu interner liste hinzufuegen: (port1 = port, port2 = 0)*/ + server_add_pkt(gameid, pkt); + + /* server mit zwei ports zur liste hinzufuegen: */ + server_add(gameid, pkt->addr.sin_addr.s_addr, port1, port2); +} + +/** + * init() + * wird direkt nach dem Ladem des Plugins aufgerufen um evtl. + * Speicher, Files/Sockets zu initialisieren + * Als Parameter wird der Pointer auf eine Liste von Optionen + * im Configfile uebergeben, die in der Configsection des Plugins + * stehen ([Section] == Pluginname) + * + * @param struct conf_section *section + * @return false bei fehler + */ +static int init(struct conf_section *section) { + /* config optionen holen (myfile in section [myplugin] */ + char *myfile = config_get_parameter(section, "myfile"); + + mybigmem = malloc(1024 * 1024); +} + +/** + * init() + * wird direkt vor dem Entfernen des Plugins aufgerufen um + * Speicher, Files/Sockets zu schliessen + * + * @return false bei fehler + */ +static int fini() { + free(mybigmem); +} + +/** + * gc() + * wird periodisch aufgerufen um Plugin interne Daten aufzufrischen + * als Parameter wird der plugin_timeout Wert uebergeben + * + * @param int timeout + * @return false bei fehler + */ +static int gc(int timeout) { + +} + +/** + * plugin + * Struktur mit Pointern auf die Funktionen. + * MUSS "plugin" heissen, damit es von dlsym() gefunden wird! + * der .name sollte dem Dateinamen entsprechen um Verwechslungen zu vermeiden + */ +struct hlswmaster_plugin plugin = { + .name = "myplugin", + .init = &init, + .fini = &fini, + .scan = &scan, + .parse = &parse, + .gc = &gc, +}; diff --git a/plugins/ut.c b/plugins/ut.c deleted file mode 100644 index 98fce1d..0000000 --- a/plugins/ut.c +++ /dev/null @@ -1,68 +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 "plugin.h" - -static struct scan_ports port_arr[] = { - { 8777, 8786, 5 }, /* Unreal Tournament (5), Ravenshield (-) */ - { 0,0,0 } -}; - -static char scanmsg[] = "REPORTQUERY"; -static char ut_reply[] = "ut "; -static char rvs_reply[] = "rvnshld 0"; - -static int scan(void) { - pkt_send_portarr(NULL, port_arr, scanmsg, strlen(scanmsg)); - return 1; -} - -static int parse(struct net_pkt *pkt) { - int gameid, port; - void *p; - - if (!(gameid = pkt_check_portarr(pkt, port_arr))) - return 0; - - switch (gameid) { - case 5: /* ut, rvs */ - if ((p = pkt_memmem(pkt, 0, ut_reply, strlen(ut_reply)))) { - port = pkt_atoi(pkt, p + strlen(ut_reply)); - server_add(gameid, pkt->addr.sin_addr.s_addr, port -1, port); - - } else if ((p = pkt_memmem(pkt, 0, rvs_reply, strlen(rvs_reply)))) { - server_add_pkt(0, pkt); - - } - break; - - default: - server_add_pkt(gameid, pkt); - break; - } - - return 1; -} - -struct hlswmaster_plugin plugin = { - .name = "ut", - .scan = &scan, - .parse = &parse, -}; diff --git a/src/Makefile.am b/src/Makefile.am index 797847e..9027b1d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,7 +3,8 @@ AUTOMAKE_OPTIONS = foreign no-dependencies INCLUDES = -I../include bin_PROGRAMS = hlswmaster -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_SOURCES = client.c config.c logging.c main.c plugin.c plugin_helper.c scanner.c \ + ../include/configfile.h ../include/hlswmaster.h ../include/list.h \ + ../include/netpkt.h ../include/plugin.h ../include/plugin_helper.h hlswmaster_LDADD = -ldl -lpthread hlswmaster_LDFLAGS = -rdynamic diff --git a/src/Makefile.in b/src/Makefile.in index 5c1cc1f..9884868 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -53,7 +53,7 @@ binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) am_hlswmaster_OBJECTS = client.$(OBJEXT) config.$(OBJEXT) \ logging.$(OBJEXT) main.$(OBJEXT) plugin.$(OBJEXT) \ - plugin_helper.$(OBJEXT) scanner.$(OBJEXT) serverlist.$(OBJEXT) + plugin_helper.$(OBJEXT) scanner.$(OBJEXT) hlswmaster_OBJECTS = $(am_hlswmaster_OBJECTS) hlswmaster_DEPENDENCIES = DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) @@ -173,8 +173,9 @@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ AUTOMAKE_OPTIONS = foreign no-dependencies INCLUDES = -I../include -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_SOURCES = client.c config.c logging.c main.c plugin.c plugin_helper.c scanner.c \ + ../include/configfile.h ../include/hlswmaster.h ../include/list.h \ + ../include/netpkt.h ../include/plugin.h ../include/plugin_helper.h hlswmaster_LDADD = -ldl -lpthread hlswmaster_LDFLAGS = -rdynamic diff --git a/src/client.c b/src/client.c index 585cc06..3b68e7e 100644 --- a/src/client.c +++ b/src/client.c @@ -29,7 +29,6 @@ #include "hlswmaster.h" #include "configfile.h" -#include "plugin.h" #include "list.h" #define HLSW_HEADER "\xFF\xFF\xFF\xFFHLSWLANSEARCH\x00" @@ -44,8 +43,8 @@ struct client_pkt { }; /* real und prepare list. enthalten die client-antworten */ -LIST_HEAD(client_pkt_list); -LIST_HEAD(client_pkt_prepare); +static LIST_HEAD(client_pkt_list); +static LIST_HEAD(client_pkt_prepare); /* sichert die real list ab */ static pthread_mutex_t pkt_list_lock = PTHREAD_MUTEX_INITIALIZER; @@ -59,7 +58,7 @@ static pthread_mutex_t pkt_list_lock = PTHREAD_MUTEX_INITIALIZER; * @return true wenn das paket noch nicht voll ist */ static inline int cpkt_not_full(const struct client_pkt *a, void *b) { - return (a->size < MAX_PKT_LEN); + return (a->size <= (MAX_PKT_LEN - HLSW_ENTRY_LEN)); } /** @@ -110,16 +109,15 @@ int client_pkt_add(struct game_server *server) { /** * client_pkt_commit() - * - * die prepare liste die echte liste und alle pakete der - * alten liste werden entfernt + * die prepare liste wird die echte liste und + * alle pakete der alten echten liste werden entfernt * * @return true */ int client_pkt_commit() { struct list_head old_list, *pkt, *tmp; - /* wenn die liste leer ist, HLSW-header verschicken */ + /* wenn die liste leer ist, nur HLSW-header verschicken */ if (list_empty(&client_pkt_prepare)) client_pkt_add_real(&client_pkt_prepare); @@ -159,7 +157,7 @@ void client_handler(void) { } ip = config_get_string("global", "master_ip", "0.0.0.0"); - log_print("starting client_handler thread"); + log_print("thread_start: client_handler (%s:7140)", ip); dst.sin_family = AF_INET; dst.sin_port = htons(7140); diff --git a/src/config.c b/src/config.c index c462057..56044bf 100644 --- a/src/config.c +++ b/src/config.c @@ -28,9 +28,15 @@ //#define DEBUG 1 -/* liste der geladenen plugins */ -LIST_HEAD(config_list); +/* liste config optionen */ +static LIST_HEAD(config_list); +/** + * config_add_section() + * fuegt der config liste ein section hinzu + * @param char *name + * @return struct conf_section * + */ static struct conf_section * config_add_section(char *name) { struct conf_section *section; @@ -48,6 +54,14 @@ static struct conf_section * config_add_section(char *name) { return section; } +/** + * config_add_tupel() + * fuegt einer config section ein werte tupel hinzu + * @param struct conf_section * + * @param char *option + * @param char *parameter + * @return false bei fehler + */ static int config_add_tupel(struct conf_section *section, char *option, char *parameter) { struct conf_tupel *tupel; @@ -66,6 +80,26 @@ static int config_add_tupel(struct conf_section *section, char *option, char *pa return 1; } +/** + * config_free() + * entfernt die config_liste aus dem Speicher + */ +static void config_free() { + struct conf_section *section, *section_tmp; + struct conf_tupel *tupel, *tupel_tmp; + + list_for_each_entry_safe(section, section_tmp, &config_list, list) { + list_for_each_entry_safe(tupel, tupel_tmp, §ion->tupel, list) { + list_del(&tupel->list); + free(tupel->option); + free(tupel->parameter); + free(tupel); + } + list_del(§ion->list); + free(section); + } +} + /** * config_parse() * parsed die configfile @@ -119,6 +153,11 @@ int config_parse(char *config) { fclose(fz); free(row); + if (atexit(config_free) != 0) { + log_print("config_parse(): atexit()"); + return 0; + } + #ifdef DEBUG { struct conf_section *section; diff --git a/src/logging.c b/src/logging.c index 34a9e88..8414469 100644 --- a/src/logging.c +++ b/src/logging.c @@ -78,19 +78,14 @@ static void log_close() { * 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; - } +int log_init(char *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 c1ee298..a275660 100644 --- a/src/main.c +++ b/src/main.c @@ -23,8 +23,11 @@ #include #include #include +#include +#include #include "hlswmaster.h" +#include "configfile.h" static struct option opts[] = { {"config", 1, 0, 'c'}, @@ -35,8 +38,8 @@ static struct option opts[] = { }; int main(int argc, char *argv[]) { - pthread_t thread1, thread2, thread3, thread4; - int arg = 0, code = 0; + pthread_t thread1, thread2, thread3; + int arg = 0, code = 0, debug = 0; char *config = NULL, *user = NULL, *logfile; while (code != -1) { @@ -52,6 +55,7 @@ int main(int argc, char *argv[]) { break; case 'd': /* debug */ + debug = 1; break; case 'h': /* help */ @@ -59,7 +63,7 @@ int main(int argc, char *argv[]) { "Options: \n" " --config -c configfile use this configfile\n" " --user -u username change uid to username\n" - " --debug -d do not fork, and log to stderr\n" + " --debug -d do not fork and log to stderr\n" " --help -h this help\n" "\n"); exit(0); @@ -74,28 +78,50 @@ int main(int argc, char *argv[]) { } } + /* userwechsel */ + if (user) { + struct passwd *pwl; + if (!(pwl = getpwnam(user))) { + log_print("unknown user: %s", user); + exit(-1); + } + + if (setgid(pwl->pw_gid) || setuid(pwl->pw_uid)) { + log_print("setgid/setuid"); + exit(-1); + } + } + /* parse config file */ if (!config_parse(config)) exit(-1); - /* start logging */ - if (!log_init()) - exit(-1); - + /* check logfile */ + logfile = config_get_string("global", "logfile", NULL); + if (logfile && !debug) { + /* start logging */ + if (!log_init(logfile)) + exit(-1); + + /* zum daemon mutieren */ + daemon(-1, 0); + } + + log_print("hlswmaster started (user: %s, pid: %d)", getpwuid(getuid())->pw_name, getpid()); + /* init scan engine */ if (!scan_init()) exit(-1); - /* load plugins */ + /* load plugins */ plugin_load_all(); /* startup threads */ - pthread_create(&thread1, NULL, (void *)&scan_transmit, NULL); + pthread_create(&thread1, NULL, (void *)&scan_control, 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); + pthread_create(&thread3, NULL, (void *)&client_handler, NULL); - /* wait till dawn */ + /* wait untill d00msday */ while (1) sleep(3600); diff --git a/src/plugin.c b/src/plugin.c index bc0868e..774cde8 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -28,7 +28,7 @@ #include "list.h" /* liste der geladenen plugins */ -LIST_HEAD(plugin_list); +static LIST_HEAD(plugin_list); /* sichert die plugin list UND die plugins ab */ static pthread_mutex_t plugin_lock = PTHREAD_MUTEX_INITIALIZER; @@ -48,28 +48,27 @@ int plugin_load(char *name) { struct conf_section *section; 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); } + log_print("%s", dlerror()); return 0; } @@ -166,8 +165,6 @@ int plugins_parse(struct net_pkt *pkt) { * * @param unsigned long timeout * @return true - * - * TODO: wird noch nicht benutzt, welcher thread soll das machen? */ int plugins_gc(unsigned long timeout) { struct hlswmaster_plugin *plugin; diff --git a/src/plugin_helper.c b/src/plugin_helper.c index 49de018..e78e085 100644 --- a/src/plugin_helper.c +++ b/src/plugin_helper.c @@ -32,37 +32,9 @@ #include #include "hlswmaster.h" -#include "plugin.h" #include "netpkt.h" - -/** - * pkt_queue() - * erzeugt ein net_pkt aus den parametern und legt es in die send queue - * - * @param struct in_addr *dstip - pointer auf eine IP, wenn NULL wird broadcast angenommen - * @param unsigned int dstport - destination port - * @param char *buf - pointer auf den zu sendenen speicherbereich - * @param unsigned int size - groesse des speicherbereichs - * @return false bei fehler - */ -int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size) { - struct net_pkt *pkt; - - if (!(pkt = malloc(sizeof(struct net_pkt) + size))) - return 0; - - INIT_LIST_HEAD(&pkt->list); - - pkt->addr.sin_family = AF_INET; - pkt->addr.sin_port = htons(dstport); - pkt->addr.sin_addr.s_addr = (dstip ? dstip->s_addr : 0xFFFFFFFF); - - pkt->size = size; - memcpy(pkt->buf, buf, size); - - pkt_queue(pkt); - return 1; -} +#include "plugin.h" +#include "plugin_helper.h" /** * pkt_queue_portarr() diff --git a/src/scanner.c b/src/scanner.c index 2d70607..4c64064 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -27,52 +27,191 @@ #include #include #include +#include #include "list.h" #include "netpkt.h" #include "configfile.h" #include "hlswmaster.h" -LIST_HEAD(send_queue); +#define DEBUG 1 +/* die interne serverliste */ +static LIST_HEAD(serverlist); + +/* sichert die server liste */ +static pthread_mutex_t serverlist_lock = PTHREAD_MUTEX_INITIALIZER; + +/* scan socket */ static int scan_sock; /** - * pkt_queue() - * packt ein paket in die sender queue - * @param struct net_pkt *pkt + * server_cmp() + * LIST_FIND helper + * + * @param struct game_server *a + * @param struct game_server *b + * @return true wenn es sich um den selben server handelt */ -void pkt_queue(struct net_pkt *pkt) { - list_add_tail(&pkt->list, &send_queue); +static inline int server_cmp(const struct game_server *a, struct game_server *b) { + return (a->gameid == b->gameid && a->ip == b->ip && + a->port1 == b->port1 && a->port2 == b->port2); } /** - * scan_transmit() - * triggert den scan der plugins - * arbeitet die sender queue ab + * server_add() + * fuegt der internen serverliste einen server hinzu + * wenn dieser server schon in der liste vorhanden ist, wird nur + * die modtime angepasst * - * TODO: ratelimiting + * @param unsigned int gameid + * @param struct in_addr ip + * @param u_int16_t port1 + * @param u_int16_t port2 + * @return false bei fehler */ -void scan_transmit(void) { - struct net_pkt *pkt, *tmp; - int interval; +int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2) { + struct game_server server, *nserver; - interval = config_get_int("global", "scan_interval", 30); - log_print("starting tx scan thread (%ds interval)", interval); + server.gameid = gameid; + server.ip = ip; + server.port1 = port1; + server.port2 = port2; + + pthread_mutex_lock(&serverlist_lock); + + /* diesen server in der liste suchen */ + nserver = LIST_FIND(&serverlist, server_cmp, struct game_server *, &server); + if (!nserver) { + /* neuen eintrag anlegen */ + if (!(nserver = malloc(sizeof(struct game_server)))) { + pthread_mutex_unlock(&serverlist_lock); + log_print("server_add(): malloc()"); + return 0; + } +#ifdef DEBUG + { + struct in_addr tmp; + tmp.s_addr = server.ip; + printf("server_add_new: gameid=%2d ip=%15s port1=%5d port2=%5d\n", + server.gameid, inet_ntoa(tmp), server.port1, server.port2); + } +#endif + memcpy(nserver, &server, sizeof(struct game_server)); + list_add_tail(&nserver->list, &serverlist); + } + + /* modtime anpassen */ + nserver->modtime = time(NULL); + + pthread_mutex_unlock(&serverlist_lock); + return 1; +} + +/** + * serverlist_refresh() + * loescht alte server aus der liste + * baut aus den verbleibenden die client_liste auf + * + * @param long timeout + */ +static void serverlist_refresh(long timeout) { + struct game_server *server, *tmp; + long now = time(NULL); + + pthread_mutex_lock(&serverlist_lock); + list_for_each_entry_safe(server, tmp, &serverlist, list) { + if ((server->modtime + timeout) < now) { +#ifdef DEBUG + { + struct in_addr tmp2; + tmp2.s_addr = server->ip; + printf("server timeout: gameid=%2d ip=%15s port1=%5d port2=%5d\n", + server->gameid, inet_ntoa(tmp2), server->port1, server->port2); + } +#endif + list_del(&server->list); + free(server); + + } else { + client_pkt_add(server); + } + } + pthread_mutex_unlock(&serverlist_lock); + + client_pkt_commit(); +} + +/** + * pkt_send() + * schickt ein paket ab + * + * @param struct in_addr *dstip - pointer auf eine IP, wenn NULL wird broadcast angenommen + * @param unsigned int dstport - destination port + * @param char *buf - pointer auf den zu sendenen speicherbereich + * @param unsigned int size - groesse des speicherbereichs + * @return false bei fehler + */ +int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size) { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(dstport); + addr.sin_addr.s_addr = (dstip ? dstip->s_addr : 0xFFFFFFFF); + + //inet_aton("10.4.1.1", &addr.sin_addr); + + if (sendto(scan_sock, buf, size, 0, (struct sockaddr *)&addr, sizeof(addr)) < 0) + log_print("scan_send(): sendto()"); + + usleep(10000); + return 1; +} + +/** + * scan_control() + * triggert den scan der plugins + * arbeitet dann die sender queue ab + * triggert den gc der plugins + */ +void scan_control(void) { + struct net_pkt *pkt, *tmp; + long now; + long last_plugin_gc = 0, last_list_refresh = 0, last_scan = 0; + int plugin_timeout, list_timeout, list_refresh, scan_interval; + + plugin_timeout = config_get_int("global", "plugin_timeout", 30); + list_timeout = config_get_int("global", "serverlist_timeout", 30); + list_refresh = config_get_int("global", "serverlist_refresh", 5); + scan_interval = config_get_int("global", "scan_interval", 30); + + log_print("thread_start: scan_control"); + log_print(" scan_interval: %ds", scan_interval); + log_print(" serverlist_refresh: %ds", list_refresh); + log_print(" serverlist_timeout: %ds", list_timeout); + log_print(" plugin_timeout: %d", plugin_timeout); while (1) { - plugins_scan(); - - list_for_each_entry_safe(pkt, tmp, &send_queue, list) { - if (sendto(scan_sock, pkt->buf, pkt->size, 0, (struct sockaddr *)&pkt->addr, sizeof(pkt->addr)) < 0) - log_print("scan_transmit(): sendto()"); - - list_del(&pkt->list); - free(pkt); - usleep(10000); + now = time(NULL); + + /* interne plugin daten aufraeumen */ + if (last_plugin_gc + plugin_timeout < now) { + last_plugin_gc = now; + plugins_gc(plugin_timeout); } - sleep(interval); + /* server liste aufraeumen, und neue client pkts erzeugen */ + if (last_list_refresh + list_refresh < now) { + last_list_refresh = now; + serverlist_refresh(list_timeout); + } + + /* neuen scan ausloesen */ + if (last_scan + scan_interval < now) { + last_scan = now; + plugins_scan(); + } + + sleep(1); } } @@ -86,7 +225,7 @@ void scan_receive(void) { fd_set fdsel, fdcpy; int recvsize, i; - log_print("starting rx scan thread"); + log_print("thread_start: scan_receiver"); FD_ZERO(&fdsel); FD_SET(scan_sock, &fdsel); @@ -166,4 +305,3 @@ int scan_init() { log_print("scan socket initialized (%s:%d)", ip, port); return 1; } - diff --git a/src/serverlist.c b/src/serverlist.c deleted file mode 100644 index 5a12a54..0000000 --- a/src/serverlist.c +++ /dev/null @@ -1,144 +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 -#include -#include -#include -#include -#include - -#include "hlswmaster.h" -#include "plugin.h" -#include "list.h" - -#define DEBUG 1 - -LIST_HEAD(server_list); - -/* sichert die server liste */ -static pthread_mutex_t server_list_lock = PTHREAD_MUTEX_INITIALIZER; - -/** - * server_cmp() - * LIST_FIND helper - * - * @param struct game_server *a - * @param struct game_server *b - * @return true wenn es sich um den selben server handelt - */ -static inline int server_cmp(const struct game_server *a, struct game_server *b) { - return (a->gameid == b->gameid && a->ip == b->ip && - a->port1 == b->port1 && a->port2 == b->port2); -} - -/** - * server_add() - * fuegt der internen serverliste einen server hinzu - * wenn dieser server schon in der liste vorhanden ist, wird nur - * die modtime angepasst - * - * @param unsigned int gameid - * @param struct in_addr ip - * @param u_int16_t port1 - * @param u_int16_t port2 - * @return false bei fehler - */ -int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2) { - struct game_server server, *nserver; - - server.gameid = gameid; - server.ip = ip; - server.port1 = port1; - server.port2 = port2; - - pthread_mutex_lock(&server_list_lock); - - /* diesen server in der liste suchen */ - nserver = LIST_FIND(&server_list, server_cmp, struct game_server *, &server); - if (!nserver) { - /* neuen eintrag anlegen */ - if (!(nserver = malloc(sizeof(struct game_server)))) { - pthread_mutex_unlock(&server_list_lock); - return 0; - } -#ifdef DEBUG - { - struct in_addr tmp; - tmp.s_addr = server.ip; - printf("server_add_new: gameid=%2d ip=%15s port1=%5d port2=%5d\n", - server.gameid, inet_ntoa(tmp), server.port1, server.port2); - } -#endif - memcpy(nserver, &server, sizeof(struct game_server)); - list_add_tail(&nserver->list, &server_list); - } - /* modtime anpassen */ - nserver->modtime = time(NULL); - - pthread_mutex_unlock(&server_list_lock); - - return 1; -} - -/** - * server_collector() - * loescht alte server aus der liste - * baut aus den verbleibenden die client_liste auf - */ -void server_collector(void) { - struct game_server *server, *tmp; - 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) { - now = time(NULL); - pthread_mutex_lock(&server_list_lock); - list_for_each_entry_safe(server, tmp, &server_list, list) { - if ((server->modtime + timeout) < now) { -#ifdef DEBUG - { - struct in_addr tmp2; - tmp2.s_addr = server->ip; - printf("server timeout: gameid=%2d ip=%15s port1=%5d port2=%5d\n", - server->gameid, inet_ntoa(tmp2), server->port1, server->port2); - } -#endif - list_del(&server->list); - free(server); - continue; - } - client_pkt_add(server); - } - pthread_mutex_unlock(&server_list_lock); - - client_pkt_commit(); - - sleep(interval); - } -} diff --git a/tools/masterquery.c b/tools/masterquery.c index 079a60e..62f2b51 100644 --- a/tools/masterquery.c +++ b/tools/masterquery.c @@ -66,14 +66,7 @@ static char *id2name[] = { "Call of Duty: United Offensive" }; -static struct option opts[] = { - {"destination", 1, 0, 'd'}, - {"intervall", 1, 0, 'i'}, - {"help", 0, 0, 'h'}, - {0, 0, 0, 0} -}; - -static int sock; +static int sock, verbose = 0; static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size) { struct _entry *server; @@ -84,16 +77,19 @@ static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size) { inet_ntoa(src->sin_addr), ntohs(src->sin_port), size); } else { - printf("received hlsw packet from: %15s:%-5d size=%d\n", - inet_ntoa(src->sin_addr), ntohs(src->sin_port), size); + printf("received hlsw packet from: %15s:%-5d size=%d\n count=%d", + inet_ntoa(src->sin_addr), ntohs(src->sin_port), size, + ((size > sizeof(hlswheader)) ? (size - sizeof(hlswheader)) / sizeof(struct _entry) : 0)); - server = pkt + sizeof(hlswheader); - while ((void *)server < pkt + size) { - tmp.s_addr = server->ip; - printf(" ip=%15s port1=%5d port2=%5d gameid=%2d (%s)\n", - inet_ntoa(tmp), server->port1, server->port2, - server->gameid, id2name[server->gameid]); - server++; + if (verbose) { + server = pkt + sizeof(hlswheader); + while ((void *)server < pkt + size) { + tmp.s_addr = server->ip; + printf(" ip=%15s port1=%5d port2=%5d gameid=%2d (%s)\n", + inet_ntoa(tmp), server->port1, server->port2, + server->gameid, id2name[server->gameid]); + server++; + } } } } @@ -136,19 +132,17 @@ static int scan_receive() { tv.tv_sec = 1; tv.tv_usec = 0; - while (1) { + /* timeout */ + while (tv.tv_sec > 0 || tv.tv_usec > 0) { + if (select(FD_SETSIZE, &fdsel, NULL, NULL, &tv) < 0) { - perror("select"); + perror("select()"); return -1; } - /* timeout: our exit */ - if (tv.tv_sec == 0 && tv.tv_usec == 0) - break; - /* get packetsize */ if (ioctl(sock, FIONREAD, &recvsize) == -1) { - perror("ioctl"); + perror("ioctl()"); return -1; } @@ -166,10 +160,17 @@ static int scan_receive() { free(pkt); } } - return 0; } +static struct option opts[] = { + {"destination", 1, 0, 'd'}, + {"intervall", 1, 0, 'i'}, + {"verbose", 0, 0, 'v'}, + {"help", 0, 0, 'h'}, + {0, 0, 0, 0} +}; + int main(int argc, char *argv[]) { struct sockaddr_in dst; int arg = 0, code = 0; @@ -180,7 +181,7 @@ int main(int argc, char *argv[]) { inet_aton("255.255.255.255", &dst.sin_addr); while (code != -1) { - code = getopt_long(argc, argv, "d:i:h", opts, &arg); + code = getopt_long(argc, argv, "d:i:vh", opts, &arg); switch (code) { case 'd': /* destination */ @@ -198,11 +199,16 @@ int main(int argc, char *argv[]) { } break; + case 'v': /* verbose */ + verbose = 1; + break; + case 'h': /* help */ printf("Usage: masterquery [options]\n" "Options: \n" " --destination -d scan destination \n" " --intervall -i scan intervall in seconds\n" + " --verbose -v verbose: show packet content\n" " --help -h this help\n" "\n"); exit(0); @@ -220,18 +226,14 @@ int main(int argc, char *argv[]) { if (scan_init()) exit(-1); - while (1) { + do { if (scan_transmit(&dst)) exit(-1); if (scan_receive()) exit(-1); - if (freq < 0) - break; - - sleep(freq -1); - } + } while (freq >= 1 && !sleep(freq -1)); close(sock); return 0;