Version 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
This commit is contained in:
Olaf Rempel 2006-02-02 16:43:41 +01:00
parent 0d0650008f
commit 7f0b2fd78f
32 changed files with 698 additions and 461 deletions

View File

@ -1,8 +1,15 @@
* Thu 31 Mar 2005 Olaf Rempel <razzor@kopf-tisch.de> 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 <razzor@kopf-tisch.de> 0.51 * Sun 27 Mar 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.51
- added configfile parser, added configfile support to subsystems - added configfile parser, added configfile support to subsystems
- plugins: replaced con/destructor with dlsym() peeking - plugins: replaced con/destructor with dlsym() peeking
* Sat 26 Mar 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.50 * Sat 26 Mar 2005 Olaf Rempel <razzor@kopf-tisch.de> 0.50
- supported games: bf1942, cod, cod:uo, d3, ef, et, halo, q2, q3, ut
- added autoconf/automake/libtool support - added autoconf/automake/libtool support
- plugins: replaced _init() / _fini() with ((constructor)) / ((destructor)) - plugins: replaced _init() / _fini() with ((constructor)) / ((destructor))

3
NEWS
View File

@ -1,2 +1 @@
ENDLICH IST ES SOWEIT!!!!!11 no news.

22
README
View File

@ -1,15 +1,21 @@
das uebliche: linux HLSWMASTER
================
install:
$ ./configure $ ./configure
$ make $ make all
$ make install
dann fuer den master: hlswmaster.conf anpassen (evtl. plugin pfade)
$ src/hlswmaster
oder fuer den Client: $ src/hlswmaster -c hlswmaster.conf
Es gibt auch einen kleinen Konsolen Client:
$ tools/masterquery --help $ 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

29
TODO
View File

@ -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 fuer config reread
- signalhandler listen-flush + neuscannen - signalhandler listen-flush + neuscannen
- auf mehreren/allen interfaces gleichzeitig scannen - auf mehreren/allen interfaces gleichzeitig scannen
geht das ueberhaupt? ohne root rechte?
- threads ueberwachen - threads ueberwachen
- threadpool fuer client-thread? - threadpool fuer client-thread?
- ratelimit fuer scanner - statistiken? webserver? gamespy-export?
- statistiken?
- Makefile: stripping binarys? - Makefile: stripping binarys?
und natuerlich: und natuerlich:
- weitere spiele finden - weitere spiele finden:
- vorhandene parser debuggen 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

20
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # 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 <Olaf Rempel <razzor@kopf-tisch.de>>. # Report bugs to <Olaf Rempel <razzor@kopf-tisch.de>>.
# #
@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package. # Identity of this package.
PACKAGE_NAME='hlswmaster' PACKAGE_NAME='hlswmaster'
PACKAGE_TARNAME='hlswmaster' PACKAGE_TARNAME='hlswmaster'
PACKAGE_VERSION='0.51' PACKAGE_VERSION='0.52'
PACKAGE_STRING='hlswmaster 0.51' PACKAGE_STRING='hlswmaster 0.52'
PACKAGE_BUGREPORT='Olaf Rempel <razzor@kopf-tisch.de>' PACKAGE_BUGREPORT='Olaf Rempel <razzor@kopf-tisch.de>'
# Factoring default headers for most tests. # 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. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF 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]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1019,7 +1019,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of hlswmaster 0.51:";; short | recursive ) echo "Configuration of hlswmaster 0.52:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1160,7 +1160,7 @@ fi
test -n "$ac_init_help" && exit 0 test -n "$ac_init_help" && exit 0
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
hlswmaster configure 0.51 hlswmaster configure 0.52
generated by GNU Autoconf 2.59 generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc. Copyright (C) 2003 Free Software Foundation, Inc.
@ -1174,7 +1174,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. 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 generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@ $ $0 $@
@ -1818,7 +1818,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE=hlswmaster PACKAGE=hlswmaster
VERSION=0.51 VERSION=0.52
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -21419,7 +21419,7 @@ _ASBOX
} >&5 } >&5
cat >&5 <<_CSEOF 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 generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -21482,7 +21482,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\ ac_cs_version="\\
hlswmaster config.status 0.51 hlswmaster config.status 0.52
configured by $0, generated by GNU Autoconf 2.59, configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"

View File

@ -1,8 +1,8 @@
dnl projekname, version, bugsto dnl projekname, version, bugsto
AC_INIT(hlswmaster, 0.51, [Olaf Rempel <razzor@kopf-tisch.de>]) AC_INIT(hlswmaster, 0.52, [Olaf Rempel <razzor@kopf-tisch.de>])
dnl same for automake dnl same for automake
AM_INIT_AUTOMAKE(hlswmaster, 0.51) AM_INIT_AUTOMAKE(hlswmaster, 0.52)
dnl do not rebuild configure dnl do not rebuild configure
AM_MAINTAINER_MODE AM_MAINTAINER_MODE

View File

@ -1,19 +1,22 @@
[global] [global]
# broadcast scan source IP & PORT (udp) # broadcast scan source IP & PORT (udp)
scan_ip 0.0.0.0 #scan_ip 0.0.0.0
scan_port 7130 #scan_port 7130
# broadcast scan every X seconds # broadcast scan every X seconds
scan_interval 30 #scan_interval 30
# serverlist rebuild every X seconds # serverlist rebuild every X seconds
serverlist_interval 5 #serverlist_interval 5
# server timeout after X seconds # 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 answers with this source IP
master_ip 0.0.0.0 #master_ip 0.0.0.0
# load these plugins # load these plugins
plugin plugins/.libs/hlswproxy.so plugin plugins/.libs/hlswproxy.so
@ -22,10 +25,9 @@ plugin plugins/.libs/quake2.so
plugin plugins/.libs/gamespy1.so plugin plugins/.libs/gamespy1.so
plugin plugins/.libs/gamespy2.so plugin plugins/.libs/gamespy2.so
plugin plugins/.libs/doom3.so plugin plugins/.libs/doom3.so
plugin plugins/.libs/ut.so
# logging # logging
# logfile hlswmaster.log logfile hlswmaster.log
[hlswproxy] [hlswproxy]
scan_ip 10.10.0.1 scan_ip 10.10.0.1

View File

@ -3,7 +3,6 @@
#include "list.h" #include "list.h"
#include "netpkt.h" #include "netpkt.h"
#include "configfile.h"
struct game_server { struct game_server {
struct list_head list; struct list_head list;
@ -17,7 +16,7 @@ struct game_server {
} __attribute__ ((packed)); } __attribute__ ((packed));
/* logging.c */ /* logging.c */
int log_open(); int log_init(char *logfile);
void log_print(const char *fmt, ... ); void log_print(const char *fmt, ... );
/* plugin.c */ /* plugin.c */
@ -29,14 +28,10 @@ int plugins_parse(struct net_pkt *pkt);
int plugins_gc(unsigned long timeout); int plugins_gc(unsigned long timeout);
/* scanner.c */ /* scanner.c */
void pkt_queue(struct net_pkt *pkt);
int scan_init(); int scan_init();
void scan_transmit(); void scan_control();
void scan_receive(); void scan_receive();
/* serverlist.c */
void server_collector();
/* client.c */ /* client.c */
int client_pkt_add(struct game_server *server); int client_pkt_add(struct game_server *server);
int client_pkt_commit(); int client_pkt_commit();

View File

@ -5,11 +5,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#include "list.h"
struct net_pkt { struct net_pkt {
struct list_head list;
struct sockaddr_in addr; struct sockaddr_in addr;
unsigned int size; unsigned int size;
unsigned char buf[0]; unsigned char buf[0];

View File

@ -5,27 +5,6 @@
#include "configfile.h" #include "configfile.h"
#include "list.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 hlswmaster_plugin {
struct list_head list; struct list_head list;

29
include/plugin_helper.h Normal file
View File

@ -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 */

View File

@ -1,8 +1,10 @@
AUTOMAKE_OPTIONS = foreign no-dependencies AUTOMAKE_OPTIONS = foreign no-dependencies
EXTRA_DIST = skel.c
INCLUDES = -I../include 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_SOURCES = doom3.c
doom3_la_LDFLAGS = -module -avoid-version doom3_la_LDFLAGS = -module -avoid-version
@ -21,6 +23,3 @@ q3engine_la_LDFLAGS = -module -avoid-version
quake2_la_SOURCES = quake2.c quake2_la_SOURCES = quake2.c
quake2_la_LDFLAGS = -module -avoid-version quake2_la_LDFLAGS = -module -avoid-version
ut_la_SOURCES = ut.c
ut_la_LDFLAGS = -module -avoid-version

View File

@ -14,7 +14,7 @@
@SET_MAKE@ @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@ srcdir = @srcdir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
@ -74,9 +74,6 @@ q3engine_la_OBJECTS = $(am_q3engine_la_OBJECTS)
quake2_la_LIBADD = quake2_la_LIBADD =
am_quake2_la_OBJECTS = quake2.lo am_quake2_la_OBJECTS = quake2.lo
quake2_la_OBJECTS = $(am_quake2_la_OBJECTS) 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) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = depcomp =
am__depfiles_maybe = am__depfiles_maybe =
@ -90,10 +87,10 @@ LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@ $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) \ SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) \
$(gamespy2_la_SOURCES) $(hlswproxy_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) \ DIST_SOURCES = $(doom3_la_SOURCES) $(gamespy1_la_SOURCES) \
$(gamespy2_la_SOURCES) $(hlswproxy_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 ETAGS = etags
CTAGS = ctags CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -197,8 +194,9 @@ sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@ sysconfdir = @sysconfdir@
target_alias = @target_alias@ target_alias = @target_alias@
AUTOMAKE_OPTIONS = foreign no-dependencies AUTOMAKE_OPTIONS = foreign no-dependencies
EXTRA_DIST = skel.c
INCLUDES = -I../include 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_SOURCES = doom3.c
doom3_la_LDFLAGS = -module -avoid-version doom3_la_LDFLAGS = -module -avoid-version
gamespy1_la_SOURCES = gamespy1.c gamespy1_la_SOURCES = gamespy1.c
@ -211,8 +209,6 @@ q3engine_la_SOURCES = q3engine.c
q3engine_la_LDFLAGS = -module -avoid-version q3engine_la_LDFLAGS = -module -avoid-version
quake2_la_SOURCES = quake2.c quake2_la_SOURCES = quake2.c
quake2_la_LDFLAGS = -module -avoid-version quake2_la_LDFLAGS = -module -avoid-version
ut_la_SOURCES = ut.c
ut_la_LDFLAGS = -module -avoid-version
all: all-am all: all-am
.SUFFIXES: .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) $(LINK) -rpath $(pkgdatadir) $(q3engine_la_LDFLAGS) $(q3engine_la_OBJECTS) $(q3engine_la_LIBADD) $(LIBS)
quake2.la: $(quake2_la_OBJECTS) $(quake2_la_DEPENDENCIES) quake2.la: $(quake2_la_OBJECTS) $(quake2_la_DEPENDENCIES)
$(LINK) -rpath $(pkgdatadir) $(quake2_la_LDFLAGS) $(quake2_la_OBJECTS) $(quake2_la_LIBADD) $(LIBS) $(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: mostlyclean-compile:
-rm -f *.$(OBJEXT) -rm -f *.$(OBJEXT)

View File

@ -18,7 +18,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/ ***************************************************************************/
#include <string.h> #include <string.h>
#include "plugin.h" #include "plugin_helper.h"
static struct scan_ports port_arr[] = { static struct scan_ports port_arr[] = {
{ 27666, 27673, 38 }, /* Doom 3 */ { 27666, 27673, 38 }, /* Doom 3 */
@ -36,11 +36,11 @@ static int scan(void) {
static int parse(struct net_pkt *pkt) { static int parse(struct net_pkt *pkt) {
int gameid; int gameid;
if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg)))
return 0;
if (!(gameid = pkt_check_portarr(pkt, port_arr))) if (!(gameid = pkt_check_portarr(pkt, port_arr)))
return 0; return 0;
if (pkt_memcmp(pkt, 0, replymsg, strlen(replymsg)))
return 0;
server_add_pkt(gameid, pkt); server_add_pkt(gameid, pkt);
return 1; return 1;

View File

@ -18,15 +18,25 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/ ***************************************************************************/
#include <string.h> #include <string.h>
#include "plugin.h" #include "plugin_helper.h"
static struct scan_ports port_arr[] = { 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 } { 0, 0, 0 }
}; };
static char scanmsg[] = "\\info\\"; static char scanmsg[] = "\\status\\";
static char bf1942_reply[] = "\\gameId\\BF1942\\"; 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 char hostport_search[] = "\\hostport\\";
static int scan(void) { static int scan(void) {
@ -37,26 +47,64 @@ static int scan(void) {
static int parse(struct net_pkt *pkt) { static int parse(struct net_pkt *pkt) {
int gameid, port; int gameid, port;
void *p; void *p;
if (!(gameid = pkt_check_portarr(pkt, port_arr))) if (!(gameid = pkt_check_portarr(pkt, port_arr)))
return 0; return 0;
switch (gameid) { 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))) if (!pkt_memmem(pkt, 0, bf1942_reply, strlen(bf1942_reply)))
return 0; return 0;
break;
p = pkt_memmem(pkt, 0, hostport_search, strlen(hostport_search)); case 17:/* alien vs. predator 2 */
if (!p) 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; 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; break;
default: 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); server_add_pkt(gameid, pkt);
break;
} }
return 1; return 1;

View File

@ -18,10 +18,10 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/ ***************************************************************************/
#include <string.h> #include <string.h>
#include "plugin.h" #include "plugin_helper.h"
static struct scan_ports port_arr[] = { static struct scan_ports port_arr[] = {
{ 2302, 2302, 30 }, /* halo */ { 2302, 2302, 30 }, /* halo(30) */
{ 0,0,0 } { 0,0,0 }
}; };

View File

@ -19,19 +19,29 @@
***************************************************************************/ ***************************************************************************/
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "plugin.h" #include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
static char scanmsg[] = "\xff\xff\xff\xffHLSWLANSEARCH"; #include "plugin_helper.h"
static struct _entry { struct _entry {
u_int16_t gameid; u_int16_t gameid;
u_int32_t ip; u_int32_t ip;
u_int16_t port1; u_int16_t port1;
u_int16_t port2; u_int16_t port2;
} __attribute__ ((packed)); } __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) { 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; return 1;
} }
@ -51,13 +61,33 @@ static int parse(struct net_pkt *pkt) {
static int init(struct conf_section *section) { static int init(struct conf_section *section) {
struct conf_tupel *tupel; struct conf_tupel *tupel;
int i = 0;
list_for_each_entry(tupel, &section->tupel, list) list_for_each_entry(tupel, &section->tupel, list)
if (!strcmp(tupel->option, "scan_ip")) 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, &section->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() { static int fini() {
if (ip_arr_size > 0 && ip_arr)
free(ip_arr);
} }
struct hlswmaster_plugin plugin = { struct hlswmaster_plugin plugin = {

View File

@ -18,11 +18,13 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/ ***************************************************************************/
#include <string.h> #include <string.h>
#include "plugin.h" #include "plugin_helper.h"
static struct scan_ports port_arr[] = { static struct scan_ports port_arr[] = {
{ 27960, 27969, 6 }, /* Quake3(6), Elite Force(7), Enemy Territory(25) */ { 27960, 27969, 6 }, /* q3(6), ef(7), et25), rtcw(8) */
{ 28960, 28963, 31 }, /* Call of Duty(31), Call of Duty: United Offensive (42) */ { 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 } { 0,0,0 }
}; };
@ -30,8 +32,11 @@ static char scanmsg[] = "\xff\xff\xff\xffgetStatus";
static char replymsg[] = "\xff\xff\xff\xffstatusResponse"; static char replymsg[] = "\xff\xff\xff\xffstatusResponse";
static char q3_reply[] = "\\version\\Q3 "; 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 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 cod_reply[] = "\\gamename\\Call of Duty\\";
static char coduo_reply[] = "\\gamename\\CoD:United Offensive\\"; static char coduo_reply[] = "\\gamename\\CoD:United Offensive\\";
@ -50,13 +55,16 @@ static int parse(struct net_pkt *pkt) {
return 0; return 0;
switch (gameid) { switch (gameid) {
case 6: /* q3, ef, et */ case 6: /* q3, ef, et, rtcw */
if (pkt_memmem(pkt, 0, q3_reply, strlen(q3_reply))) { if (pkt_memmem(pkt, 0, q3_reply, strlen(q3_reply))) {
gameid = 6; gameid = 6;
} else if (pkt_memmem(pkt, 0, ef_reply, strlen(ef_reply))) { } else if (pkt_memmem(pkt, 0, ef_reply, strlen(ef_reply))) {
gameid = 7; 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))) { } else if (pkt_memmem(pkt, 0, et_reply, strlen(et_reply))) {
gameid = 25; gameid = 25;
@ -65,6 +73,16 @@ static int parse(struct net_pkt *pkt) {
} }
break; 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 */ case 31: /* cod, cod:uo */
if (pkt_memmem(pkt, 0, cod_reply, strlen(cod_reply))) { if (pkt_memmem(pkt, 0, cod_reply, strlen(cod_reply))) {
gameid = 31; gameid = 31;

View File

@ -18,7 +18,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/ ***************************************************************************/
#include <string.h> #include <string.h>
#include "plugin.h" #include "plugin_helper.h"
static char scanmsg[] = "\xff\xff\xff\xffinfo 34"; static char scanmsg[] = "\xff\xff\xff\xffinfo 34";

159
plugins/skel.c Normal file
View File

@ -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 <string.h>
#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,
};

View File

@ -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 <string.h>
#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,
};

View File

@ -3,7 +3,8 @@ AUTOMAKE_OPTIONS = foreign no-dependencies
INCLUDES = -I../include INCLUDES = -I../include
bin_PROGRAMS = hlswmaster bin_PROGRAMS = hlswmaster
hlswmaster_SOURCES = client.c config.c logging.c main.c plugin.c plugin_helper.c scanner.c serverlist.c \ 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/configfile.h ../include/hlswmaster.h ../include/list.h \
../include/netpkt.h ../include/plugin.h ../include/plugin_helper.h
hlswmaster_LDADD = -ldl -lpthread hlswmaster_LDADD = -ldl -lpthread
hlswmaster_LDFLAGS = -rdynamic hlswmaster_LDFLAGS = -rdynamic

View File

@ -53,7 +53,7 @@ binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS) PROGRAMS = $(bin_PROGRAMS)
am_hlswmaster_OBJECTS = client.$(OBJEXT) config.$(OBJEXT) \ am_hlswmaster_OBJECTS = client.$(OBJEXT) config.$(OBJEXT) \
logging.$(OBJEXT) main.$(OBJEXT) plugin.$(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_OBJECTS = $(am_hlswmaster_OBJECTS)
hlswmaster_DEPENDENCIES = hlswmaster_DEPENDENCIES =
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
@ -173,8 +173,9 @@ sysconfdir = @sysconfdir@
target_alias = @target_alias@ target_alias = @target_alias@
AUTOMAKE_OPTIONS = foreign no-dependencies AUTOMAKE_OPTIONS = foreign no-dependencies
INCLUDES = -I../include INCLUDES = -I../include
hlswmaster_SOURCES = client.c config.c logging.c main.c plugin.c plugin_helper.c scanner.c serverlist.c \ 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/configfile.h ../include/hlswmaster.h ../include/list.h \
../include/netpkt.h ../include/plugin.h ../include/plugin_helper.h
hlswmaster_LDADD = -ldl -lpthread hlswmaster_LDADD = -ldl -lpthread
hlswmaster_LDFLAGS = -rdynamic hlswmaster_LDFLAGS = -rdynamic

View File

@ -29,7 +29,6 @@
#include "hlswmaster.h" #include "hlswmaster.h"
#include "configfile.h" #include "configfile.h"
#include "plugin.h"
#include "list.h" #include "list.h"
#define HLSW_HEADER "\xFF\xFF\xFF\xFFHLSWLANSEARCH\x00" #define HLSW_HEADER "\xFF\xFF\xFF\xFFHLSWLANSEARCH\x00"
@ -44,8 +43,8 @@ struct client_pkt {
}; };
/* real und prepare list. enthalten die client-antworten */ /* real und prepare list. enthalten die client-antworten */
LIST_HEAD(client_pkt_list); static LIST_HEAD(client_pkt_list);
LIST_HEAD(client_pkt_prepare); static LIST_HEAD(client_pkt_prepare);
/* sichert die real list ab */ /* sichert die real list ab */
static pthread_mutex_t pkt_list_lock = PTHREAD_MUTEX_INITIALIZER; 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 * @return true wenn das paket noch nicht voll ist
*/ */
static inline int cpkt_not_full(const struct client_pkt *a, void *b) { 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() * client_pkt_commit()
* * die prepare liste wird die echte liste und
* die prepare liste die echte liste und alle pakete der * alle pakete der alten echten liste werden entfernt
* alten liste werden entfernt
* *
* @return true * @return true
*/ */
int client_pkt_commit() { int client_pkt_commit() {
struct list_head old_list, *pkt, *tmp; 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)) if (list_empty(&client_pkt_prepare))
client_pkt_add_real(&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"); 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_family = AF_INET;
dst.sin_port = htons(7140); dst.sin_port = htons(7140);

View File

@ -28,9 +28,15 @@
//#define DEBUG 1 //#define DEBUG 1
/* liste der geladenen plugins */ /* liste config optionen */
LIST_HEAD(config_list); 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) { static struct conf_section * config_add_section(char *name) {
struct conf_section *section; struct conf_section *section;
@ -48,6 +54,14 @@ static struct conf_section * config_add_section(char *name) {
return section; 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) { static int config_add_tupel(struct conf_section *section, char *option, char *parameter) {
struct conf_tupel *tupel; struct conf_tupel *tupel;
@ -66,6 +80,26 @@ static int config_add_tupel(struct conf_section *section, char *option, char *pa
return 1; 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, &section->tupel, list) {
list_del(&tupel->list);
free(tupel->option);
free(tupel->parameter);
free(tupel);
}
list_del(&section->list);
free(section);
}
}
/** /**
* config_parse() * config_parse()
* parsed die configfile * parsed die configfile
@ -119,6 +153,11 @@ int config_parse(char *config) {
fclose(fz); fclose(fz);
free(row); free(row);
if (atexit(config_free) != 0) {
log_print("config_parse(): atexit()");
return 0;
}
#ifdef DEBUG #ifdef DEBUG
{ {
struct conf_section *section; struct conf_section *section;

View File

@ -78,19 +78,14 @@ static void log_close() {
* oeffnet das logfile * oeffnet das logfile
* wenn der prozess sich beendet, wird das logfile auch wieder geschlossen * wenn der prozess sich beendet, wird das logfile auch wieder geschlossen
*/ */
int log_init() { int log_init(char *logfile) {
char *logfile; if ((log_fd = fopen(logfile, "a" )) == NULL) {
log_print("log_open('%s'): %s", logfile);
logfile = config_get_string("global", "logfile", NULL); return 0;
if (logfile) { }
if ((log_fd = fopen(logfile, "a" )) == NULL) { if (atexit(log_close) != 0) {
log_print("log_open('%s'): %s", logfile); log_print("log_open(): atexit()");
return 0; return 0;
}
if (atexit(log_close) != 0) {
log_print("log_open(): atexit()");
return 0;
}
} }
log_print("=========================="); log_print("==========================");
return 1; return 1;

View File

@ -23,8 +23,11 @@
#include <string.h> #include <string.h>
#include <pthread.h> #include <pthread.h>
#include <getopt.h> #include <getopt.h>
#include <sys/stat.h>
#include <pwd.h>
#include "hlswmaster.h" #include "hlswmaster.h"
#include "configfile.h"
static struct option opts[] = { static struct option opts[] = {
{"config", 1, 0, 'c'}, {"config", 1, 0, 'c'},
@ -35,8 +38,8 @@ static struct option opts[] = {
}; };
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
pthread_t thread1, thread2, thread3, thread4; pthread_t thread1, thread2, thread3;
int arg = 0, code = 0; int arg = 0, code = 0, debug = 0;
char *config = NULL, *user = NULL, *logfile; char *config = NULL, *user = NULL, *logfile;
while (code != -1) { while (code != -1) {
@ -52,6 +55,7 @@ int main(int argc, char *argv[]) {
break; break;
case 'd': /* debug */ case 'd': /* debug */
debug = 1;
break; break;
case 'h': /* help */ case 'h': /* help */
@ -59,7 +63,7 @@ int main(int argc, char *argv[]) {
"Options: \n" "Options: \n"
" --config -c configfile use this configfile\n" " --config -c configfile use this configfile\n"
" --user -u username change uid to username\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" " --help -h this help\n"
"\n"); "\n");
exit(0); 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 */ /* parse config file */
if (!config_parse(config)) if (!config_parse(config))
exit(-1); exit(-1);
/* start logging */ /* check logfile */
if (!log_init()) logfile = config_get_string("global", "logfile", NULL);
exit(-1); 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 */ /* init scan engine */
if (!scan_init()) if (!scan_init())
exit(-1); exit(-1);
/* load plugins */ /* load plugins */
plugin_load_all(); plugin_load_all();
/* startup threads */ /* 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(&thread2, NULL, (void *)&scan_receive, NULL);
pthread_create(&thread3, NULL, (void *)&server_collector, NULL); pthread_create(&thread3, NULL, (void *)&client_handler, NULL);
pthread_create(&thread4, NULL, (void *)&client_handler, NULL);
/* wait till dawn */ /* wait untill d00msday */
while (1) while (1)
sleep(3600); sleep(3600);

View File

@ -28,7 +28,7 @@
#include "list.h" #include "list.h"
/* liste der geladenen plugins */ /* liste der geladenen plugins */
LIST_HEAD(plugin_list); static LIST_HEAD(plugin_list);
/* sichert die plugin list UND die plugins ab */ /* sichert die plugin list UND die plugins ab */
static pthread_mutex_t plugin_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t plugin_lock = PTHREAD_MUTEX_INITIALIZER;
@ -48,28 +48,27 @@ int plugin_load(char *name) {
struct conf_section *section; struct conf_section *section;
dlerror(); dlerror();
if ((tmp = dlopen(name, RTLD_NOW))) { if ((tmp = dlopen(name, RTLD_NOW))) {
if ((plugin = dlsym(tmp, "plugin"))) { if ((plugin = dlsym(tmp, "plugin"))) {
plugin->dlref = tmp; plugin->dlref = tmp;
section = config_get_section(plugin->name); section = config_get_section(plugin->name);
log_print("loading plugin '%s'", plugin->name); log_print("loading plugin '%s'", plugin->name);
if (!plugin->init || (plugin->init(section))) { if (!plugin->init || (plugin->init(section))) {
pthread_mutex_lock(&plugin_lock); pthread_mutex_lock(&plugin_lock);
list_add_tail(&plugin->list, &plugin_list); list_add_tail(&plugin->list, &plugin_list);
pthread_mutex_unlock(&plugin_lock); pthread_mutex_unlock(&plugin_lock);
return 1; return 1;
} }
log_print("failed to load '%s'", name); log_print("failed to load '%s'", name);
dlclose(tmp); dlclose(tmp);
return 0; return 0;
} }
log_print("%s", dlerror());
dlclose(tmp); dlclose(tmp);
} }
log_print("%s", dlerror());
return 0; return 0;
} }
@ -166,8 +165,6 @@ int plugins_parse(struct net_pkt *pkt) {
* *
* @param unsigned long timeout * @param unsigned long timeout
* @return true * @return true
*
* TODO: wird noch nicht benutzt, welcher thread soll das machen?
*/ */
int plugins_gc(unsigned long timeout) { int plugins_gc(unsigned long timeout) {
struct hlswmaster_plugin *plugin; struct hlswmaster_plugin *plugin;

View File

@ -32,37 +32,9 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "hlswmaster.h" #include "hlswmaster.h"
#include "plugin.h"
#include "netpkt.h" #include "netpkt.h"
#include "plugin.h"
/** #include "plugin_helper.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;
}
/** /**
* pkt_queue_portarr() * pkt_queue_portarr()

View File

@ -27,52 +27,191 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <pthread.h> #include <pthread.h>
#include <time.h>
#include "list.h" #include "list.h"
#include "netpkt.h" #include "netpkt.h"
#include "configfile.h" #include "configfile.h"
#include "hlswmaster.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; static int scan_sock;
/** /**
* pkt_queue() * server_cmp()
* packt ein paket in die sender queue * LIST_FIND helper
* @param struct net_pkt *pkt *
* @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) { static inline int server_cmp(const struct game_server *a, struct game_server *b) {
list_add_tail(&pkt->list, &send_queue); return (a->gameid == b->gameid && a->ip == b->ip &&
a->port1 == b->port1 && a->port2 == b->port2);
} }
/** /**
* scan_transmit() * server_add()
* triggert den scan der plugins * fuegt der internen serverliste einen server hinzu
* arbeitet die sender queue ab * 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) { int server_add(u_int16_t gameid, u_int32_t ip, u_int16_t port1, u_int16_t port2) {
struct net_pkt *pkt, *tmp; struct game_server server, *nserver;
int interval;
interval = config_get_int("global", "scan_interval", 30); server.gameid = gameid;
log_print("starting tx scan thread (%ds interval)", interval); 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) { while (1) {
plugins_scan(); now = time(NULL);
list_for_each_entry_safe(pkt, tmp, &send_queue, list) { /* interne plugin daten aufraeumen */
if (sendto(scan_sock, pkt->buf, pkt->size, 0, (struct sockaddr *)&pkt->addr, sizeof(pkt->addr)) < 0) if (last_plugin_gc + plugin_timeout < now) {
log_print("scan_transmit(): sendto()"); last_plugin_gc = now;
plugins_gc(plugin_timeout);
list_del(&pkt->list);
free(pkt);
usleep(10000);
} }
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; fd_set fdsel, fdcpy;
int recvsize, i; int recvsize, i;
log_print("starting rx scan thread"); log_print("thread_start: scan_receiver");
FD_ZERO(&fdsel); FD_ZERO(&fdsel);
FD_SET(scan_sock, &fdsel); FD_SET(scan_sock, &fdsel);
@ -166,4 +305,3 @@ int scan_init() {
log_print("scan socket initialized (%s:%d)", ip, port); log_print("scan socket initialized (%s:%d)", ip, port);
return 1; return 1;
} }

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
#include <pthread.h>
#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);
}
}

View File

@ -66,14 +66,7 @@ static char *id2name[] = {
"Call of Duty: United Offensive" "Call of Duty: United Offensive"
}; };
static struct option opts[] = { static int sock, verbose = 0;
{"destination", 1, 0, 'd'},
{"intervall", 1, 0, 'i'},
{"help", 0, 0, 'h'},
{0, 0, 0, 0}
};
static int sock;
static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size) { static void parse_pkt(struct sockaddr_in *src, void *pkt, unsigned int size) {
struct _entry *server; 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); inet_ntoa(src->sin_addr), ntohs(src->sin_port), size);
} else { } else {
printf("received hlsw packet from: %15s:%-5d size=%d\n", printf("received hlsw packet from: %15s:%-5d size=%d\n count=%d",
inet_ntoa(src->sin_addr), ntohs(src->sin_port), size); inet_ntoa(src->sin_addr), ntohs(src->sin_port), size,
((size > sizeof(hlswheader)) ? (size - sizeof(hlswheader)) / sizeof(struct _entry) : 0));
server = pkt + sizeof(hlswheader); if (verbose) {
while ((void *)server < pkt + size) { server = pkt + sizeof(hlswheader);
tmp.s_addr = server->ip; while ((void *)server < pkt + size) {
printf(" ip=%15s port1=%5d port2=%5d gameid=%2d (%s)\n", tmp.s_addr = server->ip;
inet_ntoa(tmp), server->port1, server->port2, printf(" ip=%15s port1=%5d port2=%5d gameid=%2d (%s)\n",
server->gameid, id2name[server->gameid]); inet_ntoa(tmp), server->port1, server->port2,
server++; server->gameid, id2name[server->gameid]);
server++;
}
} }
} }
} }
@ -136,19 +132,17 @@ static int scan_receive() {
tv.tv_sec = 1; tv.tv_sec = 1;
tv.tv_usec = 0; 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) { if (select(FD_SETSIZE, &fdsel, NULL, NULL, &tv) < 0) {
perror("select"); perror("select()");
return -1; return -1;
} }
/* timeout: our exit */
if (tv.tv_sec == 0 && tv.tv_usec == 0)
break;
/* get packetsize */ /* get packetsize */
if (ioctl(sock, FIONREAD, &recvsize) == -1) { if (ioctl(sock, FIONREAD, &recvsize) == -1) {
perror("ioctl"); perror("ioctl()");
return -1; return -1;
} }
@ -166,10 +160,17 @@ static int scan_receive() {
free(pkt); free(pkt);
} }
} }
return 0; 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[]) { int main(int argc, char *argv[]) {
struct sockaddr_in dst; struct sockaddr_in dst;
int arg = 0, code = 0; int arg = 0, code = 0;
@ -180,7 +181,7 @@ int main(int argc, char *argv[]) {
inet_aton("255.255.255.255", &dst.sin_addr); inet_aton("255.255.255.255", &dst.sin_addr);
while (code != -1) { 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) { switch (code) {
case 'd': /* destination */ case 'd': /* destination */
@ -198,11 +199,16 @@ int main(int argc, char *argv[]) {
} }
break; break;
case 'v': /* verbose */
verbose = 1;
break;
case 'h': /* help */ case 'h': /* help */
printf("Usage: masterquery [options]\n" printf("Usage: masterquery [options]\n"
"Options: \n" "Options: \n"
" --destination -d scan destination <ip>\n" " --destination -d scan destination <ip>\n"
" --intervall -i scan intervall in seconds\n" " --intervall -i scan intervall in seconds\n"
" --verbose -v verbose: show packet content\n"
" --help -h this help\n" " --help -h this help\n"
"\n"); "\n");
exit(0); exit(0);
@ -220,18 +226,14 @@ int main(int argc, char *argv[]) {
if (scan_init()) if (scan_init())
exit(-1); exit(-1);
while (1) { do {
if (scan_transmit(&dst)) if (scan_transmit(&dst))
exit(-1); exit(-1);
if (scan_receive()) if (scan_receive())
exit(-1); exit(-1);
if (freq < 0) } while (freq >= 1 && !sleep(freq -1));
break;
sleep(freq -1);
}
close(sock); close(sock);
return 0; return 0;