rewrite
This commit is contained in:
parent
2363f1de47
commit
ce59a8853e
|
@ -0,0 +1,35 @@
|
||||||
|
VERSION := v2.00
|
||||||
|
|
||||||
|
CFLAGS := -O2 -pipe -Wall -DVERSION='"$(VERSION)"'
|
||||||
|
LDFLAGS := -ldl -rdynamic
|
||||||
|
|
||||||
|
HLSWMASTER_SRC := configfile.o event.o gamelist.o hlswmaster.o logging.o \
|
||||||
|
netpkt.o plugin.o plugin_helper.o scanner.o server.o
|
||||||
|
|
||||||
|
PLUGINS := $(wildcard p_*.c)
|
||||||
|
|
||||||
|
all: hlswmaster masterquery $(PLUGINS:.c=.so)
|
||||||
|
|
||||||
|
hlswmaster: $(HLSWMASTER_SRC)
|
||||||
|
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
masterquery: masterquery.o
|
||||||
|
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
%.so: %_sh.o
|
||||||
|
$(LD) -shared -o $@ $<
|
||||||
|
|
||||||
|
%_sh.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -fPIC -c $< -o $@
|
||||||
|
|
||||||
|
%.d: %.c
|
||||||
|
$(CC) $(CFLAGS) -MM -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f hlswmaster masterquery *.so *.d *.o *.log
|
||||||
|
|
||||||
|
DEPS := $(wildcard *.c)
|
||||||
|
-include $(DEPS:.c=.d)
|
196
client.c
196
client.c
|
@ -1,196 +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 <pthread.h>
|
|
||||||
|
|
||||||
#include "hlswmaster.h"
|
|
||||||
#include "configfile.h"
|
|
||||||
#include "list.h"
|
|
||||||
|
|
||||||
#define HLSW_HEADER "\xFF\xFF\xFF\xFFHLSWLANSEARCH\x00"
|
|
||||||
#define HLSW_HEADER_LEN 0x12
|
|
||||||
#define HLSW_ENTRY_LEN 10
|
|
||||||
#define MAX_PKT_LEN (HLSW_HEADER_LEN + HLSW_ENTRY_LEN * 140)
|
|
||||||
|
|
||||||
struct client_pkt {
|
|
||||||
struct list_head list;
|
|
||||||
unsigned int size;
|
|
||||||
unsigned char buf[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
/** working list (wird zu den clients gesendet) */
|
|
||||||
static LIST_HEAD(client_pkt_list);
|
|
||||||
|
|
||||||
/** prepare list (wird im hintergrund zusammengebaut) */
|
|
||||||
static LIST_HEAD(client_pkt_prepare);
|
|
||||||
|
|
||||||
/** sichert die work list ab */
|
|
||||||
static pthread_mutex_t client_pkt_list_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* client_pkt_not_full()
|
|
||||||
* prueft ob ein client-paket komplett belegt ist
|
|
||||||
*
|
|
||||||
* @param *cpkt pointer auf paket das getestet wird
|
|
||||||
* @param *unused
|
|
||||||
* @return true wenn das paket noch nicht voll ist
|
|
||||||
*/
|
|
||||||
static inline int client_pkt_not_full(const struct client_pkt *cpkt, void *unused)
|
|
||||||
{
|
|
||||||
return (cpkt->size <= (MAX_PKT_LEN - HLSW_ENTRY_LEN));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* client_pkt_add_real()
|
|
||||||
* erzeugt eine neues client_pkt und fuegt es einer liste hinzu
|
|
||||||
*
|
|
||||||
* @param *list liste die das neue paket aufnimmt
|
|
||||||
* @return pointer auf ein neues paket oder NULL bei fehler
|
|
||||||
*/
|
|
||||||
static struct client_pkt * client_pkt_add_real(struct list_head *list)
|
|
||||||
{
|
|
||||||
struct client_pkt *cpkt;
|
|
||||||
|
|
||||||
cpkt = malloc(sizeof(struct client_pkt) + MAX_PKT_LEN);
|
|
||||||
if (cpkt) {
|
|
||||||
INIT_LIST_HEAD(&cpkt->list);
|
|
||||||
|
|
||||||
/* kopier den hlsw header in das client paket */
|
|
||||||
memcpy(cpkt->buf, HLSW_HEADER, HLSW_HEADER_LEN);
|
|
||||||
cpkt->size = HLSW_HEADER_LEN;
|
|
||||||
|
|
||||||
/* am anfang eingliedern! (suche nach freien paket schneller) */
|
|
||||||
list_add(&cpkt->list, list);
|
|
||||||
}
|
|
||||||
return cpkt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* client_pkt_add()
|
|
||||||
* fuegt der client_pkt liste einen server hinzu, wenn kein platz
|
|
||||||
* im aktuellen paket vorhanden ist, wird ein neues paket allokiert
|
|
||||||
*
|
|
||||||
* @param *server pointer den server
|
|
||||||
* @return false bei fehler
|
|
||||||
*/
|
|
||||||
int client_pkt_add(struct game_server *server)
|
|
||||||
{
|
|
||||||
struct client_pkt *cpkt;
|
|
||||||
|
|
||||||
/* sucht ein freies paket, oder erzeugt eins */
|
|
||||||
cpkt = LIST_FIND(&client_pkt_prepare, client_pkt_not_full, struct client_pkt *, NULL);
|
|
||||||
if (!cpkt && !(cpkt = client_pkt_add_real(&client_pkt_prepare)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* kopiert den server eintrag in das client paket */
|
|
||||||
memcpy((void *)&cpkt->buf + cpkt->size, &server->gameid, HLSW_ENTRY_LEN);
|
|
||||||
cpkt->size += HLSW_ENTRY_LEN;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* client_pkt_commit()
|
|
||||||
* die prepare liste und die work liste werden ausgetauscht
|
|
||||||
* alle pakete der alten work liste werden entfernt
|
|
||||||
*
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
int client_pkt_commit()
|
|
||||||
{
|
|
||||||
struct list_head old_list, *cpkt, *tmp;
|
|
||||||
|
|
||||||
/* wenn die liste leer ist, nur HLSW-header verschicken */
|
|
||||||
if (list_empty(&client_pkt_prepare))
|
|
||||||
client_pkt_add_real(&client_pkt_prepare);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&client_pkt_list_lock);
|
|
||||||
|
|
||||||
/* old_list wird head der work list */
|
|
||||||
list_add(&old_list, &client_pkt_list);
|
|
||||||
list_del(&client_pkt_list);
|
|
||||||
|
|
||||||
/* client_pkt_list wird head der prepare list */
|
|
||||||
list_add(&client_pkt_list, &client_pkt_prepare);
|
|
||||||
list_del_init(&client_pkt_prepare);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&client_pkt_list_lock);
|
|
||||||
|
|
||||||
/* alle alten pakete entfernen */
|
|
||||||
list_for_each_safe(cpkt, tmp, &old_list) {
|
|
||||||
list_del(cpkt);
|
|
||||||
free(cpkt);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* client_handler()
|
|
||||||
* empfaengt und beantwortet die HLSW anfragen der clients
|
|
||||||
*/
|
|
||||||
void client_handler(void)
|
|
||||||
{
|
|
||||||
struct client_pkt *cpkt;
|
|
||||||
struct sockaddr_in dst;
|
|
||||||
int sock, i;
|
|
||||||
unsigned char buf[32], *ip;
|
|
||||||
|
|
||||||
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
||||||
log_print("client_handler(): socket()");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ip = config_get_string("global", "master_ip", "0.0.0.0");
|
|
||||||
log_print("thread_start: client_handler (%s:7140)", ip);
|
|
||||||
|
|
||||||
dst.sin_family = AF_INET;
|
|
||||||
dst.sin_port = htons(7140);
|
|
||||||
inet_aton(ip, &dst.sin_addr);
|
|
||||||
|
|
||||||
if (bind(sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) {
|
|
||||||
log_print("client_handler(): bind()");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* auf clientanfrage warten */
|
|
||||||
i = sizeof(struct sockaddr_in);
|
|
||||||
recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&dst, &i);
|
|
||||||
|
|
||||||
/* testen ob es sich um ein HLSW anforderung handelt */
|
|
||||||
if (memcmp(buf, HLSW_HEADER, HLSW_HEADER_LEN))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&client_pkt_list_lock);
|
|
||||||
|
|
||||||
/* pakete aus der work list senden */
|
|
||||||
list_for_each_entry(cpkt, &client_pkt_list, list)
|
|
||||||
sendto(sock, cpkt->buf, cpkt->size, 0, (struct sockaddr *)&dst, sizeof(dst));
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&client_pkt_list_lock);
|
|
||||||
}
|
|
||||||
}
|
|
263
config.c
263
config.c
|
@ -1,263 +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 <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "hlswmaster.h"
|
|
||||||
#include "configfile.h"
|
|
||||||
#include "list.h"
|
|
||||||
|
|
||||||
//#define DEBUG 1
|
|
||||||
|
|
||||||
/** liste der config-sections */
|
|
||||||
static LIST_HEAD(config_list);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* config_add_section()
|
|
||||||
* allokiert eine neue section und fuegt sie der config liste hinzu
|
|
||||||
*
|
|
||||||
* @param *name name der section
|
|
||||||
* @return pointer auf die section, oder NULL bei fehler
|
|
||||||
*
|
|
||||||
* @todo sectionname ist nicht eindeutig
|
|
||||||
*/
|
|
||||||
static struct conf_section * config_add_section(char *name)
|
|
||||||
{
|
|
||||||
struct conf_section *section;
|
|
||||||
|
|
||||||
if (!name)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
section = malloc(sizeof(struct conf_section));
|
|
||||||
if (section) {
|
|
||||||
INIT_LIST_HEAD(§ion->list);
|
|
||||||
INIT_LIST_HEAD(§ion->tupel);
|
|
||||||
|
|
||||||
strncpy(section->name, name, sizeof(section->name));
|
|
||||||
list_add_tail(§ion->list, &config_list);
|
|
||||||
}
|
|
||||||
return section;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* config_add_tupel()
|
|
||||||
* fuegt einer section ein config tupel hinzu
|
|
||||||
*
|
|
||||||
* @param *section config section
|
|
||||||
* @param *option name der option
|
|
||||||
* @param *parameter wert der option
|
|
||||||
* @return false bei fehler
|
|
||||||
*/
|
|
||||||
static int config_add_tupel(struct conf_section *section, char *option, char *parameter)
|
|
||||||
{
|
|
||||||
struct conf_tupel *tupel;
|
|
||||||
|
|
||||||
if (!section || !option || !parameter)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!(tupel = malloc(sizeof(struct conf_tupel))))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&tupel->list);
|
|
||||||
|
|
||||||
tupel->option = strdup(option);
|
|
||||||
tupel->parameter = strdup(parameter);
|
|
||||||
|
|
||||||
list_add_tail(&tupel->list, §ion->tupel);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* config_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
|
|
||||||
*
|
|
||||||
* @param *config filename des configfiles
|
|
||||||
* @return false bei fehler
|
|
||||||
*/
|
|
||||||
int config_parse(char *config)
|
|
||||||
{
|
|
||||||
struct conf_section *section = NULL;
|
|
||||||
FILE *fz;
|
|
||||||
int i = 0, ret = 1;
|
|
||||||
char *row, *tok, *tok2;
|
|
||||||
|
|
||||||
if (!config)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!(row = malloc(1024)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!(fz = fopen(config, "r"))) {
|
|
||||||
log_print("config_parse(): %s", config);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (fgets(row, 1024, fz)) {
|
|
||||||
i++;
|
|
||||||
|
|
||||||
/* kommentar oder leere zeile */
|
|
||||||
if (row[0] == '#' || row[0] <= ' ') {
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* neue section */
|
|
||||||
} else if (row[0] == '[') {
|
|
||||||
tok = strtok(row +1, " ]\n");
|
|
||||||
section = config_add_section(tok);
|
|
||||||
if (!section) {
|
|
||||||
log_print("config_parse(): invalid section in row %d", i);
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* option, aber es gab noch keine section */
|
|
||||||
} else if (!section) {
|
|
||||||
log_print("config_parse(): missing section in row %d", i);
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* option */
|
|
||||||
if ((tok = strtok(row, " \n")) && (tok2 = strtok(NULL, " \n")))
|
|
||||||
if (!config_add_tupel(section, tok, tok2))
|
|
||||||
log_print("config_parse(): invalid row %d", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fz);
|
|
||||||
free(row);
|
|
||||||
|
|
||||||
/* beim beenden die liste wieder freigeben */
|
|
||||||
if (atexit(config_free) != 0) {
|
|
||||||
log_print("config_parse(): atexit()");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
{
|
|
||||||
struct conf_section *section;
|
|
||||||
struct conf_tupel *tupel;
|
|
||||||
|
|
||||||
list_for_each_entry(section, &config_list, list)
|
|
||||||
list_for_each_entry(tupel, §ion->tupel, list)
|
|
||||||
printf("%s: %s = %s\n", section->name, tupel->option, tupel->parameter);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* config_get_section()
|
|
||||||
* gibt eine benannte section zurueck
|
|
||||||
*
|
|
||||||
* @param *name name der section
|
|
||||||
* @return pointer auf die section, oder NULL bei fehler
|
|
||||||
*/
|
|
||||||
struct conf_section * config_get_section(char *name)
|
|
||||||
{
|
|
||||||
struct conf_section *section;
|
|
||||||
|
|
||||||
list_for_each_entry(section, &config_list, list) {
|
|
||||||
if (!strcmp(section->name, name))
|
|
||||||
return section;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* config_get_parameter()
|
|
||||||
* gibt den parameter der ersten passenden option
|
|
||||||
* in einer section zurueck
|
|
||||||
*
|
|
||||||
* @param *section pointer auf die section
|
|
||||||
* @param *option option name
|
|
||||||
* @return pointer auf den parameter string oder NULL bei fehler
|
|
||||||
*/
|
|
||||||
char * config_get_parameter(struct conf_section *section, char *option)
|
|
||||||
{
|
|
||||||
struct conf_tupel *tupel;
|
|
||||||
|
|
||||||
list_for_each_entry(tupel, §ion->tupel, list) {
|
|
||||||
if (!strcmp(tupel->option, option))
|
|
||||||
return tupel->parameter;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* config_get_string()
|
|
||||||
* gibt den parameter des section/option tupels zurueck
|
|
||||||
*
|
|
||||||
* @param *section name der section
|
|
||||||
* @param *option name der option
|
|
||||||
* @param *def default string
|
|
||||||
* @return parameter string oder default string bei fehler
|
|
||||||
*/
|
|
||||||
char * config_get_string(char *section, char *option, char *def)
|
|
||||||
{
|
|
||||||
struct conf_section *tmp;
|
|
||||||
char *ret;
|
|
||||||
|
|
||||||
tmp = config_get_section(section);
|
|
||||||
if (tmp && (ret = config_get_parameter(tmp, option)))
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* config_get_int()
|
|
||||||
* gibt den parameter des section/option tupels zurueck
|
|
||||||
*
|
|
||||||
* @param *section name der section
|
|
||||||
* @param *option name der option
|
|
||||||
* @param *def default wert
|
|
||||||
* @return parameter wert oder default wert bei fehler
|
|
||||||
*/
|
|
||||||
int config_get_int(char *section, char *option, int def)
|
|
||||||
{
|
|
||||||
char *ret;
|
|
||||||
|
|
||||||
ret = config_get_string(section, option, NULL);
|
|
||||||
return ret ? atoi(ret) : def;
|
|
||||||
}
|
|
|
@ -0,0 +1,230 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 06/2006 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 <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "configfile.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
#define BUFSIZE 1024
|
||||||
|
|
||||||
|
struct conf_section {
|
||||||
|
struct list_head list;
|
||||||
|
struct list_head tupel_list;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct conf_tupel {
|
||||||
|
struct list_head list;
|
||||||
|
char *option;
|
||||||
|
char *parameter;
|
||||||
|
};
|
||||||
|
|
||||||
|
static LIST_HEAD(config_list);
|
||||||
|
|
||||||
|
static struct conf_section * config_add_section(const char *name)
|
||||||
|
{
|
||||||
|
struct conf_section *section;
|
||||||
|
section = malloc(sizeof(struct conf_section) + strlen(name));
|
||||||
|
if (section == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(§ion->list);
|
||||||
|
INIT_LIST_HEAD(§ion->tupel_list);
|
||||||
|
|
||||||
|
section->name = strdup(name);
|
||||||
|
if (section->name == NULL) {
|
||||||
|
free(section);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(§ion->list, &config_list);
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int config_add_tupel(struct conf_section *section, const char *option, const char *parameter)
|
||||||
|
{
|
||||||
|
struct conf_tupel *tupel = malloc(sizeof(struct conf_tupel));
|
||||||
|
if (tupel == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&tupel->list);
|
||||||
|
tupel->option = strdup(option);
|
||||||
|
tupel->parameter = strdup(parameter);
|
||||||
|
|
||||||
|
if (tupel->option == NULL || tupel->parameter == NULL) {
|
||||||
|
free(tupel);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(&tupel->list, §ion->tupel_list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_parse(const char *config)
|
||||||
|
{
|
||||||
|
FILE *fz = fopen(config, "r");
|
||||||
|
if (fz == NULL) {
|
||||||
|
log_print(LOG_ERROR, "config_parse(): %s", config);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *line = malloc(BUFSIZE);
|
||||||
|
if (line == NULL) {
|
||||||
|
log_print(LOG_ERROR, "config_parse(): out of memory");
|
||||||
|
fclose(fz);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int linenum = 0;
|
||||||
|
struct conf_section *section = NULL;
|
||||||
|
while (fgets(line, BUFSIZE, fz) != NULL) {
|
||||||
|
linenum++;
|
||||||
|
|
||||||
|
if (line[0] == '#' || line[0] <= ' ') {
|
||||||
|
continue;
|
||||||
|
|
||||||
|
} else if (line[0] == '[') {
|
||||||
|
char *tok = strtok(line +1, " ]\n");
|
||||||
|
|
||||||
|
if (tok == NULL || (section = config_add_section(tok)) == NULL) {
|
||||||
|
log_print(LOG_WARN, "config_parse(): invalid section in row %d", linenum);
|
||||||
|
free(line);
|
||||||
|
fclose(fz);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
} else if (section == NULL) {
|
||||||
|
log_print(LOG_WARN, "config_parse(): missing section in row %d", linenum);
|
||||||
|
free(line);
|
||||||
|
fclose(fz);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *tok = strtok(line, " \n");
|
||||||
|
if (tok != NULL) {
|
||||||
|
char *tok2;
|
||||||
|
while ((tok2 = strtok(NULL, " \n"))) {
|
||||||
|
if (config_add_tupel(section, tok, tok2) != 0)
|
||||||
|
log_print(LOG_WARN, "config_parse(): invalid row %d", linenum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fz);
|
||||||
|
free(line);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct conf_section * config_get_section(const char *name)
|
||||||
|
{
|
||||||
|
struct conf_section *section;
|
||||||
|
|
||||||
|
list_for_each_entry(section, &config_list, list) {
|
||||||
|
if (!strcmp(section->name, name))
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * config_get_string(const char *section_str, const char *option, char *def)
|
||||||
|
{
|
||||||
|
struct conf_section *section = config_get_section(section_str);
|
||||||
|
if (section != NULL) {
|
||||||
|
struct conf_tupel *tupel;
|
||||||
|
list_for_each_entry(tupel, §ion->tupel_list, list) {
|
||||||
|
if (!strcmp(tupel->option, option))
|
||||||
|
return tupel->parameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def != NULL)
|
||||||
|
log_print(LOG_WARN, "config [%s:%s] not found, using default: '%s'",
|
||||||
|
section_str, option, def);
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_get_int(const char *section, const char *option, int def)
|
||||||
|
{
|
||||||
|
char *ret = config_get_string(section, option, NULL);
|
||||||
|
if (ret == NULL) {
|
||||||
|
log_print(LOG_WARN, "config [%s:%s] not found, using default: '%d'",
|
||||||
|
section, option, def);
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
return atoi(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_get_strings(const char *section_str, const char *option,
|
||||||
|
int (*callback)(const char *value, void *privdata),
|
||||||
|
void *privdata)
|
||||||
|
{
|
||||||
|
struct conf_section *section = config_get_section(section_str);
|
||||||
|
if (section == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
struct conf_tupel *tupel;
|
||||||
|
list_for_each_entry(tupel, §ion->tupel_list, list) {
|
||||||
|
if (!strcmp(tupel->option, option))
|
||||||
|
if (callback(tupel->parameter, privdata) == 0)
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: wrong place!
|
||||||
|
int parse_saddr(const char *addr, struct sockaddr_in *sa)
|
||||||
|
{
|
||||||
|
char *addr_cpy = strdup(addr);
|
||||||
|
if (addr_cpy == NULL) {
|
||||||
|
log_print(LOG_WARN, "parse_saddr(): out of memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *tmp;
|
||||||
|
char *ip = strtok_r(addr_cpy, ":", &tmp);
|
||||||
|
if (ip == NULL) {
|
||||||
|
free(addr_cpy);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *port = strtok_r(NULL, ":", &tmp);
|
||||||
|
if (port == NULL) {
|
||||||
|
free(addr_cpy);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sa->sin_family = AF_INET;
|
||||||
|
sa->sin_port = htons(atoi(port));
|
||||||
|
int ret = inet_aton(ip, &sa->sin_addr);
|
||||||
|
|
||||||
|
free(addr_cpy);
|
||||||
|
return (ret != 0) ? 0 : -1;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef _CONFIG_H_
|
||||||
|
#define _CONFIG_H_
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
int config_parse(const char *config);
|
||||||
|
|
||||||
|
char * config_get_string(const char *section_str, const char *option, char *def);
|
||||||
|
|
||||||
|
int config_get_int(const char *section, const char *option, int def);
|
||||||
|
|
||||||
|
int config_get_strings(const char *section_str, const char *option,
|
||||||
|
int (*callback)(const char *value, void *privdata),
|
||||||
|
void *privdata);
|
||||||
|
|
||||||
|
int parse_saddr(const char *addr, struct sockaddr_in *sa);
|
||||||
|
|
||||||
|
#endif /* _CONFIG_H_ */
|
|
@ -0,0 +1,310 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 10/2006 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 <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
|
static LIST_HEAD(readfd_list);
|
||||||
|
static LIST_HEAD(writefd_list);
|
||||||
|
static LIST_HEAD(exceptfd_list);
|
||||||
|
static LIST_HEAD(timeout_list);
|
||||||
|
|
||||||
|
struct fd_entry {
|
||||||
|
struct list_head list;
|
||||||
|
int fd;
|
||||||
|
int type;
|
||||||
|
int (*callback)(int fd, void *privdata);
|
||||||
|
void *privdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timeout_entry {
|
||||||
|
struct list_head list;
|
||||||
|
struct timeval timeout;
|
||||||
|
struct timeval nextrun;
|
||||||
|
int (*callback)(void *privdata);
|
||||||
|
void *privdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
int event_add_fd(int fd, int type, int (*callback)(int fd, void *privdata), void *privdata)
|
||||||
|
{
|
||||||
|
if (fd < 0 || fd > FD_SETSIZE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
struct fd_entry *entry;
|
||||||
|
entry = malloc(sizeof(struct fd_entry));
|
||||||
|
if (entry == NULL) {
|
||||||
|
log_print(LOG_ERROR, "event_add_fd(): out of memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->fd = fd;
|
||||||
|
entry->type = type;
|
||||||
|
entry->callback = callback;
|
||||||
|
entry->privdata = privdata;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case FD_READ:
|
||||||
|
list_add_tail(&entry->list, &readfd_list);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FD_WRITE:
|
||||||
|
list_add_tail(&entry->list, &writefd_list);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FD_EXCEPT:
|
||||||
|
list_add_tail(&entry->list, &exceptfd_list);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log_print(LOG_ERROR, "add_fd(): unknown type");
|
||||||
|
free(entry);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_remove_fd(int fd)
|
||||||
|
{
|
||||||
|
struct fd_entry *entry, *tmp;
|
||||||
|
list_for_each_entry_safe(entry, tmp, &readfd_list, list) {
|
||||||
|
if (entry->fd == fd) {
|
||||||
|
list_del(&entry->list);
|
||||||
|
free(entry);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry_safe(entry, tmp, &writefd_list, list) {
|
||||||
|
if (entry->fd == fd) {
|
||||||
|
list_del(&entry->list);
|
||||||
|
free(entry);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry_safe(entry, tmp, &exceptfd_list, list) {
|
||||||
|
if (entry->fd == fd) {
|
||||||
|
list_del(&entry->list);
|
||||||
|
free(entry);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calc_nextrun(struct timeval *timeout, struct timeval *nextrun)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
|
||||||
|
nextrun->tv_usec = now.tv_usec + timeout->tv_usec;
|
||||||
|
nextrun->tv_sec = now.tv_sec + timeout->tv_sec;
|
||||||
|
|
||||||
|
if (nextrun->tv_usec >= 1000000) {
|
||||||
|
nextrun->tv_usec -= 1000000;
|
||||||
|
nextrun->tv_sec++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calc_timeout(struct timeval *timeout, struct timeval *nextrun)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
|
||||||
|
timeout->tv_usec = nextrun->tv_usec - now.tv_usec;
|
||||||
|
timeout->tv_sec = nextrun->tv_sec - now.tv_sec;
|
||||||
|
|
||||||
|
if (timeout->tv_usec < 0) {
|
||||||
|
timeout->tv_usec += 1000000;
|
||||||
|
timeout->tv_sec--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void schedule_nextrun(struct timeout_entry *entry)
|
||||||
|
{
|
||||||
|
struct timeout_entry *search;
|
||||||
|
|
||||||
|
list_for_each_entry(search, &timeout_list, list) {
|
||||||
|
if (search->nextrun.tv_sec > entry->nextrun.tv_sec) {
|
||||||
|
list_add_tail(&entry->list, &search->list);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if (search->nextrun.tv_sec == entry->nextrun.tv_sec &&
|
||||||
|
search->nextrun.tv_usec > entry->nextrun.tv_usec) {
|
||||||
|
list_add_tail(&entry->list, &search->list);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_add_tail(&entry->list, &timeout_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_add_timeout(struct timeval *timeout, int (*callback)(void *privdata), void *privdata)
|
||||||
|
{
|
||||||
|
struct timeout_entry *entry;
|
||||||
|
entry = malloc(sizeof(struct timeout_entry));
|
||||||
|
if (entry == NULL) {
|
||||||
|
log_print(LOG_ERROR, "event_add_timeout(): out of memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&entry->timeout, timeout, sizeof(entry->timeout));
|
||||||
|
entry->callback = callback;
|
||||||
|
entry->privdata = privdata;
|
||||||
|
|
||||||
|
calc_nextrun(&entry->timeout, &entry->nextrun);
|
||||||
|
schedule_nextrun(entry);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void event_loop(void)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
fd_set readfds, *readfds_p = NULL;
|
||||||
|
fd_set writefds, *writefds_p = NULL;
|
||||||
|
fd_set exceptfds, *exceptfds_p =NULL;
|
||||||
|
struct timeval timeout, *timeout_p = NULL;
|
||||||
|
|
||||||
|
if (!list_empty(&readfd_list)) {
|
||||||
|
struct fd_entry *entry;
|
||||||
|
|
||||||
|
FD_ZERO(&readfds);
|
||||||
|
list_for_each_entry(entry, &readfd_list, list)
|
||||||
|
FD_SET(entry->fd, &readfds);
|
||||||
|
|
||||||
|
readfds_p = &readfds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!list_empty(&writefd_list)) {
|
||||||
|
struct fd_entry *entry;
|
||||||
|
|
||||||
|
FD_ZERO(&writefds);
|
||||||
|
list_for_each_entry(entry, &writefd_list, list)
|
||||||
|
FD_SET(entry->fd, &writefds);
|
||||||
|
|
||||||
|
writefds_p = &writefds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!list_empty(&exceptfd_list)) {
|
||||||
|
struct fd_entry *entry;
|
||||||
|
|
||||||
|
FD_ZERO(&exceptfds);
|
||||||
|
list_for_each_entry(entry, &exceptfd_list, list)
|
||||||
|
FD_SET(entry->fd, &exceptfds);
|
||||||
|
|
||||||
|
exceptfds_p = &exceptfds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!list_empty(&timeout_list)) {
|
||||||
|
struct timeout_entry *entry, *tmp;
|
||||||
|
list_for_each_entry_safe(entry, tmp, &timeout_list, list) {
|
||||||
|
|
||||||
|
calc_timeout(&timeout, &entry->nextrun);
|
||||||
|
if (timeout.tv_sec >= 0 && timeout.tv_usec > 0) {
|
||||||
|
timeout_p = &timeout;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delayed timeout, exec NOW!
|
||||||
|
list_del(&entry->list);
|
||||||
|
int ret = entry->callback(entry->privdata);
|
||||||
|
if (ret == 0) {
|
||||||
|
calc_nextrun(&entry->timeout, &entry->nextrun);
|
||||||
|
schedule_nextrun(entry);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = select(FD_SETSIZE, readfds_p, writefds_p, exceptfds_p, timeout_p);
|
||||||
|
if (i < 0) {
|
||||||
|
/* On error, -1 is returned, and errno is set
|
||||||
|
* appropriately; the sets and timeout become
|
||||||
|
* undefined, so do not rely on their contents
|
||||||
|
* after an error.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
|
||||||
|
} else if (i == 0 && !list_empty(&timeout_list)) {
|
||||||
|
struct timeout_entry *entry;
|
||||||
|
entry = list_entry(timeout_list.next, typeof(*entry), list);
|
||||||
|
list_del(&entry->list);
|
||||||
|
|
||||||
|
int ret = entry->callback(entry->privdata);
|
||||||
|
if (ret == 0) {
|
||||||
|
calc_nextrun(&entry->timeout, &entry->nextrun);
|
||||||
|
schedule_nextrun(entry);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readfds_p) {
|
||||||
|
struct fd_entry *entry, *tmp;
|
||||||
|
list_for_each_entry_safe(entry, tmp, &readfd_list, list) {
|
||||||
|
if (!FD_ISSET(entry->fd, &readfds))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (entry->callback(entry->fd, entry->privdata) != 0) {
|
||||||
|
list_del(&entry->list);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writefds_p) {
|
||||||
|
struct fd_entry *entry, *tmp;
|
||||||
|
list_for_each_entry_safe(entry, tmp, &writefd_list, list) {
|
||||||
|
if (FD_ISSET(entry->fd, &writefds))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (entry->callback(entry->fd, entry->privdata) != 0) {
|
||||||
|
list_del(&entry->list);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exceptfds_p) {
|
||||||
|
struct fd_entry *entry, *tmp;
|
||||||
|
list_for_each_entry_safe(entry, tmp, &exceptfd_list, list) {
|
||||||
|
if (FD_ISSET(entry->fd, &exceptfds))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (entry->callback(entry->fd, entry->privdata) != 0) {
|
||||||
|
list_del(&entry->list);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef _EVENT_H_
|
||||||
|
#define _EVENT_H_
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#define FD_READ 0x01
|
||||||
|
#define FD_WRITE 0x02
|
||||||
|
#define FD_EXCEPT 0x04
|
||||||
|
|
||||||
|
#define event_add_readfd(fd, callback, privdata) \
|
||||||
|
event_add_fd(fd, FD_READ, callback, privdata)
|
||||||
|
|
||||||
|
#define event_add_writefd(fd, callback, privdata) \
|
||||||
|
event_add_fd(fd, FD_WRITE, callback, privdata)
|
||||||
|
|
||||||
|
#define event_add_exceptfd(fd, callback, privdata) \
|
||||||
|
event_add_fd(fd, FD_EXCEPT, callback, privdata)
|
||||||
|
|
||||||
|
int event_add_fd(int fd, int type, int (*callback)(int fd, void *privdata), void *privdata);
|
||||||
|
int event_add_timeout(struct timeval *timeout, int (*callback)(void *privdata), void *privdata);
|
||||||
|
|
||||||
|
int event_remove_fd(int fd);
|
||||||
|
|
||||||
|
void event_loop(void);
|
||||||
|
|
||||||
|
#endif /* _EVENT_H_ */
|
|
@ -0,0 +1,85 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "gamelist.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
#define BUCKET_NUM 127
|
||||||
|
|
||||||
|
static struct list_head *bucket;
|
||||||
|
|
||||||
|
static unsigned int hash_entry(struct game_entry *entry)
|
||||||
|
{
|
||||||
|
unsigned int hash = 0x12345678;
|
||||||
|
|
||||||
|
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->ip >> 0) & 0xFF);
|
||||||
|
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->ip >> 8) & 0xFF);
|
||||||
|
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->ip >> 16) & 0xFF);
|
||||||
|
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->ip >> 24) & 0xFF);
|
||||||
|
|
||||||
|
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->port1 >> 0) & 0xFF);
|
||||||
|
hash = ((hash << 5) ^ (hash >> 27)) ^ ((entry->port1 >> 8) & 0xFF);
|
||||||
|
|
||||||
|
return hash % BUCKET_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare_entry(struct game_entry *a, struct game_entry *b)
|
||||||
|
{
|
||||||
|
return (a->gameid == b->gameid && a->ip == b->ip &&
|
||||||
|
a->port1 == b->port1 && a->port2 == b->port2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int gamelist_add(struct game_entry *entry)
|
||||||
|
{
|
||||||
|
unsigned int hash = hash_entry(entry);
|
||||||
|
|
||||||
|
struct game_entry *search;
|
||||||
|
list_for_each_entry(search, &bucket[hash], list) {
|
||||||
|
if (compare_entry(search, entry)) {
|
||||||
|
search->modtime = time(NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->modtime = time(NULL);
|
||||||
|
list_add_tail(&entry->list, &bucket[hash]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gamelist_gc_and_dump(int (*callback)(struct game_entry *entry), int timeout)
|
||||||
|
{
|
||||||
|
long now = time(NULL);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < BUCKET_NUM; i++) {
|
||||||
|
struct game_entry *entry, *tmp;
|
||||||
|
list_for_each_entry_safe(entry, tmp, &bucket[i], list) {
|
||||||
|
if (entry->modtime + timeout >= now) {
|
||||||
|
callback(entry);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
list_del(&entry->list);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gamelist_init()
|
||||||
|
{
|
||||||
|
bucket = malloc(sizeof(struct list_head) * BUCKET_NUM);
|
||||||
|
if (bucket == NULL) {
|
||||||
|
log_print(LOG_ERROR, "scan_init(): out of memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < BUCKET_NUM; i++)
|
||||||
|
INIT_LIST_HEAD(&bucket[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef _GAMELIST_H_
|
||||||
|
#define _GAMELIST_H_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
struct game_entry {
|
||||||
|
struct list_head list;
|
||||||
|
unsigned long modtime;
|
||||||
|
|
||||||
|
/* begin HLSW_ENTRY */
|
||||||
|
uint16_t gameid;
|
||||||
|
uint32_t ip;
|
||||||
|
uint16_t port1;
|
||||||
|
uint16_t port2;
|
||||||
|
/* end HLSW_ENTRY */
|
||||||
|
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
int gamelist_init();
|
||||||
|
int gamelist_add(struct game_entry *entry);
|
||||||
|
int gamelist_gc_and_dump(int (*callback)(struct game_entry *entry), int timeout);
|
||||||
|
|
||||||
|
#endif /* _GAMELIST_H_ */
|
|
@ -21,13 +21,18 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
|
||||||
#include "hlswmaster.h"
|
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
|
#include "event.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
#include "gamelist.h"
|
||||||
|
#include "scanner.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
|
||||||
static struct option opts[] = {
|
static struct option opts[] = {
|
||||||
{"config", 1, 0, 'c'},
|
{"config", 1, 0, 'c'},
|
||||||
|
@ -39,8 +44,6 @@ static struct option opts[] = {
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
pthread_t thread1, thread2, thread3;
|
|
||||||
pthread_attr_t attr;
|
|
||||||
int arg = 0, code = 0, debug = 0;
|
int arg = 0, code = 0, debug = 0;
|
||||||
char *config = NULL, *user = NULL, *logfile;
|
char *config = NULL, *user = NULL, *logfile;
|
||||||
|
|
||||||
|
@ -84,22 +87,22 @@ int main(int argc, char *argv[])
|
||||||
if (user) {
|
if (user) {
|
||||||
struct passwd *pwl;
|
struct passwd *pwl;
|
||||||
if (!(pwl = getpwnam(user))) {
|
if (!(pwl = getpwnam(user))) {
|
||||||
log_print("unknown user: %s", user);
|
log_print(LOG_ERROR, "unknown user: %s", user);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setgid(pwl->pw_gid) || setuid(pwl->pw_uid)) {
|
if (setgid(pwl->pw_gid) || setuid(pwl->pw_uid)) {
|
||||||
log_print("setgid/setuid");
|
log_print(LOG_ERROR, "setgid/setuid");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse config file */
|
/* parse config file */
|
||||||
if (!config_parse(config))
|
if (config_parse(config) == -1)
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
|
||||||
/* check logfile */
|
/* check logfile */
|
||||||
logfile = config_get_string("global", "logfile", NULL);
|
logfile = config_get_string("global", "logfile", "hlswmaster.log");
|
||||||
if (logfile && !debug) {
|
if (logfile && !debug) {
|
||||||
/* start logging */
|
/* start logging */
|
||||||
if (!log_init(logfile))
|
if (!log_init(logfile))
|
||||||
|
@ -109,26 +112,25 @@ int main(int argc, char *argv[])
|
||||||
daemon(-1, 0);
|
daemon(-1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_print("hlswmaster started (user: %s, pid: %d)", getpwuid(getuid())->pw_name, getpid());
|
log_print(LOG_INFO, "hlswmaster started (user: %s, pid: %d)", getpwuid(getuid())->pw_name, getpid());
|
||||||
|
|
||||||
/* init scan engine */
|
/* init plugins */
|
||||||
if (!scan_init())
|
if (plugin_init() == -1)
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
|
||||||
/* load plugins */
|
/* init gamelist */
|
||||||
plugin_load_all();
|
if (gamelist_init() == -1)
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
/* startup threads */
|
/* init server */
|
||||||
pthread_attr_init(&attr);
|
if (server_init() == -1)
|
||||||
pthread_attr_setstacksize(&attr, 65536);
|
exit(-1);
|
||||||
|
|
||||||
pthread_create(&thread1, &attr, (void *)&scan_control, NULL);
|
/* init scanner */
|
||||||
pthread_create(&thread2, &attr, (void *)&scan_receive, NULL);
|
if (scanner_init() == -1)
|
||||||
pthread_create(&thread3, &attr, (void *)&client_handler, NULL);
|
exit(-1);
|
||||||
|
|
||||||
/* wait untill d00msday */
|
event_loop();
|
||||||
while (1)
|
|
||||||
sleep(3600);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -1,43 +1,43 @@
|
||||||
[global]
|
[global]
|
||||||
# broadcast scan source IP & PORT (udp)
|
## broadcast scan source IP & PORT (udp)
|
||||||
scan_ip 0.0.0.0
|
#scanner_src 0.0.0.0:7130
|
||||||
scan_port 7130
|
|
||||||
|
|
||||||
# broadcast scan every X seconds
|
## broadcast scan every X seconds
|
||||||
scan_interval 60
|
#scan_interval 60
|
||||||
|
|
||||||
# serverlist rebuild every X seconds
|
## serverlist rebuild every X seconds
|
||||||
serverlist_interval 5
|
#serverlist_refresh 5
|
||||||
|
|
||||||
# server timeout after X seconds
|
## server timeout after X seconds
|
||||||
serverlist_timeout 180
|
#serverlist_timeout 180
|
||||||
|
|
||||||
# plugin data timeout every X seconds
|
## master answers with this source IP
|
||||||
plugin_timeout 90
|
#master_src 0.0.0.0:7140
|
||||||
|
|
||||||
# master answers with this source IP
|
#plugin_dir .
|
||||||
master_ip 0.0.0.0
|
plugin p_d3engine.so
|
||||||
|
plugin p_gamespy1.so
|
||||||
|
plugin p_gamespy2.so
|
||||||
|
plugin p_halflife.so
|
||||||
|
plugin p_hlswproxy.so
|
||||||
|
plugin p_q3engine.so
|
||||||
|
plugin p_quake2.so
|
||||||
|
plugin p_ut2k4.so
|
||||||
|
|
||||||
# load these plugins
|
## logging
|
||||||
#plugin plugins/.libs/hlswproxy.so
|
#logfile hlswmaster.log
|
||||||
plugin plugins/.libs/halflife.so
|
|
||||||
plugin plugins/.libs/q3engine.so
|
|
||||||
plugin plugins/.libs/quake2.so
|
|
||||||
plugin plugins/.libs/gamespy1.so
|
|
||||||
plugin plugins/.libs/gamespy2.so
|
|
||||||
plugin plugins/.libs/d3engine.so
|
|
||||||
plugin plugins/.libs/ut2k4.so
|
|
||||||
|
|
||||||
# logging
|
[gamespy1]
|
||||||
logfile hlswmaster.log
|
## internal fragment-list timeout
|
||||||
|
#gc_timeout 90
|
||||||
|
|
||||||
[hlswproxy]
|
[hlswproxy]
|
||||||
# ask these hlswmasters
|
## ask these hlswmasters
|
||||||
scan_ip 10.10.0.1
|
scan 10.10.0.1:7140
|
||||||
scan_ip 10.10.0.2
|
scan 10.10.0.2:7140
|
||||||
|
|
||||||
[halflife]
|
[halflife]
|
||||||
# allow these nets
|
## allow these nets
|
||||||
valid_net 10.10.0.0/16
|
valid_net 10.10.0.0/16
|
||||||
valid_net 172.16.0.0/16
|
valid_net 172.16.0.0/16
|
||||||
|
|
||||||
|
|
42
hlswmaster.h
42
hlswmaster.h
|
@ -1,42 +0,0 @@
|
||||||
#ifndef _HLSWMASTER_H
|
|
||||||
#define _HLSWMASTER_H
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include "list.h"
|
|
||||||
#include "netpkt.h"
|
|
||||||
|
|
||||||
struct game_server {
|
|
||||||
struct list_head list;
|
|
||||||
unsigned long modtime;
|
|
||||||
|
|
||||||
uint16_t gameid;
|
|
||||||
uint32_t ip;
|
|
||||||
uint16_t port1;
|
|
||||||
uint16_t port2;
|
|
||||||
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
/* logging.c */
|
|
||||||
int log_init(char *logfile);
|
|
||||||
void log_print(const char *fmt, ... );
|
|
||||||
|
|
||||||
/* plugin.c */
|
|
||||||
int plugin_load(char *name);
|
|
||||||
int plugin_load_all();
|
|
||||||
int plugin_unload_all();
|
|
||||||
int plugins_scan();
|
|
||||||
int plugins_parse(struct net_pkt *pkt);
|
|
||||||
int plugins_gc(unsigned long timeout);
|
|
||||||
|
|
||||||
/* scanner.c */
|
|
||||||
int scan_init();
|
|
||||||
void scan_control();
|
|
||||||
void scan_receive();
|
|
||||||
|
|
||||||
/* client.c */
|
|
||||||
int client_pkt_add(struct game_server *server);
|
|
||||||
int client_pkt_commit();
|
|
||||||
void client_handler();
|
|
||||||
|
|
||||||
#endif /* _HLSWMASTER_H */
|
|
6
list.h
6
list.h
|
@ -1,5 +1,5 @@
|
||||||
#ifndef _LIST_H
|
#ifndef _LIST_H_
|
||||||
#define _LIST_H
|
#define _LIST_H_
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* stolen from linux kernel 2.6.11 (http://kernel.org/)
|
* stolen from linux kernel 2.6.11 (http://kernel.org/)
|
||||||
|
@ -265,4 +265,4 @@ static inline void list_splice_init(struct list_head *list,
|
||||||
(type)__j; \
|
(type)__j; \
|
||||||
})
|
})
|
||||||
|
|
||||||
#endif /* _LIST_H */
|
#endif /* _LIST_H_ */
|
||||||
|
|
98
logging.c
98
logging.c
|
@ -1,5 +1,5 @@
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 03/2005 by Olaf Rempel *
|
* Copyright (C) 06/2006 by Olaf Rempel *
|
||||||
* razzor@kopf-tisch.de *
|
* razzor@kopf-tisch.de *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
@ -24,84 +24,80 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "configfile.h"
|
#include "logging.h"
|
||||||
|
|
||||||
|
#define BUFSIZE 8192
|
||||||
|
|
||||||
static FILE *log_fd = NULL;
|
static FILE *log_fd = NULL;
|
||||||
|
static char *buffer = NULL;
|
||||||
|
|
||||||
/**
|
void log_print(int prio, const char *fmt, ...)
|
||||||
* log_print()
|
|
||||||
* schreibt eine Zeile ins Logfile oder auf stderr
|
|
||||||
* wenn errno gesetzt ist, wird der error-string mit ausgegeben
|
|
||||||
*
|
|
||||||
* @param fmt variable argumentenliste (syntax wie bei printf)
|
|
||||||
*
|
|
||||||
* @todo code vereinfachen?
|
|
||||||
*/
|
|
||||||
void log_print(const char *fmt, ...)
|
|
||||||
{
|
{
|
||||||
va_list az;
|
va_list az;
|
||||||
char *buffer = malloc(8192);
|
int len;
|
||||||
|
|
||||||
va_start(az, fmt);
|
if (buffer == NULL) {
|
||||||
vsprintf(buffer, fmt, az);
|
buffer = malloc(BUFSIZE);
|
||||||
va_end(az);
|
if (buffer == NULL) {
|
||||||
|
fprintf(stderr, "log_print: out of memory\nBailing out!\n");
|
||||||
/* ins logfile loggen */
|
exit(-1);
|
||||||
if (log_fd) {
|
}
|
||||||
time_t tzgr;
|
|
||||||
char tbuf[64];
|
|
||||||
time(&tzgr);
|
|
||||||
strftime(tbuf, 64, "%b %d %H:%M:%S :", localtime(&tzgr));
|
|
||||||
|
|
||||||
if (errno) {
|
|
||||||
fprintf(log_fd, "%s %s: %s\n", tbuf, buffer, strerror(errno));
|
|
||||||
} else {
|
|
||||||
fprintf(log_fd, "%s %s\n", tbuf, buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
va_start(az, fmt);
|
||||||
|
len = vsnprintf(buffer, BUFSIZE, fmt, az);
|
||||||
|
va_end(az);
|
||||||
|
|
||||||
|
if (len < 0 || len >= BUFSIZE) {
|
||||||
|
log_print(LOG_ERROR, "log_print: arguments too long");
|
||||||
|
errno = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errno) {
|
||||||
|
strncpy(buffer + len, ": ", BUFSIZE - len);
|
||||||
|
len += 2;
|
||||||
|
strncpy(buffer + len, strerror(errno), BUFSIZE - len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log_fd) {
|
||||||
|
char tbuf[64];
|
||||||
|
time_t tzgr;
|
||||||
|
|
||||||
|
time(&tzgr);
|
||||||
|
strftime(tbuf, sizeof(tbuf), "%b %d %H:%M:%S :", localtime(&tzgr));
|
||||||
|
|
||||||
|
fprintf(log_fd, "%s %s\n", tbuf, buffer);
|
||||||
fflush(log_fd);
|
fflush(log_fd);
|
||||||
|
|
||||||
/* nach stderr loggen */
|
|
||||||
} else {
|
|
||||||
if (errno) {
|
|
||||||
fprintf(stderr, "%s: %s\n", buffer, strerror(errno));
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%s\n", buffer);
|
fprintf(stderr, "%s\n", buffer);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
free(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void log_close(void)
|
||||||
* log_close()
|
|
||||||
* schliesst das logfile
|
|
||||||
*/
|
|
||||||
static void log_close()
|
|
||||||
{
|
{
|
||||||
|
if (buffer)
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
fclose(log_fd);
|
fclose(log_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* log_init()
|
|
||||||
* initialisiert das logging
|
|
||||||
*
|
|
||||||
* @param logfile filename des logfiles
|
|
||||||
* @return false bei fehler
|
|
||||||
*/
|
|
||||||
int log_init(char *logfile)
|
int log_init(char *logfile)
|
||||||
{
|
{
|
||||||
if ((log_fd = fopen(logfile, "a" )) == NULL) {
|
log_fd = fopen(logfile, "a");
|
||||||
log_print("log_open('%s'): %s", logfile);
|
if (log_fd == NULL) {
|
||||||
|
log_print(LOG_ERROR, "log_open('%s'): %s", logfile);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* beim beenden log schliessen */
|
|
||||||
if (atexit(log_close) != 0) {
|
if (atexit(log_close) != 0) {
|
||||||
log_print("log_open(): atexit()");
|
log_print(LOG_ERROR, "log_open(): atexit()");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_print("==========================");
|
log_print(LOG_EVERYTIME, "==========================");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef _LOGGING_H_
|
||||||
|
#define _LOGGING_H_
|
||||||
|
|
||||||
|
#define LOG_DEBUG 5
|
||||||
|
#define LOG_INFO 4
|
||||||
|
#define LOG_NOTICE 3
|
||||||
|
#define LOG_WARN 2
|
||||||
|
#define LOG_ERROR 1
|
||||||
|
#define LOG_CRIT 0
|
||||||
|
|
||||||
|
#define LOG_EVERYTIME 0
|
||||||
|
|
||||||
|
int log_init(char *logfile);
|
||||||
|
void log_print(int prio, const char *fmt, ... );
|
||||||
|
|
||||||
|
#endif /* _LOGGING_H_ */
|
|
@ -68,8 +68,8 @@ static char *id2name[] = {
|
||||||
"Starwars: Battlefront (?)",
|
"Starwars: Battlefront (?)",
|
||||||
"SWAT 4",
|
"SWAT 4",
|
||||||
"Battlefield 2", // 45
|
"Battlefield 2", // 45
|
||||||
"???",
|
"(unknown)",
|
||||||
"Quake 4 (???)",
|
"Quake 4 (?)",
|
||||||
"Call of Duty 2"
|
"Call of Duty 2"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define __USE_GNU
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "netpkt.h"
|
||||||
|
|
||||||
|
int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (offset >= pkt->size)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* nicht ueber das paket hinaus vergleichen */
|
||||||
|
if (offset + size >= pkt->size)
|
||||||
|
size = pkt->size - offset;
|
||||||
|
|
||||||
|
return memcmp(pkt->buf + offset, search, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size)
|
||||||
|
{
|
||||||
|
void *found;
|
||||||
|
|
||||||
|
if (offset >= pkt->size)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
found = memmem(pkt->buf + offset, pkt->size, search, size);
|
||||||
|
|
||||||
|
return (found == NULL) ? -1 : (found - (void *)pkt->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct net_pkt * pkt_merge(struct net_pkt *pkt1, struct net_pkt *pkt2)
|
||||||
|
{
|
||||||
|
struct net_pkt *ret;
|
||||||
|
ret = malloc(sizeof(struct net_pkt) + pkt1->size + pkt2->size);
|
||||||
|
|
||||||
|
memcpy(&ret->addr, &pkt1->addr, sizeof(ret->addr));
|
||||||
|
ret->size = pkt1->size + pkt2->size;
|
||||||
|
|
||||||
|
memcpy(ret->buf, pkt1->buf, pkt1->size);
|
||||||
|
memcpy(ret->buf + pkt1->size, pkt2->buf, pkt2->size);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * pkt_ntoa(struct net_pkt *pkt)
|
||||||
|
{
|
||||||
|
return inet_ntoa(pkt->addr.sin_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short pkt_getport(struct net_pkt *pkt)
|
||||||
|
{
|
||||||
|
return ntohs(pkt->addr.sin_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pkt_sameaddr(struct net_pkt *pkt1, struct net_pkt *pkt2)
|
||||||
|
{
|
||||||
|
return (pkt1->addr.sin_addr.s_addr == pkt2->addr.sin_addr.s_addr) &&
|
||||||
|
(pkt1->addr.sin_port == pkt2->addr.sin_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pkt_parse_int(struct net_pkt *pkt, unsigned int offset, int *val)
|
||||||
|
{
|
||||||
|
unsigned char *max = pkt->buf + pkt->size;
|
||||||
|
unsigned char *c = pkt->buf + offset;
|
||||||
|
|
||||||
|
/* untere grenze abtesten */
|
||||||
|
if (pkt->buf > c || c > max)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*val = 0;
|
||||||
|
|
||||||
|
/* ziffern einlesen */
|
||||||
|
while (isdigit(*c) && c < max)
|
||||||
|
*val = (*val * 10) + (*c++ - 0x30);
|
||||||
|
|
||||||
|
return (c - (pkt->buf + offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
int pkt_parse_ip(struct net_pkt *pkt, int offset, struct in_addr *ip)
|
||||||
|
{
|
||||||
|
int i, tmp, count, pos = offset;
|
||||||
|
ip->s_addr = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
count = pkt_parse_int(pkt, pos, &tmp);
|
||||||
|
pos += count;
|
||||||
|
if (count == 0 || tmp < 0 || tmp > 255)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ip->s_addr = ip->s_addr>>8 | tmp<<24;
|
||||||
|
|
||||||
|
if (i != 3 && pkt->buf[pos++] != '.')
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return pos - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * pkt_print(struct net_pkt *pkt)
|
||||||
|
{
|
||||||
|
int pos = 0, i = 0, j;
|
||||||
|
char *buf = malloc(pkt->size * 4 + 64);
|
||||||
|
|
||||||
|
while (pos < pkt->size) {
|
||||||
|
i += sprintf(buf + i, "%04X: ", pos);
|
||||||
|
for (j = 0; j < 16; j++) {
|
||||||
|
if (pos + j < pkt->size)
|
||||||
|
i += sprintf(buf + i, "%02X", pkt->buf[pos + j]);
|
||||||
|
else
|
||||||
|
i += sprintf(buf + i, " ");
|
||||||
|
|
||||||
|
if (j % 2)
|
||||||
|
buf[i++] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < 16; j++) {
|
||||||
|
if (pos + j < pkt->size) {
|
||||||
|
unsigned char val = pkt->buf[pos + j];
|
||||||
|
if (val >= 0x20 && val < 0x80)
|
||||||
|
buf[i++] = val;
|
||||||
|
else
|
||||||
|
buf[i++] = '.';
|
||||||
|
} else {
|
||||||
|
buf[i++] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += 16;
|
||||||
|
buf[i++] = '\r';
|
||||||
|
buf[i++] = '\n';
|
||||||
|
}
|
||||||
|
buf[i] = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
14
netpkt.h
14
netpkt.h
|
@ -5,10 +5,24 @@
|
||||||
#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];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
|
||||||
|
int pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
|
||||||
|
struct net_pkt * pkt_merge(struct net_pkt *pkt1, struct net_pkt *pkt2);
|
||||||
|
|
||||||
|
char * pkt_ntoa(struct net_pkt *pkt);
|
||||||
|
unsigned short pkt_getport(struct net_pkt *pkt);
|
||||||
|
int pkt_sameaddr(struct net_pkt *pkt1, struct net_pkt *pkt2);
|
||||||
|
int pkt_parse_int(struct net_pkt *pkt, unsigned int offset, int *val);
|
||||||
|
int pkt_parse_ip(struct net_pkt *pkt, int offset, struct in_addr *ip);
|
||||||
|
char * pkt_print(struct net_pkt *pkt);
|
||||||
|
|
||||||
#endif /* _NETPKT_H */
|
#endif /* _NETPKT_H */
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
* 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 "netpkt.h"
|
||||||
|
#include "plugin.h"
|
||||||
#include "plugin_helper.h"
|
#include "plugin_helper.h"
|
||||||
|
|
||||||
static struct scan_ports port_arr[] = {
|
static struct scan_ports port_arr[] = {
|
||||||
|
|
32
p_gamespy1.c
32
p_gamespy1.c
|
@ -17,7 +17,14 @@
|
||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "logging.h"
|
||||||
|
#include "event.h"
|
||||||
|
#include "netpkt.h"
|
||||||
|
#include "plugin.h"
|
||||||
#include "plugin_helper.h"
|
#include "plugin_helper.h"
|
||||||
|
|
||||||
static struct scan_ports port_arr[] = {
|
static struct scan_ports port_arr[] = {
|
||||||
|
@ -112,7 +119,7 @@ static struct net_pkt * gs1_pkt_merge(struct net_pkt *pkt, unsigned int queryid,
|
||||||
|
|
||||||
/* merge error, eat last paket, cleanup */
|
/* merge error, eat last paket, cleanup */
|
||||||
if (i != subid || notfound > subid) {
|
if (i != subid || notfound > subid) {
|
||||||
log_print("gs1: merging error!");
|
log_print(LOG_INFO, "gs1: merging error!");
|
||||||
free(pkt);
|
free(pkt);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -250,23 +257,38 @@ static int parse(struct net_pkt *pkt)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gc(int timeout) {
|
static int gc(void *privdata) {
|
||||||
struct gs1_part *part, *tmp;
|
|
||||||
|
unsigned int timeout = (int)privdata;
|
||||||
unsigned long now = time(NULL);
|
unsigned long now = time(NULL);
|
||||||
|
|
||||||
|
struct gs1_part *part, *tmp;
|
||||||
list_for_each_entry_safe(part, tmp, &gs1_partlist, list) {
|
list_for_each_entry_safe(part, tmp, &gs1_partlist, list) {
|
||||||
if (part->timeout + timeout < now) {
|
if (part->timeout + timeout < now) {
|
||||||
log_print("gs1: removing dead fragment");
|
log_print(LOG_INFO, "gs1: removing dead fragment");
|
||||||
list_del(&part->list);
|
list_del(&part->list);
|
||||||
free(part->pkt);
|
free(part->pkt);
|
||||||
free(part);
|
free(part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init(void)
|
||||||
|
{
|
||||||
|
int timeout = config_get_int("gamespy1", "gc_timeout", 90);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = timeout;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
event_add_timeout(&tv, gc, (void *)timeout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hlswmaster_plugin plugin = {
|
struct hlswmaster_plugin plugin = {
|
||||||
.name = "gamespy1",
|
.name = "gamespy1",
|
||||||
.scan = &scan,
|
.scan = &scan,
|
||||||
.parse = &parse,
|
.parse = &parse,
|
||||||
.gc = &gc,
|
.init = &init,
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
* 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 "netpkt.h"
|
||||||
|
#include "plugin.h"
|
||||||
#include "plugin_helper.h"
|
#include "plugin_helper.h"
|
||||||
|
|
||||||
static struct scan_ports port_arr[] = {
|
static struct scan_ports port_arr[] = {
|
||||||
|
|
119
p_halflife.c
119
p_halflife.c
|
@ -17,16 +17,25 @@
|
||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "plugin_helper.h"
|
|
||||||
|
|
||||||
struct net_entry {
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "netpkt.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "plugin_helper.h"
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
struct validnet_entry {
|
||||||
|
struct list_head list;
|
||||||
struct in_addr ip;
|
struct in_addr ip;
|
||||||
struct in_addr mask;
|
struct in_addr netmask;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct net_entry *net_arr = NULL;
|
static LIST_HEAD(validnet_list);
|
||||||
static int net_arr_size = 0;
|
|
||||||
|
|
||||||
static struct scan_ports port_arr[] = {
|
static struct scan_ports port_arr[] = {
|
||||||
{ 27015, 27024, 1 }, /* cs/hl */
|
{ 27015, 27024, 1 }, /* cs/hl */
|
||||||
|
@ -48,7 +57,7 @@ static int scan(void)
|
||||||
static int parse(struct net_pkt *pkt)
|
static int parse(struct net_pkt *pkt)
|
||||||
{
|
{
|
||||||
struct in_addr tmp;
|
struct in_addr tmp;
|
||||||
int port, count, pos, i;
|
int port, count, pos;
|
||||||
|
|
||||||
if (!pkt_check_portarr(pkt, port_arr))
|
if (!pkt_check_portarr(pkt, port_arr))
|
||||||
return PARSE_REJECT;
|
return PARSE_REJECT;
|
||||||
|
@ -80,8 +89,9 @@ static int parse(struct net_pkt *pkt)
|
||||||
return PARSE_REJECT;
|
return PARSE_REJECT;
|
||||||
|
|
||||||
/* check server IP */
|
/* check server IP */
|
||||||
for (i = 0; i < net_arr_size; i++) {
|
struct validnet_entry *entry;
|
||||||
if (((net_arr[i].ip.s_addr ^ tmp.s_addr) & net_arr[i].mask.s_addr) == 0) {
|
list_for_each_entry(entry, &validnet_list, list) {
|
||||||
|
if (((entry->ip.s_addr ^ tmp.s_addr) & entry->netmask.s_addr) == 0) {
|
||||||
server_add(1, tmp.s_addr, port, 0);
|
server_add(1, tmp.s_addr, port, 0);
|
||||||
return PARSE_ACCEPT;
|
return PARSE_ACCEPT;
|
||||||
}
|
}
|
||||||
|
@ -91,86 +101,74 @@ static int parse(struct net_pkt *pkt)
|
||||||
return PARSE_ACCEPT;
|
return PARSE_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_net(char *buf, struct net_entry *net)
|
// TODO: wrong place
|
||||||
|
int parse_ipmask(const char *value, struct in_addr *ip, struct in_addr *netmask)
|
||||||
{
|
{
|
||||||
char *p;
|
|
||||||
|
char *buf = strdup(value);
|
||||||
|
if (buf == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int retval = -1;
|
||||||
|
char *p = strchr(buf, '/');
|
||||||
|
|
||||||
/* valid_net x.x.x.x */
|
/* valid_net x.x.x.x */
|
||||||
if ((p = strchr(buf, '/')) == NULL) {
|
if (p == NULL) {
|
||||||
/* ip */
|
/* single ip */
|
||||||
if (inet_pton(AF_INET, buf, &net->ip) <= 0)
|
if (inet_pton(AF_INET, buf, ip) > 0) {
|
||||||
return 0;
|
netmask->s_addr = 0xFFFFFFFF;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* mask */
|
/* valid_net x.x.x.x/x.x.x.x or x.x.x.x/xx */
|
||||||
net->mask.s_addr = 0xFFFFFFFF;
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* valid_net x.x.x.x/x.x.x.x oder x.x.x.x/xx */
|
|
||||||
} else {
|
} else {
|
||||||
int retval, mask;
|
|
||||||
*p = 0x00;
|
*p = 0x00;
|
||||||
|
|
||||||
/* ip */
|
/* ip */
|
||||||
if (inet_pton(AF_INET, buf, &net->ip) <= 0) {
|
if (inet_pton(AF_INET, buf, &ip) > 0) {
|
||||||
retval = 0;
|
|
||||||
|
|
||||||
/* x.x.x.x/x.x.x.x */
|
/* x.x.x.x/x.x.x.x */
|
||||||
} else if (inet_pton(AF_INET, p+1, &net->mask) > 0) {
|
if (inet_pton(AF_INET, p+1, netmask) > 0) {
|
||||||
retval = 1;
|
retval = 0;
|
||||||
|
|
||||||
/* x.x.x.x/xx */
|
/* x.x.x.x/xx */
|
||||||
} else {
|
} else {
|
||||||
mask = atoi(p+1);
|
int mask = atoi(p+1);
|
||||||
|
|
||||||
if (mask >= 0 && mask <= 32) {
|
if (mask >= 0 && mask <= 32) {
|
||||||
net->mask.s_addr = htonl(0xFFFFFFFF << (32 - mask));
|
netmask->s_addr = htonl(0xFFFFFFFF << (32 - mask));
|
||||||
retval = 1;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
*p = '/';
|
*p = '/';
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int init_callback(const char *value, void *privdata)
|
||||||
|
{
|
||||||
|
struct validnet_entry *entry = malloc(sizeof(struct validnet_entry));
|
||||||
|
if (entry == NULL) {
|
||||||
|
log_print(LOG_ERROR, "halflife_init(): out of memory");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init(struct conf_section *section)
|
if (parse_ipmask(value, &entry->ip, &entry->netmask) != 0) {
|
||||||
{
|
log_print(LOG_WARN, " invalid dst: %s", value);
|
||||||
struct conf_tupel *tupel;
|
free(entry);
|
||||||
static char buf[32];
|
return -1;
|
||||||
int i = 0, j;
|
}
|
||||||
|
|
||||||
list_for_each_entry(tupel, §ion->tupel, list)
|
list_add(&entry->list, &validnet_list);
|
||||||
if (!strcmp(tupel->option, "valid_net"))
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i == 0 || !(net_arr = malloc(sizeof(struct net_entry) * i)))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
list_for_each_entry(tupel, §ion->tupel, list) {
|
|
||||||
if (strcmp(tupel->option, "valid_net"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (parse_net(tupel->parameter, &net_arr[i])) {
|
|
||||||
j = sprintf(buf, " adding: %s", inet_ntoa(net_arr[i].ip));
|
|
||||||
sprintf(buf + j, "/%s", inet_ntoa(net_arr[i].mask));
|
|
||||||
log_print(buf);
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
log_print(" invalid net: %s", tupel->parameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
net_arr_size = i;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fini()
|
static int init(void)
|
||||||
{
|
{
|
||||||
if (net_arr_size > 0 && net_arr)
|
config_get_strings("halflife", "valid_net", init_callback, NULL);
|
||||||
free(net_arr);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hlswmaster_plugin plugin = {
|
struct hlswmaster_plugin plugin = {
|
||||||
|
@ -178,5 +176,4 @@ struct hlswmaster_plugin plugin = {
|
||||||
.scan = &scan,
|
.scan = &scan,
|
||||||
.parse = &parse,
|
.parse = &parse,
|
||||||
.init = &init,
|
.init = &init,
|
||||||
.fini = &fini,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,82 +17,89 @@
|
||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/ip.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "plugin_helper.h"
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
struct hlsw_entry {
|
#include "netpkt.h"
|
||||||
|
#include "plugin.h"
|
||||||
|
#include "plugin_helper.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "scanner.h"
|
||||||
|
|
||||||
|
struct game_entry {
|
||||||
uint16_t gameid;
|
uint16_t gameid;
|
||||||
uint32_t ip;
|
uint32_t ip;
|
||||||
uint16_t port1;
|
uint16_t port1;
|
||||||
uint16_t port2;
|
uint16_t port2;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
static struct in_addr *ip_arr = NULL;
|
struct master_entry {
|
||||||
static int ip_arr_size = 0;
|
struct list_head list;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static LIST_HEAD(master_list);
|
||||||
|
|
||||||
static char scanmsg[] = "\xff\xff\xff\xffHLSWLANSEARCH";
|
static char scanmsg[] = "\xff\xff\xff\xffHLSWLANSEARCH";
|
||||||
|
|
||||||
static int scan(void)
|
static int scan(void)
|
||||||
{
|
{
|
||||||
int i;
|
struct master_entry *entry;
|
||||||
for (i = 0; i < ip_arr_size; i++)
|
list_for_each_entry(entry, &master_list, list)
|
||||||
pkt_send(&ip_arr[i], 7140, scanmsg, sizeof(scanmsg));
|
pkt_send(&entry->addr.sin_addr, ntohs(entry->addr.sin_port), scanmsg, sizeof(scanmsg));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse(struct net_pkt *pkt)
|
static int parse(struct net_pkt *pkt)
|
||||||
{
|
{
|
||||||
struct hlsw_entry *server;
|
// TODO: check against master_list
|
||||||
if (pkt_getport(pkt) != 7140)
|
if (pkt_getport(pkt) != 7140)
|
||||||
return PARSE_REJECT;
|
return PARSE_REJECT;
|
||||||
|
|
||||||
server = (void *)pkt->buf + sizeof(scanmsg);
|
struct game_entry *game = (void *)pkt->buf + sizeof(scanmsg);
|
||||||
|
|
||||||
while ((void *)server < ((void *)pkt->buf + pkt->size)) {
|
while ((void *)game < ((void *)pkt->buf + pkt->size)) {
|
||||||
server_add(server->gameid, server->ip, server->port1, server->port2);
|
server_add(game->gameid, game->ip, game->port1, game->port2);
|
||||||
server++;
|
game++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PARSE_ACCEPT;
|
return PARSE_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init(struct conf_section *section)
|
static int init_callback(const char *value, void *privdata)
|
||||||
{
|
{
|
||||||
struct conf_tupel *tupel;
|
struct master_entry *entry = malloc(sizeof(struct master_entry));
|
||||||
int i = 0;
|
if (entry == NULL) {
|
||||||
list_for_each_entry(tupel, §ion->tupel, list)
|
log_print(LOG_ERROR, "hlswproxy_init(): out of memory");
|
||||||
if (!strcmp(tupel->option, "scan_ip"))
|
return -1;
|
||||||
i++;
|
}
|
||||||
|
|
||||||
if (i == 0 || !(ip_arr = malloc(sizeof(struct in_addr) * i)))
|
if (parse_saddr(value, &entry->addr) != 0) {
|
||||||
|
log_print(LOG_WARN, " invalid dst: %s", value);
|
||||||
|
free(entry);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_print(LOG_INFO, " adding remote master %s:%d",
|
||||||
|
inet_ntoa(entry->addr.sin_addr), ntohs(entry->addr.sin_port));
|
||||||
|
|
||||||
|
list_add(&entry->list, &master_list);
|
||||||
return 0;
|
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;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fini()
|
static int init(void)
|
||||||
{
|
{
|
||||||
if (ip_arr_size > 0 && ip_arr)
|
if (config_get_strings("hlswproxy", "scan", init_callback, NULL) <= 0)
|
||||||
free(ip_arr);
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hlswmaster_plugin plugin = {
|
struct hlswmaster_plugin plugin = {
|
||||||
|
@ -100,5 +107,4 @@ struct hlswmaster_plugin plugin = {
|
||||||
.scan = &scan,
|
.scan = &scan,
|
||||||
.parse = &parse,
|
.parse = &parse,
|
||||||
.init = &init,
|
.init = &init,
|
||||||
.fini = &fini,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
* 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 "netpkt.h"
|
||||||
|
#include "plugin.h"
|
||||||
#include "plugin_helper.h"
|
#include "plugin_helper.h"
|
||||||
|
|
||||||
static struct scan_ports port_arr[] = {
|
static struct scan_ports port_arr[] = {
|
||||||
|
|
|
@ -18,7 +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 "netpkt.h"
|
||||||
|
#include "plugin.h"
|
||||||
#include "plugin_helper.h"
|
#include "plugin_helper.h"
|
||||||
|
#include "scanner.h"
|
||||||
|
|
||||||
static char scanmsg[] = "\xff\xff\xff\xffinfo 34"; /* q2(3) */
|
static char scanmsg[] = "\xff\xff\xff\xffinfo 34"; /* q2(3) */
|
||||||
static char replymsg[] = "\xff\xff\xff\xffinfo";
|
static char replymsg[] = "\xff\xff\xff\xffinfo";
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
* 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 "netpkt.h"
|
||||||
|
#include "scanner.h"
|
||||||
|
#include "plugin.h"
|
||||||
#include "plugin_helper.h"
|
#include "plugin_helper.h"
|
||||||
|
|
||||||
static char scanmsg1[] = "\x80\x00\x00\x00\x00";
|
static char scanmsg1[] = "\x80\x00\x00\x00\x00";
|
||||||
|
|
181
plugin.c
181
plugin.c
|
@ -17,174 +17,97 @@
|
||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include "hlswmaster.h"
|
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
|
#include "logging.h"
|
||||||
#include "netpkt.h"
|
#include "netpkt.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
|
#define BUFSIZE 512
|
||||||
|
|
||||||
/** liste der geladenen plugins */
|
|
||||||
static LIST_HEAD(plugin_list);
|
static LIST_HEAD(plugin_list);
|
||||||
|
|
||||||
/** sichert die plugin liste UND die plugins selbst ab */
|
static int plugin_load(const char *filename, void *privdata)
|
||||||
static pthread_mutex_t plugin_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plugin_load()
|
|
||||||
* laedt ein plugin und fuegt es in die plugin liste ein
|
|
||||||
*
|
|
||||||
* @param *name filename des plugins
|
|
||||||
* @return false on error
|
|
||||||
*/
|
|
||||||
int plugin_load(char *name)
|
|
||||||
{
|
{
|
||||||
struct hlswmaster_plugin *plugin;
|
char *plugin_dir = (char *)privdata;
|
||||||
void *tmp;
|
|
||||||
struct conf_section *section;
|
char *fullname = malloc(BUFSIZE);
|
||||||
|
if (fullname == NULL) {
|
||||||
|
log_print(LOG_ERROR, "plugin_load: out of memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = snprintf(fullname, BUFSIZE, "%s/%s", plugin_dir, filename);
|
||||||
|
if (len < 0 || len >= BUFSIZE) {
|
||||||
|
log_print(LOG_ERROR, "plugin_load: file name too long: %s/%s", plugin_dir, filename);
|
||||||
|
free(fullname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
dlerror();
|
dlerror();
|
||||||
|
void *dlref = dlopen(fullname, RTLD_NOW);
|
||||||
|
if (dlref == NULL) {
|
||||||
|
log_print(LOG_WARN, "plugin_load: %s", dlerror());
|
||||||
|
free(fullname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* shared objekt oeffnen */
|
struct hlswmaster_plugin *plugin = dlsym(dlref, "plugin");
|
||||||
if ((tmp = dlopen(name, RTLD_NOW))) {
|
if (plugin == NULL) {
|
||||||
|
log_print(LOG_WARN, "plugin_load: invalid plugin '%s'", fullname);
|
||||||
|
dlclose(dlref);
|
||||||
|
free(fullname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* plugin struct suchen */
|
log_print(LOG_INFO, "loading plugin '%s'", plugin->name);
|
||||||
if ((plugin = dlsym(tmp, "plugin"))) {
|
|
||||||
plugin->dlref = tmp;
|
|
||||||
|
|
||||||
section = config_get_section(plugin->name);
|
if (plugin->init == NULL || (plugin->init() == 0)) {
|
||||||
log_print("loading plugin '%s'", plugin->name);
|
|
||||||
|
|
||||||
/* wenn vorhanden, init aufrufen */
|
|
||||||
if (!plugin->init || (plugin->init(section))) {
|
|
||||||
pthread_mutex_lock(&plugin_lock);
|
|
||||||
list_add_tail(&plugin->list, &plugin_list);
|
list_add_tail(&plugin->list, &plugin_list);
|
||||||
pthread_mutex_unlock(&plugin_lock);
|
free(fullname);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_print("failed to load '%s'", name);
|
|
||||||
dlclose(tmp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
dlclose(tmp);
|
|
||||||
}
|
|
||||||
log_print("%s", dlerror());
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_print(LOG_WARN, "plugin_load: failed to load '%s'", plugin->name);
|
||||||
/**
|
dlclose(dlref);
|
||||||
* plugin_load_all()
|
free(fullname);
|
||||||
* laedt alle in der config angegebenen plugins
|
return -1;
|
||||||
*
|
|
||||||
* @return false on error
|
|
||||||
*/
|
|
||||||
int plugin_load_all()
|
|
||||||
{
|
|
||||||
struct conf_section *section;
|
|
||||||
struct conf_tupel *tupel;
|
|
||||||
|
|
||||||
section = config_get_section("global");
|
|
||||||
if (section) {
|
|
||||||
list_for_each_entry(tupel, §ion->tupel, list)
|
|
||||||
if (!strcmp(tupel->option, "plugin"))
|
|
||||||
plugin_load(tupel->parameter);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plugin_unload_all()
|
|
||||||
* entfernt alle plugins aus der liste,
|
|
||||||
*
|
|
||||||
* @return false on error
|
|
||||||
*/
|
|
||||||
int plugin_unload_all()
|
|
||||||
{
|
|
||||||
struct hlswmaster_plugin *plugin, *tmp;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&plugin_lock);
|
|
||||||
list_for_each_entry_safe(plugin, tmp, &plugin_list, list) {
|
|
||||||
list_del(&plugin->list);
|
|
||||||
|
|
||||||
if (plugin->fini)
|
|
||||||
plugin->fini();
|
|
||||||
|
|
||||||
log_print("plugin '%s' unloaded", plugin->name);
|
|
||||||
dlclose(plugin->dlref);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&plugin_lock);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* plugins_scan()
|
|
||||||
* ruft die scan() Funktionen der Plugins auf
|
|
||||||
*
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
int plugins_scan(void)
|
int plugins_scan(void)
|
||||||
{
|
{
|
||||||
struct hlswmaster_plugin *plugin;
|
struct hlswmaster_plugin *plugin;
|
||||||
|
|
||||||
pthread_mutex_lock(&plugin_lock);
|
|
||||||
list_for_each_entry(plugin, &plugin_list, list)
|
list_for_each_entry(plugin, &plugin_list, list)
|
||||||
/* wenn vorhanden die scan funktion aufrufen */
|
|
||||||
if (plugin->scan && !plugin->scan())
|
if (plugin->scan && !plugin->scan())
|
||||||
log_print("plugin %s: scan error", plugin->name);
|
log_print(LOG_WARN, "plugin %s: scan error", plugin->name);
|
||||||
|
|
||||||
pthread_mutex_unlock(&plugin_lock);
|
return 0;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* plugins_parse()
|
|
||||||
* ruft die parse() Funktionen der Plugins auf
|
|
||||||
* bis ein Plugin das Paket annimmt
|
|
||||||
*
|
|
||||||
* @param *pkt das zu parsene paket
|
|
||||||
* @return false wenn kein Plugin das Paket angenommen,
|
|
||||||
* sonst rueckgabewert des Plugins
|
|
||||||
*/
|
|
||||||
int plugins_parse(struct net_pkt *pkt)
|
int plugins_parse(struct net_pkt *pkt)
|
||||||
{
|
{
|
||||||
struct hlswmaster_plugin *plugin;
|
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
pthread_mutex_lock(&plugin_lock);
|
struct hlswmaster_plugin *plugin;
|
||||||
list_for_each_entry(plugin, &plugin_list, list) {
|
list_for_each_entry(plugin, &plugin_list, list)
|
||||||
/* wenn vorhanden die parse funktion aufrufen */
|
if (plugin->parse && (retval = plugin->parse(pkt)))
|
||||||
if (plugin->parse && (retval = plugin->parse(pkt))) {
|
|
||||||
pthread_mutex_unlock(&plugin_lock);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&plugin_lock);
|
|
||||||
return PARSE_REJECT;
|
return PARSE_REJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int plugin_init(void)
|
||||||
* plugins_gc()
|
|
||||||
* ruft die gc() Funktionen der Plugins auf
|
|
||||||
*
|
|
||||||
* @param timeout timeout interval in sekunden
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
int plugins_gc(unsigned long timeout)
|
|
||||||
{
|
{
|
||||||
struct hlswmaster_plugin *plugin;
|
char *dir = config_get_string("global", "plugin_dir", ".");
|
||||||
|
int cnt = config_get_strings("global", "plugin", plugin_load, (void *)dir);
|
||||||
|
|
||||||
pthread_mutex_lock(&plugin_lock);
|
log_print(LOG_INFO, "%d plugins loaded", cnt);
|
||||||
list_for_each_entry(plugin, &plugin_list, list)
|
return 0;
|
||||||
if (plugin->gc)
|
|
||||||
plugin->gc(timeout);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&plugin_lock);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
plugin.h
9
plugin.h
|
@ -16,15 +16,16 @@
|
||||||
|
|
||||||
struct hlswmaster_plugin {
|
struct hlswmaster_plugin {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
|
||||||
char name[32];
|
char name[32];
|
||||||
void *dlref;
|
|
||||||
|
|
||||||
int (*init)(struct conf_section *config);
|
int (*init)(void);
|
||||||
int (*fini)(void);
|
int (*fini)(void);
|
||||||
int (*scan)(void);
|
int (*scan)(void);
|
||||||
int (*parse)(struct net_pkt *pkt);
|
int (*parse)(struct net_pkt *pkt);
|
||||||
int (*gc)(int timeout);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int plugin_init();
|
||||||
|
int plugins_scan();
|
||||||
|
int plugins_parse(struct net_pkt *pkt);
|
||||||
|
|
||||||
#endif /* _PLUGIN_H */
|
#endif /* _PLUGIN_H */
|
||||||
|
|
281
plugin_helper.c
281
plugin_helper.c
|
@ -20,55 +20,50 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define __USE_GNU
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include "gamelist.h"
|
||||||
|
#include "logging.h"
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netinet/ip.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
#include "hlswmaster.h"
|
|
||||||
#include "netpkt.h"
|
#include "netpkt.h"
|
||||||
#include "plugin.h"
|
|
||||||
#include "plugin_helper.h"
|
#include "plugin_helper.h"
|
||||||
|
#include "scanner.h"
|
||||||
|
|
||||||
|
int server_add(uint16_t gameid, uint32_t ip, uint16_t port1, uint16_t port2)
|
||||||
|
{
|
||||||
|
struct game_entry *entry = malloc(sizeof(struct game_entry));
|
||||||
|
if (entry == NULL) {
|
||||||
|
log_print(LOG_WARN, "server_add(): out of memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->gameid = gameid;
|
||||||
|
entry->ip = ip;
|
||||||
|
entry->port1 = port1;
|
||||||
|
entry->port2 = port2;
|
||||||
|
|
||||||
|
return gamelist_add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
int server_add_pkt(unsigned int gameid, struct net_pkt *pkt)
|
||||||
|
{
|
||||||
|
return server_add(gameid, pkt->addr.sin_addr.s_addr, ntohs(pkt->addr.sin_port), 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_queue_portarr()
|
|
||||||
* sendet an eine reihe von ports
|
|
||||||
*
|
|
||||||
* @param *dstip destination IP, wenn NULL wird broadcast angenommen
|
|
||||||
* @param *portarr ports an die gesendet wird
|
|
||||||
* @param *buf daten die gesendet werden
|
|
||||||
* @param size groesse der daten
|
|
||||||
* @return false bei fehler
|
|
||||||
*/
|
|
||||||
int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size)
|
int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size)
|
||||||
{
|
{
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
int ret = 1;
|
int ret = 0;
|
||||||
|
|
||||||
while (portarr && portarr->portlo) {
|
while (portarr && portarr->portlo) {
|
||||||
for (port = portarr->portlo; port <= portarr->porthi; port++)
|
for (port = portarr->portlo; port <= portarr->porthi; port++)
|
||||||
if (!pkt_send(dstip, port, buf, size))
|
if (pkt_send(dstip, port, buf, size) < 0)
|
||||||
ret = 0;
|
ret = -1;
|
||||||
|
|
||||||
portarr++;
|
portarr++;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_check_portarr()
|
|
||||||
* prueft ob der src-port des pakets in der portliste vorhanden ist
|
|
||||||
*
|
|
||||||
* @param *pkt paket vom gameserver
|
|
||||||
* @param *portarr ports die angenommen werden
|
|
||||||
* @return die gameid der portrange oder 0 wenn nicht vorhanden
|
|
||||||
*/
|
|
||||||
int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr)
|
int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr)
|
||||||
{
|
{
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
|
@ -81,225 +76,3 @@ int pkt_check_portarr(struct net_pkt *pkt, struct scan_ports *portarr)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_memcmp()
|
|
||||||
* vergleicht das Paket mit einem Speicherbereich
|
|
||||||
*
|
|
||||||
* @param *pkt paket vom gameserver
|
|
||||||
* @param offset offset ab dem verglichen wird
|
|
||||||
* @param *search daten nach denen gesucht wird
|
|
||||||
* @param size laenge der daten
|
|
||||||
* @return false wenn gleich
|
|
||||||
*
|
|
||||||
* @todo return false wenn offset + size >= pkt->size ?
|
|
||||||
*/
|
|
||||||
int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (offset >= pkt->size)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* nicht ueber das paket hinaus vergleichen */
|
|
||||||
if (offset + size >= pkt->size)
|
|
||||||
size = pkt->size - offset;
|
|
||||||
|
|
||||||
return memcmp(pkt->buf + offset, search, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_memmem()
|
|
||||||
* sucht einen Speicherbereich in dem Paket
|
|
||||||
*
|
|
||||||
* @param *pkt paket vom gameserver
|
|
||||||
* @param offset offset ab dem gesucht wird
|
|
||||||
* @param *search daten nach denen gesucht wird
|
|
||||||
* @param size laenge der daten
|
|
||||||
* @return offset auf den string im Paket, oder -1 wenn nicht gefunden
|
|
||||||
*/
|
|
||||||
int pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size)
|
|
||||||
{
|
|
||||||
void *found;
|
|
||||||
|
|
||||||
if (offset >= pkt->size)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
found = memmem(pkt->buf + offset, pkt->size, search, size);
|
|
||||||
|
|
||||||
return (found == NULL) ? -1 : (found - (void *)pkt->buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_merge()
|
|
||||||
* fuegt zwei pakete zu einem zusammen
|
|
||||||
* die header werden vom ersten Paket uebernommen
|
|
||||||
* die pakete werden nicht gefreed(!)
|
|
||||||
*
|
|
||||||
* @param *pkt1 erstes Paket
|
|
||||||
* @param *pkt2 zweites Paket
|
|
||||||
* @return zusammengefasstes Paket
|
|
||||||
*/
|
|
||||||
struct net_pkt * pkt_merge(struct net_pkt *pkt1, struct net_pkt *pkt2)
|
|
||||||
{
|
|
||||||
struct net_pkt *ret;
|
|
||||||
ret = malloc(sizeof(struct net_pkt) + pkt1->size + pkt2->size);
|
|
||||||
|
|
||||||
memcpy(&ret->addr, &pkt1->addr, sizeof(ret->addr));
|
|
||||||
ret->size = pkt1->size + pkt2->size;
|
|
||||||
|
|
||||||
memcpy(ret->buf, pkt1->buf, pkt1->size);
|
|
||||||
memcpy(ret->buf + pkt1->size, pkt2->buf, pkt2->size);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* server_add_pkt()
|
|
||||||
* fuegt der serverliste einen server hinzu
|
|
||||||
*
|
|
||||||
* @param gameid gameid des gameservers
|
|
||||||
* @param *pkt daten vom gameserver (fuer ip/port)
|
|
||||||
* @return false bei fehler
|
|
||||||
*/
|
|
||||||
int server_add_pkt(unsigned int gameid, struct net_pkt *pkt)
|
|
||||||
{
|
|
||||||
return server_add(gameid, pkt->addr.sin_addr.s_addr, ntohs(pkt->addr.sin_port), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_ntoa()
|
|
||||||
* gibt die IP des Pakets als String zurueck
|
|
||||||
*
|
|
||||||
* @param *pkt daten vom gameserver
|
|
||||||
* @return pointer auf String
|
|
||||||
*/
|
|
||||||
char * pkt_ntoa(struct net_pkt *pkt)
|
|
||||||
{
|
|
||||||
return inet_ntoa(pkt->addr.sin_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_getport()
|
|
||||||
* gibt den Port des Pakets als short zurueck
|
|
||||||
*
|
|
||||||
* @param *pkt daten vom gameserver
|
|
||||||
* @return portnummer
|
|
||||||
*/
|
|
||||||
unsigned short pkt_getport(struct net_pkt *pkt)
|
|
||||||
{
|
|
||||||
return ntohs(pkt->addr.sin_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_sameaddr()
|
|
||||||
* vergleicht die Adressen zweier Pakete
|
|
||||||
*
|
|
||||||
* @param *pkt1 Paket 1
|
|
||||||
* @param *pkt2 Paket 2
|
|
||||||
* @return true wenn Adressen gleich
|
|
||||||
*/
|
|
||||||
int pkt_sameaddr(struct net_pkt *pkt1, struct net_pkt *pkt2)
|
|
||||||
{
|
|
||||||
return (pkt1->addr.sin_addr.s_addr == pkt2->addr.sin_addr.s_addr) &&
|
|
||||||
(pkt1->addr.sin_port == pkt2->addr.sin_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_parse_int()
|
|
||||||
* gibt die dezimalzahl in dem paket ab einer position zurueck
|
|
||||||
*
|
|
||||||
* @param *pkt daten vom gameserver
|
|
||||||
* @param offset offset auf den begin des integers
|
|
||||||
* @param *val pointer auf das ergebnis
|
|
||||||
* @return Anzahl der gelesenen Zeichen oder 0 bei fehler
|
|
||||||
*/
|
|
||||||
int pkt_parse_int(struct net_pkt *pkt, unsigned int offset, int *val)
|
|
||||||
{
|
|
||||||
unsigned char *max = pkt->buf + pkt->size;
|
|
||||||
unsigned char *c = pkt->buf + offset;
|
|
||||||
|
|
||||||
/* untere grenze abtesten */
|
|
||||||
if (pkt->buf > c || c > max)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
*val = 0;
|
|
||||||
|
|
||||||
/* ziffern einlesen */
|
|
||||||
while (isdigit(*c) && c < max)
|
|
||||||
*val = (*val * 10) + (*c++ - 0x30);
|
|
||||||
|
|
||||||
return (c - (pkt->buf + offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_parse_ip()
|
|
||||||
* gibt die IP in *.*.*.* ab p als integer zurueck
|
|
||||||
*
|
|
||||||
* @param *pkt daten vom gameserver
|
|
||||||
* @param offset offset auf den begin der IP
|
|
||||||
* @param *ip pointer auf eine in_addr struct
|
|
||||||
* @return Anzahl der gelesenen Zeichen oder 0 bei Fehler
|
|
||||||
*/
|
|
||||||
int pkt_parse_ip(struct net_pkt *pkt, int offset, struct in_addr *ip)
|
|
||||||
{
|
|
||||||
int i, tmp, count, pos = offset;
|
|
||||||
ip->s_addr = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
count = pkt_parse_int(pkt, pos, &tmp);
|
|
||||||
pos += count;
|
|
||||||
if (count == 0 || tmp < 0 || tmp > 255)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ip->s_addr = ip->s_addr>>8 | tmp<<24;
|
|
||||||
|
|
||||||
if (i != 3 && pkt->buf[pos++] != '.')
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return pos - offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* pkt_print()
|
|
||||||
* gibt ein paket als hex-dump aus
|
|
||||||
*
|
|
||||||
* @param *pkt daten vom gameserver
|
|
||||||
* @return char pointer auf hex-dump
|
|
||||||
*/
|
|
||||||
char * pkt_print(struct net_pkt *pkt)
|
|
||||||
{
|
|
||||||
int pos = 0, i = 0, j;
|
|
||||||
char *buf = malloc(pkt->size * 4 + 64);
|
|
||||||
|
|
||||||
while (pos < pkt->size) {
|
|
||||||
i += sprintf(buf + i, "%04X: ", pos);
|
|
||||||
for (j = 0; j < 16; j++) {
|
|
||||||
if (pos + j < pkt->size)
|
|
||||||
i += sprintf(buf + i, "%02X", pkt->buf[pos + j]);
|
|
||||||
else
|
|
||||||
i += sprintf(buf + i, " ");
|
|
||||||
|
|
||||||
if (j % 2)
|
|
||||||
buf[i++] = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 0; j < 16; j++) {
|
|
||||||
if (pos + j < pkt->size) {
|
|
||||||
unsigned char val = pkt->buf[pos + j];
|
|
||||||
if (val >= 0x20 && val < 0x80)
|
|
||||||
buf[i++] = val;
|
|
||||||
else
|
|
||||||
buf[i++] = '.';
|
|
||||||
} else {
|
|
||||||
buf[i++] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += 16;
|
|
||||||
buf[i++] = '\r';
|
|
||||||
buf[i++] = '\n';
|
|
||||||
}
|
|
||||||
buf[i] = 0;
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,35 +1,15 @@
|
||||||
#ifndef _PLUGIN_HELPER_H
|
#ifndef _PLUGIN_HELPER_H
|
||||||
#define _PLUGIN_HELPER_H
|
#define _PLUGIN_HELPER_H
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include "netpkt.h"
|
|
||||||
#include "list.h"
|
|
||||||
#include "plugin.h"
|
|
||||||
|
|
||||||
extern int server_add(uint16_t gameid, uint32_t ip, uint16_t port1, uint16_t port2);
|
|
||||||
|
|
||||||
struct scan_ports {
|
struct scan_ports {
|
||||||
unsigned short portlo;
|
unsigned short portlo;
|
||||||
unsigned short porthi;
|
unsigned short porthi;
|
||||||
unsigned short gameid;
|
unsigned short gameid;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size);
|
int server_add(uint16_t gameid, uint32_t ip, uint16_t port1, uint16_t port2);
|
||||||
extern int pkt_send_portarr(struct in_addr *dstip, struct scan_ports *portarr, char *buf, unsigned int size);
|
int server_add_pkt(unsigned int gameid, struct net_pkt *pkt);
|
||||||
|
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);
|
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 int pkt_memmem(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
|
|
||||||
extern struct net_pkt * pkt_merge(struct net_pkt *pkt1, struct net_pkt *pkt2);
|
|
||||||
|
|
||||||
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_sameaddr(struct net_pkt *pkt1, struct net_pkt *pkt2);
|
|
||||||
extern int pkt_parse_int(struct net_pkt *pkt, unsigned int offset, int *val);
|
|
||||||
extern int pkt_parse_ip(struct net_pkt *pkt, int offset, struct in_addr *ip);
|
|
||||||
extern char * pkt_print(struct net_pkt *pkt);
|
|
||||||
|
|
||||||
#endif /* _PLUGIN_HELPER_H */
|
#endif /* _PLUGIN_HELPER_H */
|
||||||
|
|
438
scanner.c
438
scanner.c
|
@ -21,211 +21,101 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include <semaphore.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include "list.h"
|
#include "event.h"
|
||||||
#include "netpkt.h"
|
#include "netpkt.h"
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include "hlswmaster.h"
|
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "plugin_helper.h"
|
#include "scanner.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "gamelist.h"
|
||||||
|
|
||||||
#define DEBUG 1
|
static LIST_HEAD(tx_queue);
|
||||||
|
|
||||||
struct rx_entry {
|
|
||||||
struct list_head list;
|
|
||||||
struct net_pkt *pkt;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** rx packet liste */
|
|
||||||
static LIST_HEAD(rxlist);
|
|
||||||
|
|
||||||
/** sichert die rx liste */
|
|
||||||
static pthread_mutex_t rxlist_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
|
|
||||||
/** anzahl der pakete in der rxlist */
|
|
||||||
static sem_t rxlist_sem;
|
|
||||||
|
|
||||||
/** interne serverliste */
|
|
||||||
static LIST_HEAD(serverlist);
|
|
||||||
|
|
||||||
/** sichert die interne serverliste */
|
|
||||||
static pthread_mutex_t serverlist_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
|
|
||||||
/** scan socket */
|
|
||||||
static int scan_sock;
|
static int scan_sock;
|
||||||
|
|
||||||
/**
|
|
||||||
* server_cmp()
|
|
||||||
* LIST_FIND helper
|
|
||||||
*
|
|
||||||
* @param *a gameserver 1
|
|
||||||
* @param *b gameserver 2
|
|
||||||
* @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()
|
|
||||||
* wenn der server noch nicht in der internen liste vorhanden ist
|
|
||||||
* wird er hinzugefuegt, ansonsten nur die modtime angepasst
|
|
||||||
*
|
|
||||||
* @param gameid gameid des servers
|
|
||||||
* @param ip ip des servers
|
|
||||||
* @param port1 erster port
|
|
||||||
* @param port2 zweiter port
|
|
||||||
* @return false bei fehler
|
|
||||||
*/
|
|
||||||
int server_add(uint16_t gameid, uint32_t ip, uint16_t port1, uint16_t port2)
|
|
||||||
{
|
|
||||||
struct game_server server, *nserver;
|
|
||||||
|
|
||||||
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 timeout timeout in sekunden
|
|
||||||
*/
|
|
||||||
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 *dstip destination IP, wenn NULL wird broadcast angenommen
|
|
||||||
* @param dstport destination port
|
|
||||||
* @param *buf datenbereich der gesendet wird
|
|
||||||
* @param size groesse der daten
|
|
||||||
* @return false bei fehler
|
|
||||||
*/
|
|
||||||
int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size)
|
int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size)
|
||||||
{
|
{
|
||||||
struct sockaddr_in addr;
|
struct net_pkt *pkt = malloc(sizeof(struct net_pkt) + size);
|
||||||
int ret = 1;
|
if (pkt == NULL) {
|
||||||
|
log_print(LOG_WARN, "pkt_send(): out of memory");
|
||||||
addr.sin_family = AF_INET;
|
return -1;
|
||||||
addr.sin_port = htons(dstport);
|
|
||||||
addr.sin_addr.s_addr = (dstip ? dstip->s_addr : 0xFFFFFFFF);
|
|
||||||
|
|
||||||
if (sendto(scan_sock, buf, size, 0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
||||||
log_print("scan_send(): sendto()");
|
|
||||||
ret = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
usleep(10000);
|
pkt->addr.sin_family = AF_INET;
|
||||||
return ret;
|
pkt->addr.sin_port = htons(dstport);
|
||||||
|
pkt->addr.sin_addr.s_addr = (dstip ? dstip->s_addr : 0xFFFFFFFF);
|
||||||
|
|
||||||
|
memcpy(pkt->buf, buf, size);
|
||||||
|
pkt->size = size;
|
||||||
|
|
||||||
|
list_add_tail(&pkt->list, &tx_queue);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static int scanner_transmit(void *privdata)
|
||||||
* scan_receive_real()
|
|
||||||
* arbeitet die receive queue ab
|
|
||||||
*/
|
|
||||||
void scan_receive_real(void)
|
|
||||||
{
|
{
|
||||||
struct rx_entry *rx;
|
if (list_empty(&tx_queue))
|
||||||
|
return -1;
|
||||||
|
|
||||||
struct net_pkt *pkt;
|
struct net_pkt *pkt;
|
||||||
int cnt, retval;
|
pkt = list_entry(tx_queue.next, struct net_pkt, list);
|
||||||
|
list_del(&pkt->list);
|
||||||
|
|
||||||
do {
|
int ret = sendto(scan_sock, pkt->buf, pkt->size, 0, (struct sockaddr *)&pkt->addr, sizeof(pkt->addr));
|
||||||
sem_wait(&rxlist_sem);
|
if (ret <= 0)
|
||||||
|
log_print(LOG_WARN, "scanner_transmit(): sendto()");
|
||||||
|
|
||||||
pthread_mutex_lock(&rxlist_lock);
|
return 0;
|
||||||
rx = list_entry(rxlist.next, struct rx_entry, list);
|
}
|
||||||
list_del(&rx->list);
|
|
||||||
pthread_mutex_unlock(&rxlist_lock);
|
|
||||||
|
|
||||||
pkt = rx->pkt;
|
static int scanner_scan(void *privdata)
|
||||||
free(rx);
|
{
|
||||||
|
plugins_scan();
|
||||||
|
|
||||||
retval = plugins_parse(pkt);
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 10000;
|
||||||
|
|
||||||
switch (retval) {
|
event_add_timeout(&tv, scanner_transmit, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scanner_receive(int fd, void *privdata)
|
||||||
|
{
|
||||||
|
int recvsize;
|
||||||
|
if (ioctl(fd, FIONREAD, &recvsize) == -1) {
|
||||||
|
log_print(LOG_WARN, "scanner_receive(): ioctl(FIONREAD)");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct net_pkt *pkt = malloc(sizeof(struct net_pkt) + recvsize);
|
||||||
|
if (pkt == NULL) {
|
||||||
|
log_print(LOG_WARN, "scanner_receive(): out of memory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = sizeof(struct sockaddr_in);
|
||||||
|
pkt->size = recvfrom(fd, pkt->buf, recvsize, 0, (struct sockaddr *)&pkt->addr, &i);
|
||||||
|
|
||||||
|
if (pkt->size < 0) {
|
||||||
|
log_print(LOG_WARN, "scanner_receive(): recvfrom()");
|
||||||
|
free(pkt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (plugins_parse(pkt)) {
|
||||||
case PARSE_REJECT:
|
case PARSE_REJECT:
|
||||||
log_print("scan_receive(): unknown packet: %s:%d size:%d",
|
log_print(LOG_INFO, "scanner_receive(): unknown packet: %s:%d size:%d",
|
||||||
inet_ntoa(pkt->addr.sin_addr),
|
inet_ntoa(pkt->addr.sin_addr),
|
||||||
ntohs(pkt->addr.sin_port),
|
ntohs(pkt->addr.sin_port),
|
||||||
pkt->size);
|
pkt->size);
|
||||||
#if 0
|
|
||||||
{
|
|
||||||
char *p = pkt_print(pkt);
|
|
||||||
log_print("%s", p);
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case PARSE_ACCEPT:
|
case PARSE_ACCEPT:
|
||||||
free(pkt);
|
free(pkt);
|
||||||
|
@ -234,168 +124,50 @@ void scan_receive_real(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sem_getvalue(&rxlist_sem, &cnt);
|
|
||||||
} while (cnt > 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* scan_control()
|
|
||||||
* triggert den gc der plugins
|
|
||||||
* triggert den serverlist_refresh
|
|
||||||
* triggert den scan der plugins
|
|
||||||
* arbeitet die rx queue ab
|
|
||||||
*/
|
|
||||||
void scan_control(void)
|
|
||||||
{
|
|
||||||
long last_plugin_gc = 0, last_list_refresh = 0, last_scan = 0;
|
|
||||||
int plugin_timeout, list_timeout, list_refresh, scan_interval;
|
|
||||||
int cnt;
|
|
||||||
long now;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
now = time(NULL);
|
|
||||||
|
|
||||||
/* interne plugin daten aufraeumen */
|
|
||||||
if (last_plugin_gc + plugin_timeout < now) {
|
|
||||||
last_plugin_gc = now;
|
|
||||||
plugins_gc(plugin_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* empfangene daten parsen */
|
|
||||||
sem_getvalue(&rxlist_sem, &cnt);
|
|
||||||
if (cnt > 0)
|
|
||||||
scan_receive_real();
|
|
||||||
|
|
||||||
usleep(500000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* scan_receive()
|
|
||||||
* wartet auf serverantworten und uebergibt die pakete der
|
|
||||||
* receive queue
|
|
||||||
*/
|
|
||||||
void scan_receive(void)
|
|
||||||
{
|
|
||||||
struct net_pkt *pkt;
|
|
||||||
struct rx_entry *rx;
|
|
||||||
fd_set fdsel, fdcpy;
|
|
||||||
int recvsize, i;
|
|
||||||
|
|
||||||
log_print("thread_start: scan_receiver");
|
|
||||||
|
|
||||||
FD_ZERO(&fdsel);
|
|
||||||
FD_SET(scan_sock, &fdsel);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
memcpy(&fdcpy, &fdsel, sizeof(fdsel));
|
|
||||||
select(FD_SETSIZE, &fdcpy, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (ioctl(scan_sock, FIONREAD, &recvsize) == -1) {
|
|
||||||
log_print("scan_receive(): ioctl()");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pkt = malloc(sizeof(struct net_pkt) + recvsize))) {
|
|
||||||
log_print("scan_receive(): malloc()");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = sizeof(struct sockaddr_in);
|
|
||||||
pkt->size = recvfrom(scan_sock, pkt->buf, recvsize, 0, (struct sockaddr *)&pkt->addr, &i);
|
|
||||||
|
|
||||||
if (pkt->size == 0) {
|
|
||||||
free(pkt);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
rx = malloc(sizeof(struct rx_entry));
|
|
||||||
rx->pkt = pkt;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&rxlist_lock);
|
|
||||||
list_add_tail(&rx->list, &rxlist);
|
|
||||||
pthread_mutex_unlock(&rxlist_lock);
|
|
||||||
|
|
||||||
sem_post(&rxlist_sem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* schliesst den server scan socket
|
|
||||||
*/
|
|
||||||
static void scan_close()
|
|
||||||
{
|
|
||||||
close(scan_sock);
|
|
||||||
sem_destroy(&rxlist_sem);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* scan_init()
|
|
||||||
* initialisiert den socket fuer den server scan
|
|
||||||
* initialisiert die rxlist semaphore
|
|
||||||
*
|
|
||||||
* @return false on error
|
|
||||||
*/
|
|
||||||
int scan_init()
|
|
||||||
{
|
|
||||||
struct sockaddr_in dst;
|
|
||||||
int i = 1, port;
|
|
||||||
char *ip;
|
|
||||||
|
|
||||||
if ((scan_sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
||||||
log_print("scan_init(): socket()");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ip = config_get_string("global", "scan_ip", "0.0.0.0");
|
int scanner_init()
|
||||||
port = config_get_int("global", "scan_port", 7130);
|
{
|
||||||
|
scan_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (scan_sock < 0) {
|
||||||
|
log_print(LOG_ERROR, "scan_init(): socket()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
dst.sin_family = AF_INET;
|
struct sockaddr_in src;
|
||||||
dst.sin_port = htons(port);
|
char *addr = config_get_string("global", "scanner_src", "0.0.0.0:7130");
|
||||||
inet_aton(ip, &dst.sin_addr);
|
if (parse_saddr(addr, &src) != 0) {
|
||||||
|
log_print(LOG_ERROR, "server_init(): invalid scanner_src '%s'", addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (bind(scan_sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) {
|
if (bind(scan_sock, (struct sockaddr *)&src, sizeof(src)) < 0) {
|
||||||
log_print("scan_init(): bind()");
|
log_print(LOG_ERROR, "scan_init(): bind()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int j = 1;
|
||||||
|
if (setsockopt(scan_sock, SOL_SOCKET, SO_BROADCAST, &j, sizeof(j))) {
|
||||||
|
log_print(LOG_ERROR, "scan_init(): setsockopt(SO_BROADCAST)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rxsize = 1<<20;
|
||||||
|
if (setsockopt(scan_sock, SOL_SOCKET, SO_RCVBUF, &rxsize, sizeof(rxsize))) {
|
||||||
|
log_print(LOG_ERROR, "scan_init(): setsockopt(SO_RCVBUF)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_add_readfd(scan_sock, scanner_receive, NULL);
|
||||||
|
log_print(LOG_INFO, "scan socket initialized (%s:%d)", inet_ntoa(src.sin_addr), ntohs(src.sin_port));
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = config_get_int("global", "scan_interval", 60);
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
event_add_timeout(&tv, scanner_scan, NULL);
|
||||||
|
|
||||||
|
scanner_scan(NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsockopt(scan_sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i))) {
|
|
||||||
log_print("scan_init(): setsockopt()");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atexit(scan_close) != 0) {
|
|
||||||
log_print("scan_init(): atexit()");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_print("scan socket initialized (%s:%d)", ip, port);
|
|
||||||
|
|
||||||
sem_init(&rxlist_sem, 0, 0);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef _SCANNER_H_
|
||||||
|
#define _SCANNER_H_
|
||||||
|
|
||||||
|
int pkt_send(struct in_addr *dstip, unsigned int dstport, char *buf, unsigned int size);
|
||||||
|
int scanner_init();
|
||||||
|
|
||||||
|
#endif /* _SCANNER_H_ */
|
|
@ -0,0 +1,138 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 11/2006 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 "configfile.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "event.h"
|
||||||
|
#include "scanner.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "netpkt.h"
|
||||||
|
#include "gamelist.h"
|
||||||
|
|
||||||
|
#define HLSW_HEADER "\xFF\xFF\xFF\xFFHLSWLANSEARCH\x00"
|
||||||
|
#define HLSW_HEADER_LEN 0x12
|
||||||
|
#define HLSW_ENTRY_LEN 10
|
||||||
|
#define MAX_PKT_LEN (HLSW_HEADER_LEN + HLSW_ENTRY_LEN * 140)
|
||||||
|
|
||||||
|
static LIST_HEAD(master_pkt_list);
|
||||||
|
|
||||||
|
static int serverlist_add_game(struct game_entry *entry)
|
||||||
|
{
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
struct net_pkt *pkt;
|
||||||
|
list_for_each_entry(pkt, &master_pkt_list, list) {
|
||||||
|
if (pkt->size <= (MAX_PKT_LEN - HLSW_ENTRY_LEN)) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
pkt = malloc(sizeof(struct net_pkt) + MAX_PKT_LEN);
|
||||||
|
if (pkt == NULL) {
|
||||||
|
log_print(LOG_WARN, "serverlist_add_game(): out of memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pkt->buf, HLSW_HEADER, HLSW_HEADER_LEN);
|
||||||
|
pkt->size = HLSW_HEADER_LEN;
|
||||||
|
list_add(&pkt->list, &master_pkt_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy((void *)&pkt->buf + pkt->size, &entry->gameid, HLSW_ENTRY_LEN);
|
||||||
|
pkt->size += HLSW_ENTRY_LEN;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int serverlist_refresh(void *privdata)
|
||||||
|
{
|
||||||
|
int timeout = (int)privdata;
|
||||||
|
|
||||||
|
struct net_pkt *pkt, *tmp;
|
||||||
|
list_for_each_entry_safe(pkt, tmp, &master_pkt_list, list) {
|
||||||
|
list_del(&pkt->list);
|
||||||
|
free(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
gamelist_gc_and_dump(serverlist_add_game, timeout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int server_handler(int fd, void *privdata)
|
||||||
|
{
|
||||||
|
struct sockaddr_in client;
|
||||||
|
unsigned char buf[32];
|
||||||
|
|
||||||
|
int i = sizeof(client);
|
||||||
|
int ret = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&client, &i);
|
||||||
|
if (ret <= 0) {
|
||||||
|
log_print(LOG_WARN, "server_handler(): recvfrom()");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(buf, HLSW_HEADER, HLSW_HEADER_LEN))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
struct net_pkt *pkt;
|
||||||
|
list_for_each_entry(pkt, &master_pkt_list, list)
|
||||||
|
sendto(fd, pkt->buf, pkt->size, 0, (struct sockaddr *)&client, sizeof(client));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int server_init()
|
||||||
|
{
|
||||||
|
int sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
log_print(LOG_ERROR, "server_init(): socket()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in src;
|
||||||
|
char *addr = config_get_string("global", "master_src", "0.0.0.0:7140");
|
||||||
|
if (parse_saddr(addr, &src) != 0) {
|
||||||
|
log_print(LOG_ERROR, "server_init(): invalid master_src '%s'", addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(sock, (struct sockaddr *)&src, sizeof(src)) < 0) {
|
||||||
|
log_print(LOG_ERROR, "server_init(): bind()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_add_readfd(sock, server_handler, NULL);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = config_get_int("global", "serverlist_refresh", 5);
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
int timeout = config_get_int("global", "serverlist_timeout", 180);
|
||||||
|
event_add_timeout(&tv, serverlist_refresh, (void *)timeout);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue