Version 0.10

This commit is contained in:
Olaf Rempel 2006-02-02 16:24:06 +01:00
commit c4d38c9cd0
14 changed files with 1214 additions and 0 deletions

29
Makefile Normal file
View File

@ -0,0 +1,29 @@
# Toplevel Makefile
MASTER_SRC := src/client.c src/daemon.c src/logging.c src/main.c src/plugin.c src/plugin_helper.c src/scanner.c src/serverlist.c
PLUGIN_SRC := plugins/quake3.c
CFLAGS := -Wall -I. -I./include -g -fPIC
DEPFILES := $(PLUGIN_SRC:%.c=%.d) $(MASTER_SRC:%.c=%.d)
# ############################
all: $(DEPFILES) $(PLUGIN_SRC:%.c=%.so) src/hlswmaster
src/hlswmaster: $(MASTER_SRC:%.c=%.o)
gcc -ldl -lpthread -rdynamic $^ -o $@
%.d: %.c
@-$(CC) -M -MG $(CFLAGS) $< > $@
%.o: %.c %.d
$(CC) $(CFLAGS) -o $@ -c $<
%.so: %.o
$(LD) -shared -o $@ $<
clean:
rm -rf src/hlswmaster src/*.o plugins/*.so plugins/*.o $(DEPFILES)
-include $(DEPFILES)

48
include/hlswmaster.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef _HLSWMASTER_H
#define _HLSWMASTER_H
#include "list.h"
#include "netpkt.h"
struct game_server {
/* must be first */
struct list_head list;
u_int16_t gameid;
u_int32_t ip;
u_int16_t port1;
u_int16_t port2;
unsigned long modtime;
};
/* daemon.c */
void daemonize(char *pw_name);
/* logging.c */
void log_open(char *logfile);
void log_close();
void log_print(const char *fmt, ... );
/* plugin.c */
int plugin_load(char *name);
int plugin_unload(char *name);
int plugins_scan(void);
int plugins_parse(struct net_pkt *pkt);
int plugins_gc(unsigned long timeout);
/* scanner.c */
int scan_init(void);
void scan_exit(void);
void scan_transmit(void);
void scan_receive(void);
/* serverlist.c */
void server_collector(void);
/* client.c */
int client_pkt_add(struct game_server *server);
int client_pkt_commit(void);
void client_handler(void);
#endif

267
include/list.h Normal file
View File

@ -0,0 +1,267 @@
#ifndef _LIST_H
#define _LIST_H
/*
** stolen from linux kernel (2.6.11)
** linux/include/linux/stddef.h (offsetoff)
** linux/include/linux/kernel.h (container_of)
** linux/include/linux/list.h (*list*)
** linux/include/linux/netfilter_ipv4/listhelp.h (LIST_FIND)
**
** modified by Olaf Rempel
*/
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/**
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = NULL;
entry->prev = NULL;
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_move - delete from one list and add as another's head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del(list->prev, list->next);
list_add(list, head);
}
/**
* list_move_tail - delete from one list and add as another's tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
list_add_tail(list, head);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}
/**
* list_splice_init - join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head);
INIT_LIST_HEAD(list);
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); pos = pos->prev)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif
/* Return pointer to first true entry, if any, or NULL. A macro
required to allow inlining of cmpfn. */
#define LIST_FIND(head, cmpfn, type, args...) \
({ \
const struct list_head *__i, *__j = NULL; \
\
list_for_each(__i, (head)) \
if (cmpfn((const type)__i , ## args)) { \
__j = __i; \
break; \
} \
(type)__j; \
})

20
include/netpkt.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _NETPKT_H
#define _NETPKT_H
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include "list.h"
struct net_pkt {
/* must be first */
struct list_head list;
struct sockaddr_in addr;
unsigned int size;
unsigned char buf[0];
};
#endif

31
include/plugin.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef _PLUGIN_H
#define _PLUGIN_H
#include "netpkt.h"
#include "list.h"
extern void pkt_queue(struct net_pkt *pkt);
extern int server_add(unsigned int gameid, struct in_addr ip, u_int16_t port1, u_int16_t port2);
extern struct net_pkt * pkt_factory(char *dstip, unsigned int dstport, char *buf, unsigned int size);
extern int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size);
extern int pkt_strcmp(struct net_pkt *pkt, unsigned int offset, char *search);
struct hlswmaster_plugin {
/* must be first */
struct list_head list;
char name[32];
int (*init)(struct list_head *config);
int (*fini)(void);
int (*scan)(void);
int (*parse)(struct net_pkt *pkt);
int (*gc)(int timeout);
};
extern void register_plugin(struct hlswmaster_plugin *me);
extern void unregister_plugin(struct hlswmaster_plugin *me);
#endif

49
plugins/quake3.c Normal file
View File

@ -0,0 +1,49 @@
#include "plugin.h"
#define GAMEID_Q3 0x0006
int scan(void) {
struct net_pkt *scan;
unsigned int port;
char msg[] = "\xff\xff\xff\xffgetstatus";
for (port = 27960; port <= 27963; port++) {
if (!(scan = pkt_factory(NULL, port, msg, 13)))
return 0;
pkt_queue(scan);
}
return 1;
}
int parse(struct net_pkt *pkt) {
if (!pkt_strcmp(pkt, 0, "\xff\xff\xff\xffstatusResponse")) {
server_add(GAMEID_Q3, pkt->addr.sin_addr, pkt->addr.sin_port, 0);
return 1;
}
return 0;
}
int init(struct list_head *config) {
return 1;
}
int fini(void) {
return 1;
}
static struct hlswmaster_plugin quake3_plugin = {
.name = "quake3",
.init = &init,
.fini = &fini,
.scan = &scan,
.parse = &parse,
};
void _init(void) {
register_plugin(&quake3_plugin);
}
void _fini(void) {
unregister_plugin(&quake3_plugin);
}

197
src/client.c Normal file
View File

@ -0,0 +1,197 @@
/***************************************************************************
* 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 "plugin.h"
#include "list.h"
#define HLSW_HEADER "\xFF\xFF\xFF\xFFHLSWLANSEARCH\x00"
#define HLSW_HEADER_LEN 0x12
#define MAX_PKT_LEN (1400 + HLSW_HEADER_LEN)
struct client_pkt {
struct list_head list;
unsigned int size;
unsigned char buf[0];
};
/* real und prepare list. enthalten die client-antworten */
LIST_HEAD(client_pkt_list);
LIST_HEAD(client_pkt_prepare);
/* sichert die real list ab */
static pthread_mutex_t pkt_list_lock = PTHREAD_MUTEX_INITIALIZER;
/**
* pkt_not_full()
* LIST_FIND helper
*
* @param struct client_pkt *a
* @param void *b
* @return true wenn das paket noch nicht voll ist
*/
static inline int pkt_not_full(const struct client_pkt *a, void *b) {
return (a->size < MAX_PKT_LEN);
}
/**
* client_pkt_add_real()
* erzeugt eine neues client_pkt und fuegt es einer liste hinzu
* gibt einen pointer auf das neue client_pkt zurueck
*
* @param struct list_head *list
* @return struct client_pkt * or NULL on error
*/
static struct client_pkt * client_pkt_add_real(struct list_head *list) {
struct client_pkt *new;
if (!(new = malloc(sizeof(struct client_pkt) + MAX_PKT_LEN)))
return NULL;
INIT_LIST_HEAD(&new->list);
new->size = HLSW_HEADER_LEN;
memcpy(new->buf, HLSW_HEADER, HLSW_HEADER_LEN);
list_add_tail(&new->list, list);
return new;
}
/**
* client_pkt_add()
* fuegt dem freien client_pkt der prepare-liste ein Spiel hinzu
* wenn kein platz vorhanden ist, wird ein neues paket erzeugt
*
* @param struct game_server *server
* @return false bei fehler (malloc)
*
* TODO: memcpy() durch pointer ops ersetzen?
*/
int client_pkt_add(struct game_server *server) {
struct client_pkt *pkt;
char *src, *dst;
pkt = LIST_FIND(&client_pkt_prepare, pkt_not_full, struct client_pkt *, NULL);
if (!pkt && !(pkt = client_pkt_add_real(&client_pkt_prepare)))
return 0;
dst = (char *)&pkt->buf + pkt->size;
src = (char *)&server->gameid;
memcpy(dst, src, 2);
src = (char *)&server->ip;
memcpy(dst +2, src, 4);
src = (char *)&server->port1;
memcpy(dst +6, src, 4);
src = (char *)&server->port2;
memcpy(dst +8, src, 4);
pkt->size += 10;
return 1;
}
/**
* client_pkt_commit()
*
* die prepare liste die echte liste und alle pakete der
* alten liste werden entfernt
*
* @return true
*/
int client_pkt_commit() {
struct list_head old_list, *pkt, *tmp;
pthread_mutex_lock(&pkt_list_lock);
/* old_list wird head der real 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(&pkt_list_lock);
/* alle alten pakete entfernen */
list_for_each_safe(pkt, tmp, &old_list) {
list_del(pkt);
free(pkt);
}
return 1;
}
/**
* client_handler()
* empfaengt und beantwortet die HLSW Anfragen
*
* TODO: src-ip configurierbar machen (config file?)
*/
void client_handler(void) {
struct client_pkt *pkt;
struct sockaddr_in dst;
int sock, i;
unsigned char buf[32];
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
log_print("client_handler(): socket()");
return;
}
dst.sin_family = AF_INET;
dst.sin_port = htons(7140);
inet_aton("0.0.0.0", &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(&pkt_list_lock);
/* unsere vorbereiteten pakete ausgeben */
list_for_each_entry(pkt, &client_pkt_list, list)
sendto(sock, pkt->buf, pkt->size, 0, (struct sockaddr *)&dst, sizeof(dst));
pthread_mutex_unlock(&pkt_list_lock);
}
}

50
src/daemon.c Normal file
View File

@ -0,0 +1,50 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <pwd.h>
#include "hlswmaster.h"
void daemonize(char *pw_name) {
int fail = 0;
pid_t pid;
struct passwd *pwl;
if ((pid = fork()) < 0) {
log_print("daemonize(): fork()");
exit(-1);
} else if (pid != 0) {
exit(0);
} else {
/* Kindprozess weiterlaufen lassen */
if (setsid() == -1) {
log_print("daemonize: setsid()");
exit(-1);
}
umask(0) ;
if (pw_name != NULL) {
if((pwl = getpwnam(pw_name)) == NULL) {
log_print("mkdaemon(): getpwnam(\"%s\")", pw_name);
exit(-1);
}
if (setgid(pwl->pw_gid) != 0) {
log_print("mkdaemon(): setgid()");
fail = 1;
}
if (setuid(pwl->pw_uid) != 0) {
log_print("mkdaemon(): setuid()");
fail = 1;
}
if (fail == 0) {
log_print("user changed to: %s, pid: %d", pw_name, getpid());
}
}
}
}

53
src/logging.c Normal file
View File

@ -0,0 +1,53 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
static FILE *log_fd = NULL;
void log_close() {
fclose(log_fd);
}
void log_open(char *logfile) {
if ((log_fd = fopen(logfile, "a" )) == NULL) {
fprintf(stderr, "log_open(\"%s\"): %s\n", logfile, strerror(errno));
exit(-1);
}
if (atexit(log_close) != 0) {
fprintf(stderr, "log_open(): atexit(): %s\n", strerror(errno));
exit(-1);
}
}
void log_print(const char *fmt, ...) {
va_list az;
time_t tzgr;
char tbuf[64];
char buffer[256];
va_start(az, fmt);
vsprintf(buffer, fmt, az);
va_end(az);
time(&tzgr);
strftime(tbuf, 64, "%b %d %H:%M:%S :", localtime(&tzgr));
if (log_fd) {
if (errno) {
fprintf(log_fd, "%s %s: %s\n", tbuf, buffer, strerror(errno));
} else {
fprintf(log_fd, "%s %s\n", tbuf, buffer);
}
} else {
if (errno) {
fprintf(stderr, "%s %s: %s\n", tbuf, buffer, strerror(errno));
} else {
fprintf(stderr, "%s %s\n", tbuf, buffer);
}
}
errno = 0;
fflush(log_fd);
}

77
src/main.c Normal file
View File

@ -0,0 +1,77 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <getopt.h>
#include "hlswmaster.h"
static struct option opts[] = {
{"config", 1, 0, 'c'},
{"user", 1, 0, 'u'},
{"debug", 1, 0, 'd'},
{"no-daemon", 0, 0, 'f'},
{"help", 0, 0, 'h'},
{0, 0, 0, 0}
};
int main(int argc, char *argv[]) {
int arg = 0, code = 0;
pthread_t thread1, thread2, thread3, thread4;
while (code != -1) {
code = getopt_long(argc, argv, "c:u:d:fh", opts, &arg);
switch (code) {
case 'c': /* config */
break;
case 'u': /* user */
break;
case 'd': /* debug */
break;
case 'f': /* no-daemon */
break;
case 'h': /* help */
printf("Usage: hlsw-master [options]\n"
"Options: \n"
" --config -c configfile use this configfile\n"
" --user -u username change uid to username\n"
" --debug -d debuglevel level: 0 - 7\n"
" --no-daemon -f do not fork\n"
" --help -h this help\n"
"\n");
exit(0);
break;
case '?': /* error */
exit(-1);
break;
default: /* unknown / all options parsed */
break;
}
}
plugin_load("plugins/quake3.so");
scan_init();
pthread_create(&thread1, NULL, (void *)&scan_transmit, NULL);
pthread_create(&thread2, NULL, (void *)&scan_receive, NULL);
pthread_create(&thread3, NULL, (void *)&server_collector, NULL);
pthread_create(&thread4, NULL, (void *)&client_handler, NULL);
sleep(9999);
scan_exit();
return 0;
}

104
src/plugin.c Normal file
View File

@ -0,0 +1,104 @@
/***************************************************************************
* 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 <stdlib.h>
#include <dlfcn.h>
#include <pthread.h>
#include "hlswmaster.h"
#include "plugin.h"
#include "netpkt.h"
#include "list.h"
/* liste der geladenen plugins */
LIST_HEAD(plugin_list);
/* sichert die plugin list UND die plugins ab */
static pthread_mutex_t plugin_lock = PTHREAD_MUTEX_INITIALIZER;
int plugin_load(char *name) {
void *tmp;
if (!(tmp = dlopen(name, RTLD_NOW)))
log_print("unable to load plugin '%s'", name);
return 0;
}
int plugin_unload(char *name) {
return 0;
}
int plugins_scan(void) {
struct hlswmaster_plugin *plugin;
pthread_mutex_lock(&plugin_lock);
list_for_each_entry(plugin, &plugin_list, list)
if (plugin->scan && !plugin->scan())
log_print("plugin %s: scan error", plugin->name);
pthread_mutex_unlock(&plugin_lock);
return 1;
}
int plugins_parse(struct net_pkt *pkt) {
struct hlswmaster_plugin *plugin;
pthread_mutex_lock(&plugin_lock);
list_for_each_entry(plugin, &plugin_list, list) {
if (plugin->parse && plugin->parse(pkt)) {
pthread_mutex_unlock(&plugin_lock);
return 1;
}
}
pthread_mutex_unlock(&plugin_lock);
return 0;
}
int plugins_gc(unsigned long timeout) {
struct hlswmaster_plugin *plugin;
pthread_mutex_lock(&plugin_lock);
list_for_each_entry(plugin, &plugin_list, list)
if (plugin->gc)
plugin->gc(timeout);
pthread_mutex_unlock(&plugin_lock);
return 1;
}
/* called vom plugin:_init() after local init */
void register_plugin(struct hlswmaster_plugin *me) {
if (!me->init || (me->init(NULL))) {
pthread_mutex_lock(&plugin_lock);
list_add((struct list_head *)me, &plugin_list);
pthread_mutex_unlock(&plugin_lock);
}
}
/* called vom plugin:_fini() after local finish */
void unregister_plugin(struct hlswmaster_plugin *me) {
pthread_mutex_lock(&plugin_lock);
list_del((struct list_head *)me);
pthread_mutex_unlock(&plugin_lock);
if (me->fini)
me->fini();
}

48
src/plugin_helper.c Normal file
View File

@ -0,0 +1,48 @@
#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 "plugin.h"
#include "netpkt.h"
struct net_pkt * pkt_factory(char *dstip, unsigned int dstport, char *buf, unsigned int size) {
struct net_pkt *pkt;
if (!(pkt = malloc(sizeof(struct net_pkt) + size)))
return NULL;
INIT_LIST_HEAD(&pkt->list);
pkt->addr.sin_family = AF_INET;
pkt->addr.sin_port = htons(dstport);
if (dstip)
inet_aton(dstip, &pkt->addr.sin_addr);
else
inet_aton("255.255.255.255", &pkt->addr.sin_addr);
pkt->size = size;
memcpy(pkt->buf, buf, size);
return pkt;
}
int pkt_memcmp(struct net_pkt *pkt, unsigned int offset, char *search, unsigned int size) {
if (offset >= pkt->size)
return 1;
if (offset + size >= pkt->size)
size = pkt->size - offset;
return memcmp(pkt->buf, search, size);
}
int pkt_strcmp(struct net_pkt *pkt, unsigned int offset, char *search) {
return pkt_memcmp(pkt, offset, search, strlen(search));
}

119
src/scanner.c Normal file
View File

@ -0,0 +1,119 @@
/***************************************************************************
* 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 <sys/ioctl.h>
#include <pthread.h>
#include "list.h"
#include "netpkt.h"
#include "hlswmaster.h"
LIST_HEAD(send_queue);
static int scan_sock;
void pkt_queue(struct net_pkt *pkt) {
list_add_tail(&pkt->list, &send_queue);
}
void scan_transmit(void) {
struct net_pkt *pkt, *tmp;
while (1) {
plugins_scan();
list_for_each_entry_safe(pkt, tmp, &send_queue, list) {
if (sendto(scan_sock, pkt->buf, pkt->size, 0, (struct sockaddr *)&pkt->addr, sizeof(pkt->addr)) < 0)
log_print("scan_transmit(): sendto()");
list_del(&pkt->list);
free(pkt);
}
sleep(30);
}
}
void scan_receive(void) {
struct net_pkt *pkt;
fd_set fdsel, fdcpy;
int recvsize, i;
FD_ZERO(&fdsel);
FD_SET(scan_sock, &fdsel);
while (1) {
memcpy(&fdcpy, &fdsel, sizeof(fdsel));
select(FD_SETSIZE, &fdcpy, NULL, NULL, NULL);
ioctl(scan_sock, FIONREAD, &recvsize);
if (recvsize <= 0)
continue;
if (!(pkt = malloc(sizeof(struct net_pkt) + recvsize)))
continue;
i = sizeof(struct sockaddr_in);
pkt->size = recvfrom(scan_sock, pkt->buf, recvsize, 0, (struct sockaddr *)&pkt->addr, &i);
if (!plugins_parse(pkt))
log_print("received unknown packet\n");
free(pkt);
}
}
int scan_init() {
struct sockaddr_in dst;
int i;
if ((scan_sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
log_print("scan_init(): socket()");
return 0;
}
dst.sin_family = AF_INET;
dst.sin_port = htons(7130);
inet_aton("0.0.0.0", &dst.sin_addr);
if (bind(scan_sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) {
log_print("scan_init(): bind()");
return 0;
}
if (setsockopt(scan_sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i))) {
log_print("scan_init(): setsockopt()");
return 0;
}
return 1;
}
void scan_exit() {
close(scan_sock);
}

122
src/serverlist.c Normal file
View File

@ -0,0 +1,122 @@
/***************************************************************************
* Copyright (C) 03/2005 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
#include <pthread.h>
#include "hlswmaster.h"
#include "plugin.h"
#include "list.h"
LIST_HEAD(server_list);
/* sichert die server liste */
static pthread_mutex_t server_list_lock = PTHREAD_MUTEX_INITIALIZER;
/**
* server_cmp()
* LIST_FIND helper
*
* @param struct game_server *a
* @param struct game_server *b
* @return true wenn es sich um den selben server handelt
*/
static inline int server_cmp(const struct game_server *a, struct game_server *b) {
return (a->gameid == b->gameid && a->ip == b->ip &&
a->port1 == b->port1 && a->port2 == b->port2);
}
/**
* server_add()
* fuegt der internen serverliste einen server hinzu
* wenn dieser server schon in der liste vorhanden ist, wird nur
* die modtime angepasst
*
* @param unsigned int gameid
* @param struct in_addr ip
* @param u_int16_t port1
* @param u_int16_t port2
* @return false bei fehler
*/
int server_add(unsigned int gameid, struct in_addr ip, u_int16_t port1, u_int16_t port2) {
struct game_server server, *nserver;
server.gameid = gameid;
server.ip = ip.s_addr;
server.port1 = ntohs(port1);
server.port2 = ntohs(port2);
pthread_mutex_lock(&server_list_lock);
/* diesen server in der liste suchen */
nserver = LIST_FIND(&server_list, server_cmp, struct game_server *, &server);
if (!nserver) {
/* neuen eintrag anlegen */
if (!(nserver = malloc(sizeof(struct game_server)))) {
pthread_mutex_unlock(&server_list_lock);
return 0;
}
memcpy(nserver, &server, sizeof(struct game_server));
list_add_tail(&nserver->list, &server_list);
}
/* modtime anpassen */
nserver->modtime = time(NULL);
pthread_mutex_unlock(&server_list_lock);
return 1;
}
/**
* server_collector()
* loescht alte server aus der liste
* baut aus den verbleibenden die client_liste auf
*
* TODO: timeout und intervall als config parameter (config file?)
*/
void server_collector(void) {
struct game_server *server, *tmp;
unsigned long now, timeout = 120;
while (1) {
sleep(5);
now = time(NULL);
pthread_mutex_lock(&server_list_lock);
list_for_each_entry_safe(server, tmp, &server_list, list) {
if (server->modtime + timeout < now) {
list_del(&server->list);
free(server);
continue;
}
client_pkt_add(server);
}
pthread_mutex_unlock(&server_list_lock);
client_pkt_commit();
}
}