commit
ba91546d88
29 changed files with 1799 additions and 0 deletions
@ -0,0 +1,22 @@
|
||||
CFLAGS := -O2 -pipe -Wall -Wunused -Wno-deprecated
|
||||
LIBS := -lpthread
|
||||
|
||||
SRC := $(wildcard *.cpp)
|
||||
OBJS := $(SRC:.cpp=.o)
|
||||
DEPS := $(SRC:.cpp=.d)
|
||||
|
||||
all: hlswmaster |
||||
|
||||
hlswmaster: $(OBJS) |
||||
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@
|
||||
|
||||
%.o: %.cpp |
||||
$(CXX) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.d: %.cpp |
||||
$(CXX) $(CFLAGS) -MM -c $< -o $@
|
||||
|
||||
clean: |
||||
rm -f hlswmaster *.d *.o *.log
|
||||
|
||||
-include $(DEPS) |
@ -0,0 +1,197 @@
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#include "config.h" |
||||
#include "logging.h" |
||||
|
||||
/* ------ */ |
||||
|
||||
Config::Tupel::Tupel(const char* name_, const char* value_) |
||||
{ |
||||
name = strdup(name_); |
||||
value = strdup(value_); |
||||
} |
||||
|
||||
Config::Tupel::~Tupel() |
||||
{ |
||||
free(name); |
||||
free(value); |
||||
} |
||||
|
||||
/* ------ */ |
||||
|
||||
Config::Section::Section(const char* name_) |
||||
{ |
||||
name = strdup(name_); |
||||
} |
||||
|
||||
Config::Section::~Section() |
||||
{ |
||||
while (!tupelList.isEmpty()) |
||||
delete tupelList.get(); |
||||
|
||||
free(name); |
||||
} |
||||
|
||||
bool Config::Section::addTupel(const char* name, const char* value) |
||||
{ |
||||
if (!name || !value) |
||||
return false; |
||||
|
||||
Tupel* t = new Tupel(name, value); |
||||
tupelList.addTail(t); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void Config::Section::show() const |
||||
{ |
||||
Iterator<Tupel>* it = tupelList.createIterator(); |
||||
LogSystem::log(LOG_DEBUG, "[%s]", name); |
||||
|
||||
while (it->hasNext()) { |
||||
Tupel* t = it->next(); |
||||
LogSystem::log(LOG_DEBUG, " %s = %s", t->name, t->value); |
||||
} |
||||
|
||||
delete it; |
||||
} |
||||
|
||||
char* Config::Section::getTupelValue(const char* name) const |
||||
{ |
||||
char* retval = 0; |
||||
Iterator<Tupel>* it = this->tupelList.createIterator(); |
||||
while (it->hasNext()) { |
||||
Tupel* t = it->next(); |
||||
if (!strcmp(t->name, name)) { |
||||
retval = t->value; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
delete it; |
||||
return retval; |
||||
} |
||||
|
||||
/* ------ */ |
||||
|
||||
Config::~Config() |
||||
{ |
||||
while (!sectionList.isEmpty()) |
||||
delete sectionList.get(); |
||||
} |
||||
|
||||
Config::Section* Config::addSection(const char* name) |
||||
{ |
||||
Section* s = new Section(name); |
||||
sectionList.addTail(s); |
||||
return s; |
||||
} |
||||
|
||||
bool Config::parseFile(const char* name) |
||||
{ |
||||
Config::Section* section = 0; |
||||
FILE *fz; |
||||
int i = 0; |
||||
char *row, *tok, *tok2; |
||||
bool ret = true; |
||||
|
||||
if (!(row = (char*)malloc(1024))) { |
||||
LogSystem::log(LOG_CRIT, "config_parse(): malloc()"); |
||||
return false; |
||||
} |
||||
|
||||
if (!(fz = fopen(name, "r"))) { |
||||
LogSystem::log(LOG_ERROR, "config_parse(): can not open %s", name); |
||||
return false; |
||||
} |
||||
|
||||
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 = addSection(tok); |
||||
if (!section) { |
||||
LogSystem::log(LOG_WARNING, "config_parse(): invalid section in row %d", i); |
||||
ret = false; |
||||
break; |
||||
} |
||||
continue; |
||||
|
||||
/* option, aber es gab noch keine section */ |
||||
} else if (!section) { |
||||
LogSystem::log(LOG_WARNING, "config_parse(): missing section in row %d", i); |
||||
ret = false; |
||||
break; |
||||
} |
||||
|
||||
/* option */ |
||||
if ((tok = strtok(row, " \n")) && (tok2 = strtok(NULL, " \n"))) { |
||||
if (!section->addTupel(tok, tok2)) |
||||
LogSystem::log(LOG_WARNING, "config_parse(): invalid row %d", i); |
||||
} |
||||
} |
||||
|
||||
fclose(fz); |
||||
free(row); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
void Config::show() const |
||||
{ |
||||
LogSystem::log(LOG_DEBUG, "Config Dump:"); |
||||
Iterator<Section>* it = sectionList.createIterator(); |
||||
while (it->hasNext()) |
||||
it->next()->show(); |
||||
|
||||
delete it; |
||||
} |
||||
|
||||
char* Config::getParameter(const char* section, const char* option) const |
||||
{ |
||||
char* retval = 0; |
||||
|
||||
Iterator<Section>* it = sectionList.createIterator(); |
||||
while (it->hasNext()) { |
||||
Section* s = it->next(); |
||||
if (!strcmp(s->name, section)) { |
||||
retval = s->getTupelValue(option); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
delete it; |
||||
return retval; |
||||
} |
||||
|
||||
char* Config::getString(const char* section, const char* option, char* def) const |
||||
{ |
||||
char* retval = getParameter(section, option); |
||||
if (!retval) { |
||||
LogSystem::log(LOG_NOTICE, |
||||
"Config: [%s:%s] not found => using '%s'", |
||||
section, option, def); |
||||
return def; |
||||
} |
||||
return retval; |
||||
} |
||||
|
||||
int Config::getInteger(const char* section, const char* option, int def) const |
||||
{ |
||||
char* retval = getParameter(section, option); |
||||
if (!retval) { |
||||
LogSystem::log(LOG_NOTICE, |
||||
"Config: [%s:%s] not found => using '%d'", |
||||
section, option, def); |
||||
return def; |
||||
} |
||||
return atoi(retval); |
||||
} |
@ -0,0 +1,47 @@
|
||||
#ifndef _CONFIG_H_ |
||||
#define _CONFIG_H_ |
||||
|
||||
#include "list.h" |
||||
|
||||
class Config { |
||||
public: |
||||
~Config(); |
||||
|
||||
bool parseFile(const char* name); |
||||
void show() const; |
||||
|
||||
char* getParameter(const char* section, const char* name) const; |
||||
char* getString(const char* section, const char* name, char* def) const; |
||||
int getInteger(const char* section, const char* name, int def) const; |
||||
|
||||
private: |
||||
class Tupel { |
||||
public:
|
||||
Tupel(const char* name, const char* value); |
||||
~Tupel(); |
||||
|
||||
char* name; |
||||
char* value; |
||||
}; |
||||
|
||||
class Section { |
||||
public: |
||||
Section(const char* name); |
||||
~Section(); |
||||
|
||||
bool addTupel(const char* name, const char* option); |
||||
char* getTupelValue(const char* name) const; |
||||
void show() const; |
||||
|
||||
char* name; |
||||
|
||||
private: |
||||
List<Tupel> tupelList; |
||||
}; |
||||
|
||||
Section* addSection(const char* name); |
||||
|
||||
List<Section> sectionList; |
||||
}; |
||||
|
||||
#endif // _CONFIG_H_
|
@ -0,0 +1,31 @@
|
||||
#ifndef _GAMELIST_H_ |
||||
#define _GAMELIST_H_ |
||||
|
||||
class GameEntry { |
||||
public: |
||||
GameEntry(); |
||||
~GameEntry(); |
||||
|
||||
protected: |
||||
GameEntry(const GameEntry& ge); |
||||
GameEntry& operator=(const GameEntry& ge); |
||||
|
||||
private: |
||||
struct in_addr addr; |
||||
int port1; |
||||
int port2; |
||||
int gameid; |
||||
}; |
||||
|
||||
|
||||
class GameList { |
||||
public: |
||||
virtual ~GameList() {}; |
||||
|
||||
virtual void cleanup() {}; |
||||
|
||||
protected: |
||||
GameList() {} |
||||
}; |
||||
|
||||
#endif // _GAMELIST_H_
|
@ -0,0 +1,42 @@
|
||||
#include "logging.h" |
||||
#include "netpkt.h" |
||||
#include "gameparser.h" |
||||
|
||||
#define DEFAULT_TIMEOUT 180 |
||||
|
||||
GameParser::GameParser(Config& conf, RecvQueue& rxQueue, ModuleList& modList) |
||||
: rxQueue(rxQueue), modList(modList) |
||||
{ |
||||
int interval = conf.getInteger("global", "game_timeout", DEFAULT_TIMEOUT); |
||||
TimerService::registerTimer(new Timer(new CleanupEvent(this), interval)); |
||||
} |
||||
|
||||
GameParser::~GameParser() |
||||
{ |
||||
} |
||||
|
||||
int GameParser::execute(void* arg) |
||||
{ |
||||
while (1) { |
||||
NetPkt* pkt = rxQueue.getPkt(); |
||||
int ret = modList.parse(pkt, this); |
||||
switch (ret) { |
||||
case PKT_REJECT: |
||||
char buf[64]; |
||||
pkt->show(buf, sizeof(buf)); |
||||
LogSystem::log(LOG_DEBUG, "unknown Packet: %s", buf); |
||||
|
||||
case PKT_ACCEPT: |
||||
delete pkt; |
||||
|
||||
case PKT_ACCEPT_FREED: |
||||
break; |
||||
}
|
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
void GameParser::cleanup() |
||||
{ |
||||
LogSystem::log(LOG_DEBUG, "GameParser::cleanup()"); |
||||
} |
@ -0,0 +1,39 @@
|
||||
#ifndef _GAMEPARSER_H_ |
||||
#define _GAMEPARSER_H_ |
||||
|
||||
#include "gamelist.h" |
||||
#include "thread.h" |
||||
#include "config.h" |
||||
#include "recvqueue.h" |
||||
#include "modulelist.h" |
||||
#include "timerservice.h" |
||||
|
||||
class GameParser : public GameList, public Thread { |
||||
public: |
||||
GameParser(Config& conf, RecvQueue& rxQueue, ModuleList& modlist); |
||||
~GameParser(); |
||||
|
||||
int execute(void* arg); |
||||
|
||||
void cleanup(); |
||||
|
||||
protected: |
||||
GameParser(const GameParser& rp); |
||||
GameParser& operator=(const GameParser& rp); |
||||
|
||||
private: |
||||
class CleanupEvent : public Command { |
||||
public: |
||||
CleanupEvent(GameList* sl) : sl(sl) {} |
||||
~CleanupEvent() {} |
||||
void execute() { sl->cleanup(); } |
||||
|
||||
private: |
||||
GameList* sl;
|
||||
};
|
||||
|
||||
RecvQueue& rxQueue; |
||||
ModuleList& modList; |
||||
}; |
||||
|
||||
#endif // _GAMEPARSER_H_
|
@ -0,0 +1,50 @@
|
||||
#include "logging.h" |
||||
#include "timerservice.h" |
||||
|
||||
#include "gamescanner.h" |
||||
|
||||
#define DEFAULT_INTERVAL 30 |
||||
|
||||
GameScanner::GameScanner(Config& conf, ModuleList& modList) |
||||
: modList(modList) |
||||
{ |
||||
msock = new MultiSock(conf); |
||||
pktCount = new Semaphore(0); |
||||
|
||||
int interval = conf.getInteger("global", "scan_interval", DEFAULT_INTERVAL); |
||||
TimerService::registerTimer(new Timer(new ScanEvent(this), interval)); |
||||
} |
||||
|
||||
GameScanner::~GameScanner() |
||||
{ |
||||
while (!pktList.isEmpty()) |
||||
delete pktList.get(); |
||||
|
||||
delete pktCount; |
||||
delete msock; |
||||
} |
||||
|
||||
int GameScanner::execute(void* arg) |
||||
{ |
||||
while (1) { |
||||
int fd = msock->getRecvSocket(); |
||||
NetPkt* pkt = NetPkt::createFromSocket(fd); |
||||
|
||||
if (pkt != NULL) { |
||||
pktList.addTail(pkt); |
||||
pktCount->post(); |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
void GameScanner::scan() |
||||
{ |
||||
modList.scan(msock); |
||||
} |
||||
|
||||
NetPkt* GameScanner::getPkt() |
||||
{ |
||||
pktCount->wait(); |
||||
return pktList.get(); |
||||
} |
@ -0,0 +1,49 @@
|
||||
#ifndef _GAMESCANNER_H_ |
||||
#define _GAMESCANNER_H_ |
||||
|
||||
#include "recvqueue.h" |
||||
#include "thread.h" |
||||
#include "config.h" |
||||
#include "modulelist.h" |
||||
|
||||
#include "multisock.h" |
||||
#include "semaphore.h" |
||||
#include "list.h" |
||||
#include "netpkt.h" |
||||
|
||||
#include "timerservice.h" |
||||
|
||||
class GameScanner : public RecvQueue, public Thread { |
||||
public: |
||||
GameScanner(Config& conf, ModuleList& modList); |
||||
~GameScanner(); |
||||
|
||||
void scan(); |
||||
|
||||
NetPkt* getPkt(); |
||||
int execute(void* arg); |
||||
|
||||
protected: |
||||
GameScanner(const GameScanner& hs); |
||||
GameScanner& operator=(const GameScanner& hs); |
||||
|
||||
private: |
||||
class ScanEvent : public Command { |
||||
public: |
||||
ScanEvent(GameScanner* gs) : gs(gs) {} |
||||
~ScanEvent() {} |
||||
void execute() { gs->scan(); } |
||||
|
||||
private: |
||||
GameScanner* gs;
|
||||
};
|
||||
|
||||
ModuleList& modList; |
||||
MultiSock* msock; |
||||
Semaphore* pktCount; |
||||
List<NetPkt> pktList; |
||||
}; |
||||
|
||||
|
||||
|
||||
#endif // _SCANNER_H_
|
@ -0,0 +1,16 @@
|
||||
[global] |
||||
# broadcast scan source port (udp) |
||||
scan_port 7130 |
||||
|
||||
# broadcast scan every X seconds |
||||
scan_interval 10 |
||||
|
||||
# server timeout after X seconds |
||||
game_timeout 30 |
||||
|
||||
# master answers with this source IP |
||||
master_ip 0.0.0.0 |
||||
|
||||
# logging |
||||
logfile hlswmaster.log |
||||
logprio 7 |
@ -0,0 +1,106 @@
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <getopt.h> |
||||
|
||||
#include "logging.h" |
||||
#include "config.h" |
||||
#include "gamescanner.h" |
||||
#include "gameparser.h" |
||||
#include "hlswserver.h" |
||||
#include "timerservice.h" |
||||
#include "modulelist.h" |
||||
|
||||
#include "mod_example.h" |
||||
|
||||
#define DEFAULT_CONFIG "hlswmaster.conf" |
||||
#define DEFAULT_LOGFILE "hlswmaster.log" |
||||
|
||||
static struct option opts[] = { |
||||
{"config", 1, 0, 'c'}, |
||||
{"debug", 0, 0, 'd'}, |
||||
{"help", 0, 0, 'h'}, |
||||
{0, 0, 0, 0} |
||||
}; |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
LogSystem::init(LOG_DEBUG, new StdErrLog()); |
||||
|
||||
int arg = 0, code = 0, debug = 0; |
||||
char *configfile = DEFAULT_CONFIG; |
||||
while (code != -1) { |
||||
code = getopt_long(argc, argv, "c:dh", opts, &arg); |
||||
|
||||
switch (code) { |
||||
case 'c': /* config */ |
||||
configfile = optarg; |
||||
break; |
||||
|
||||
case 'd': /* debug */ |
||||
debug = 1; |
||||
break; |
||||
|
||||
case 'h': /* help */ |
||||
printf("Usage: hlsw-master [options]\n" |
||||
"Options: \n" |
||||
" --config -c configfile use this configfile\n" |
||||
" --debug -d do not fork and log to stderr\n" |
||||
" --help -h this help\n" |
||||
"\n"); |
||||
exit(0); |
||||
break; |
||||
|
||||
case '?': /* error */ |
||||
exit(-1); |
||||
break; |
||||
|
||||
default: /* unknown / all options parsed */ |
||||
break; |
||||
} |
||||
} |
||||
|
||||
Config conf; |
||||
conf.parseFile(configfile); |
||||
|
||||
// char* logfile = conf.getString("global", "logfile", DEFAULT_LOGFILE);
|
||||
// int logprio = conf.getInteger("global", "logprio", LOG_NOTICE);
|
||||
// LogSystem::init(logprio, new FileLog(logfile));
|
||||
|
||||
LogSystem::log(LOG_EVERYTIME, "hlswmaster-ng startup"); |
||||
// conf.show();
|
||||
|
||||
ModuleList modList; |
||||
|
||||
GameScanner scanner(conf, modList); |
||||
GameParser parser(conf, scanner, modList); |
||||
HlswServer server(conf, parser); |
||||
|
||||
modList.reg(new ModExample(conf)); |
||||
|
||||
server.start(); |
||||
parser.start(); |
||||
scanner.start(); |
||||
|
||||
while (1) { |
||||
TimerService::checkTimers(); |
||||
usleep(500000); |
||||
|
||||
if (!scanner.isRunning()) { |
||||
LogSystem::log(LOG_CRIT, "Scanner aborted!"); |
||||
break; |
||||
} |
||||
|
||||
if (!parser.isRunning()) { |
||||
LogSystem::log(LOG_CRIT, "RecvParser aborted!"); |
||||
break; |
||||
} |
||||
|
||||
if (!server.isRunning()) { |
||||
LogSystem::log(LOG_CRIT, "HlswServer aborted!"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return -1; |
||||
} |
@ -0,0 +1,78 @@
|
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <sys/socket.h> |
||||
#include <netinet/in.h> |
||||
#include <netinet/ip.h> |
||||
#include <arpa/inet.h> |
||||
|
||||
#include "config.h" |
||||
#include "logging.h" |
||||
#include "hlswserver.h" |
||||
|
||||
#define HLSW_HEADER "\xFF\xFF\xFF\xFFHLSWLANSEARCH\x00" |
||||
#define HLSW_HEADER_LEN 0x12 |
||||
#define HLSW_MASTER_PORT 7140 |
||||
|
||||
HlswServer::HlswServer(Config& conf, GameList& slist) |
||||
{ |
||||
struct sockaddr_in dst; |
||||
char *ip; |
||||
|
||||
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { |
||||
LogSystem::log(LOG_CRIT, "HlswServer(): socket()"); |
||||
return; |
||||
} |
||||
|
||||
ip = conf.getString("global", "master_ip", "0.0.0.0"); |
||||
LogSystem::log(LOG_NOTICE, "HlswServer listen on %s:%d", ip, HLSW_MASTER_PORT); |
||||
|
||||
dst.sin_family = AF_INET; |
||||
dst.sin_port = htons(HLSW_MASTER_PORT); |
||||
inet_aton(ip, &dst.sin_addr); |
||||
|
||||
if (bind(sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) { |
||||
LogSystem::log(LOG_WARNING, "HlswServer(): bind()"); |
||||
return; |
||||
} |
||||
|
||||
out = new HlswPacket(); |
||||
} |
||||
|
||||
HlswServer::~HlswServer() |
||||
{ |
||||
close(sock); |
||||
} |
||||
|
||||
int HlswServer::execute(void* arg) |
||||
{ |
||||
struct sockaddr_in src; |
||||
unsigned char buf[32]; |
||||
socklen_t len; |
||||
int ret; |
||||
|
||||
while (1) { |
||||
/* auf clientanfrage warten */ |
||||
len = sizeof(src); |
||||
ret = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&src, &len); |
||||
if (ret != HLSW_HEADER_LEN) { |
||||
LogSystem::log(LOG_WARNING, "HlswServer: invalid packet"); |
||||
continue; |
||||
} |
||||
|
||||
/* testen ob es sich um ein HLSW anforderung handelt */ |
||||
if (memcmp(buf, HLSW_HEADER, HLSW_HEADER_LEN)) { |
||||
LogSystem::log(LOG_WARNING, "HlswServer: not a hlsw packet"); |
||||
continue; |
||||
} |
||||
|
||||
if (out != NULL && out->count > 0) { |
||||
HlswPacket* pkt; |
||||
for (pkt = out; pkt != NULL; pkt = pkt->next) { |
||||
sendto(sock, pkt->data, pkt->getSize(), 0, |
||||
(struct sockaddr *)&src, sizeof(src)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,46 @@
|
||||
#ifndef _HLSWSERVER_H_ |
||||
#define _HLSWSERVER_H_ |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "thread.h" |
||||
#include "config.h" |
||||
#include "gamelist.h" |
||||
|
||||
|
||||
class HlswServer : public Thread { |
||||
public: |
||||
HlswServer(Config& conf, GameList& slist); |
||||
~HlswServer(); |
||||
|
||||
int execute(void* arg); |
||||
|
||||
protected: |
||||
HlswServer(const HlswServer& hs); |
||||
HlswServer& operator=(const HlswServer& hs); |
||||
|
||||
private: |
||||
class HlswPacket { |
||||
public: |
||||
HlswPacket() : next(0), count(0) |
||||
{ |
||||
memset(data, 0, sizeof(data)); |
||||
} |
||||
|
||||
int getSize() |
||||
{ |
||||
return 12 + count * 10; |
||||
} |
||||
|
||||
void addGame(void* ptr) {} |
||||
|
||||
HlswPacket* next; |
||||
int count; |
||||
char data[1412]; |
||||
}; |
||||
|
||||
HlswPacket* out; |
||||
int sock; |
||||
}; |
||||
|
||||
#endif // _HLSWSERVER_H_
|
@ -0,0 +1,167 @@
|
||||
#ifndef _LIST_H_ |
||||
#define _LIST_H_ |
||||
|
||||
#include "mutex.h" |
||||
|
||||
template <class T> |
||||
class Iterator { |
||||
public: |
||||
virtual ~Iterator() {} |
||||
virtual bool hasNext() const =0; |
||||
virtual T* next() =0; |
||||
|
||||
protected: |
||||
Iterator<T>() {} |
||||
Iterator<T>(const Iterator<T>& it); |
||||
Iterator<T>& operator=(const Iterator<T>& it); |
||||
}; |
||||
|
||||
template <class T> |
||||
class List { |
||||
public: |
||||
List() {} |
||||
|
||||
~List() |
||||
{ |
||||
AutoMutex am(mutex); |
||||
while(!head.isEmpty()) |
||||
head.getNext()->del(); |
||||
} |
||||
|
||||
void add(const T* part) |
||||
{ |
||||
ListEntry<T>* entry = new ListEntry<T>(part); |
||||
|
||||
AutoMutex am(mutex); |
||||
entry->add(&head, head.getNext()); |
||||
} |
||||
|
||||
void addTail(const T* part) |
||||
{ |
||||
ListEntry<T>* entry = new ListEntry<T>(part); |
||||
|
||||
AutoMutex am(mutex); |
||||
entry->add(head.getPrev(), &head); |
||||
} |
||||
|
||||
T* get() |
||||
{ |
||||
AutoMutex am(mutex); |
||||
ListEntry<T>* entry = head.getNext(); |
||||
T* retval = (T*)entry->getPart(); |
||||
|
||||
if (!head.isEmpty()) { |
||||
entry->del(); |
||||
delete entry; |
||||
} |
||||
return retval; |
||||
} |
||||
|
||||
T* getTail() |
||||
{ |
||||
AutoMutex am(mutex); |
||||
ListEntry<T>* entry = head.getPrev(); |
||||
T* retval = (T*)entry->getPart(); |
||||
|
||||
if (!head.isEmpty()) { |
||||
entry->del(); |
||||
delete entry; |
||||
} |
||||
return retval; |
||||
} |
||||
|
||||
bool isEmpty() const |
||||
{ |
||||
AutoMutex am((Mutex&)mutex); |
||||
return head.isEmpty(); |
||||
} |
||||
|
||||
Iterator<T>* createIterator() const |
||||
{ |
||||
return new ListIterator<T>(this); |
||||
} |
||||
|
||||
protected: |
||||
List(const List& l); |
||||
List& operator=(const List& l); |
||||
|
||||
private: |
||||
template <class TT> |
||||
class ListEntry { |
||||
public: |
||||
ListEntry(const TT* part = 0) |
||||
: prev(this), next(this), part(part) |
||||
{ |
||||
} |
||||
|
||||
void add(ListEntry<TT>* prev_, ListEntry<TT>* next_) |
||||
{ |
||||
this->next = next_; |
||||
this->prev = prev_; |
||||
next_->prev = this; |
||||
prev_->next = this; |
||||
} |
||||
|
||||
void del() |
||||
{ |
||||
next->prev = prev; |
||||
prev->next = next; |
||||
next = prev = this; |
||||
} |
||||
|
||||
bool isEmpty() const |
||||
{ |
||||
return (this->prev == this) && (this->next == this); |
||||
} |
||||
|
||||
const TT* getPart() const { return part; } |
||||
ListEntry<TT>* getPrev() const { return prev; } |
||||
ListEntry<TT>* getNext() const { return next; } |
||||
|
||||
private: |
||||
ListEntry<TT>* prev; |
||||
ListEntry<TT>* next; |
||||
const TT* part; |
||||
}; |
||||
|
||||
ListEntry<T> head; |
||||
Mutex mutex; |
||||
|
||||
template <class TT> |
||||
class ListIterator : public Iterator<TT> { |
||||
public: |
||||
ListIterator(const List<TT>* list) |
||||
: list(list) |
||||
{ |
||||
// ((ListBase*)list)->mutex.lock();
|
||||
pos = &list->head; |
||||
} |
||||
|
||||
~ListIterator() |
||||
{ |
||||
// ((ListBase*)list)->mutex.unlock();
|
||||
} |
||||
|
||||
bool hasNext() const |
||||
{ |
||||
return (pos->getNext() != &list->head); |
||||
} |
||||
|
||||
TT* next() |
||||
{ |
||||
pos = pos->getNext(); |
||||
return (TT*)pos->getPart(); |
||||
} |
||||
|
||||
protected: |
||||
ListIterator(const ListIterator& lit); |
||||
ListIterator& operator=(const ListIterator& lit); |
||||
|
||||
private: |
||||
const List<TT>* list; |
||||
const ListEntry<TT>* pos; |
||||
}; |
||||
}; |
||||
|
||||
|
||||
#endif //_LIST_H_
|
@ -0,0 +1,99 @@
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <time.h> |
||||
#include <stdarg.h> |
||||
#include <errno.h> |
||||
#include <string.h> |
||||
|
||||
#include "logging.h" |
||||
|
||||
#define BUFLEN 1024 |
||||
|
||||
|
||||
LogSystem::LogSystem() : output(0), priority(0) |
||||
{ |
||||
buffer = new char[BUFLEN]; |
||||
} |
||||
|
||||
LogSystem::~LogSystem() |
||||
{ |
||||
delete buffer; |
||||
|
||||
if (output) |
||||
delete output; |
||||
} |
||||
|
||||
LogSystem* LogSystem::getInstance() |
||||
{ |
||||
static LogSystem ls; |
||||
return &ls; |
||||
} |
||||
|
||||
void LogSystem::init(int prio, LogOutput* out) |
||||
{ |
||||
LogSystem* ls = getInstance(); |
||||
|
||||
if (ls->output) |
||||
delete ls->output; |
||||
|
||||
ls->output = out; |
||||
ls->priority = prio; |
||||
} |
||||
|
||||
void LogSystem::log(int prio, const char* fmt, ...) |
||||
{ |
||||
LogSystem* ls = getInstance(); |
||||
|
||||
if (prio > ls->priority || !ls->output) |
||||
return; |
||||
|
||||
va_list az; |
||||
int len; |
||||
|
||||
va_start(az, fmt); |
||||
len = vsnprintf(ls->buffer, BUFLEN, fmt, az); |
||||
va_end(az); |
||||
|
||||
if (errno) { |
||||
strncpy(ls->buffer + len, ": ", BUFLEN - len); |
||||
len += 2; |
||||
strncpy(ls->buffer + len, strerror(errno), BUFLEN - len); |
||||
|
||||
errno = 0; |
||||
} |
||||
|
||||
ls->output->write(ls->buffer); |
||||
} |
||||
|
||||
/* ------- */ |
||||
|
||||
void StdErrLog::write(const char* buf) |
||||
{ |
||||
fprintf(stderr, "%s\n", buf); |
||||
} |
||||
|
||||
/* ------- */ |
||||
|
||||
FileLog::FileLog(const char* filename) |
||||
{ |
||||
if (!(logfile = fopen(filename, "a" ))) |
||||
LogSystem::log(LOG_CRIT, "Can not open logfile '%s'", filename); |
||||
|
||||
fprintf(logfile, "-----------------\n"); |
||||
} |
||||
|
||||
FileLog::~FileLog() |
||||
{ |
||||
fclose(logfile); |
||||
} |
||||
|
||||
void FileLog::write(const char* buf) |
||||
{ |
||||
time_t tzgr; |
||||
char tbuf[64]; |
||||
time(&tzgr); |
||||
strftime(tbuf, sizeof(tbuf), "%b %d %H:%M:%S :", localtime(&tzgr)); |
||||
|
||||
fprintf(logfile, "%s %s\n", tbuf, buf); |
||||
fflush(logfile); |
||||
} |
@ -0,0 +1,63 @@
|
||||
#ifndef _LOGGING_H_ |
||||
#define _LOGGING_H_ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
// really noisy debugging (pkt-dumps)
|
||||
#define LOG_DEBUG 5 |
||||
|
||||
// normal "debug" (config, recv. packets)
|
||||
#define LOG_INFO 4 |
||||
|
||||
// interesting stuff
|
||||
#define LOG_NOTICE 3 |
||||
|
||||
// something is not right, but programm is still working (config errors)
|
||||
#define LOG_WARN 2 |
||||
|
||||
// something is *really* bad, but we try to keep up (mem-allocs)
|
||||
#define LOG_ERROR 1 |
||||
|
||||
// we must bailout *now*
|
||||
#define LOG_CRIT 0 |
||||
|
||||
#define LOG_EVERYTIME 0 |
||||
|
||||
class LogOutput { |
||||
public: |
||||
virtual ~LogOutput() {}; |
||||
virtual void write(const char* buf) {}; |
||||
}; |
||||
|
||||
class LogSystem { |
||||
public: |
||||
static void init(int prio, LogOutput* lo); |
||||
static void log(int prio, const char* fmt, ...); |
||||
|
||||
private: |
||||
LogSystem(); |
||||
~LogSystem(); |
||||
static LogSystem* getInstance(); |
||||
|
||||
LogOutput *output; |
||||
int priority; |
||||
char* buffer; |
||||
}; |
||||
|
||||
class StdErrLog : public LogOutput { |
||||
public: |
||||
void write(const char* buf); |
||||
}; |
||||
|
||||
class FileLog : public LogOutput { |
||||
public: |
||||
FileLog(const char* filename); |
||||
~FileLog(); |
||||
|
||||
void write(const char* buf); |
||||
|
||||
private: |
||||
FILE* logfile; |
||||
}; |
||||
|
||||
#endif // _LOGGING_H_
|
@ -0,0 +1,35 @@
|
||||
#ifndef _MODEXAMPLE_H_ |
||||
#define _MODEXAMPLE_H_ |
||||
|
||||
#include "modulelist.h" |
||||
#include "logging.h" |
||||
|
||||
class ModExample : public Module { |
||||
public: |
||||
ModExample(Config& conf) |
||||
{ |
||||
} |
||||
|
||||
~ModExample() |
||||
{ |
||||
} |
||||
|
||||
void scan(MultiSock* msock) |
||||
{ |
||||
LogSystem::log(LOG_DEBUG, "ModExample::scan()"); |
||||
} |
||||
|
||||
int parse(NetPkt* pkt, GameList* slist) |
||||
{ |
||||
LogSystem::log(LOG_DEBUG, "ModExample::parse()"); |
||||
return 0; |
||||
} |
||||
|
||||
char* getName() { |
||||
return "Example Module"; |
||||
} |
||||
|
||||
protected: |
||||
}; |
||||
|
||||
#endif // _MODEXAMPLE_H_
|
@ -0,0 +1,42 @@
|
||||
#include "logging.h" |
||||
#include "modulelist.h" |
||||
|
||||
ModuleList::ModuleList() |
||||
{ |
||||
} |
||||
|
||||
ModuleList::~ModuleList() |
||||
{ |
||||
while (!mlist.isEmpty()) |
||||
delete mlist.get(); |
||||
} |
||||
|
||||
void ModuleList::reg(Module* mod) |
||||
{ |
||||
LogSystem::log(LOG_INFO, "Loading Module '%s'", mod->getName()); |
||||
mlist.addTail(mod); |
||||
} |
||||
|
||||
void ModuleList::scan(MultiSock* msock) |
||||
{ |
||||
Iterator<Module> *it = mlist.createIterator(); |
||||
while (it->hasNext()) |
||||
it->next()->scan(msock); |
||||
|
||||
delete it; |
||||
} |
||||
|
||||
int ModuleList::parse(NetPkt* pkt, GameList* slist) |
||||
{ |
||||
int retval = PKT_REJECT; |
||||
|
||||
Iterator<Module> *it = mlist.createIterator(); |
||||
while (it->hasNext()) { |
||||
retval = it->next()->parse(pkt, slist); |
||||
if (retval != PKT_REJECT) |
||||
break; |
||||
} |
||||
|
||||
delete it; |
||||
return retval; |
||||
} |
@ -0,0 +1,40 @@
|
||||
#ifndef _MODULELIST_H_ |
||||
#define _MODULELIST_H_ |
||||
|
||||
#include "multisock.h" |
||||
#include "netpkt.h" |
||||
#include "gamelist.h" |
||||
#include "config.h" |
||||
|
||||
class Module { |
||||
public: |
||||
virtual ~Module() {}; |
||||
|
||||
virtual void scan(MultiSock* msock) =0; |
||||
virtual int parse(NetPkt* pkt, GameList* slist) =0; |
||||
virtual char* getName() =0; |
||||
|
||||
protected: |
||||
Module() {}; |
||||
}; |
||||
|
||||
|
||||
class ModuleList { |
||||
public: |
||||
ModuleList(); |
||||
~ModuleList(); |
||||
|
||||
void reg(Module* mod); |
||||
|
||||
void scan(MultiSock* msock); |
||||
int parse(NetPkt* pkt, GameList* slist); |
||||
|
||||
protected: |
||||
ModuleList(const ModuleList& ml); |
||||
ModuleList& operator=(const ModuleList& ml); |
||||
|
||||
private: |
||||
List<Module> mlist; |
||||
}; |
||||
|
||||
#endif // _MODULELIST_H_
|
@ -0,0 +1,187 @@
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/ioctl.h> |
||||
#include <net/if.h> |
||||
#include <netinet/in.h> |
||||
#include <arpa/inet.h> |
||||
|
||||
#include "logging.h" |
||||
#include "multisock.h" |
||||
|
||||
#define DEFAULT_PORT 7130 |
||||
|
||||
#define DEVFILE "/proc/net/dev" |
||||
#define BUFSIZE 256 |
||||
|
||||
|
||||
MultiSock::Socket::Socket() |
||||
{ |
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) |
||||
LogSystem::log(LOG_CRIT, "Socket: socket()"); |
||||
} |
||||
|
||||
MultiSock::Socket::~Socket() |
||||
{ |
||||
close(fd); |
||||
} |
||||
|
||||
bool MultiSock::Socket::bindToDevice(const char* name) |
||||
{ |
||||
strncpy(devname, name, sizeof(devname)); |
||||
|
||||
int ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, devname, sizeof(devname)); |
||||
|
||||
if (ret < 0) { |
||||
LogSystem::log(LOG_WARNING, "Socket: setsockopt(SO_BINDTODEVICE) %s", devname); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool MultiSock::Socket::bindToPort(int port) |
||||
{ |
||||
struct ifreq ifr; |
||||
|
||||
strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name)); |
||||
|
||||
if (ioctl(fd, SIOCGIFADDR, &ifr) != 0) { |
||||
LogSystem::log(LOG_WARNING, "Socket: ioctl(SIOCGIFADDR) %s", devname); |
||||
return false; |
||||
} |
||||
|
||||
memcpy(&addr, &ifr.ifr_addr, sizeof(addr)); |
||||
addr.sin_port = htons(port); |
||||
|
||||
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { |
||||
LogSystem::log(LOG_WARNING, "Socket: bind() %s", devname); |
||||
return false; |
||||
} |
||||
|
||||
int bcast = 1; |
||||
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast))) { |
||||
LogSystem::log(LOG_WARNING, "Socket: setsockopt(SO_BROADCAST) %s", devname); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
int MultiSock::Socket::show(char* buf, int size) |
||||
{ |
||||
return snprintf(buf, size, "%s (%s:%d) ", devname, |
||||
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); |
||||
} |
||||
|
||||
MultiSock::Socket* MultiSock::Socket::createSocket(const char* name, int port) |
||||
{ |
||||
Socket* sock = new Socket(); |
||||
|
||||
if (sock->fd < 0) { |
||||
delete sock; |
||||
return NULL; |
||||
} |
||||
|
||||
struct ifreq ifr; |
||||
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); |
||||
|
||||
if (ioctl(sock->fd, SIOCGIFFLAGS, &ifr) != 0) { |
||||
LogSystem::log(LOG_WARNING, "Socket: ioctl(SIOCGIFFLAGS) %s", name); |
||||
delete sock; |
||||
return NULL; |
||||
} |
||||
|
||||
if (!(ifr.ifr_flags & IFF_UP) || (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) { |
||||
delete sock; |
||||
return NULL; |
||||
} |
||||
|
||||
sock->bindToDevice(name); |
||||
|
||||
if (!sock->bindToPort(port)) { |
||||
delete sock; |
||||
return NULL; |
||||
} |
||||
|
||||
return sock; |
||||
} |
||||
|
||||
|
||||
MultiSock::MultiSock(Config& conf) |
||||
{ |
||||
char* buf = (char*)malloc(BUFSIZE); |
||||
if (buf == NULL) { |
||||
LogSystem::log(LOG_CRIT, "MultiSock(): out of memory"); |
||||
return; |
||||
} |
||||
|
||||
FILE* fp = fopen(DEVFILE, "r"); |
||||
if (fp == NULL) { |
||||
LogSystem::log(LOG_CRIT, "MultiSock(): can not open " DEVFILE); |
||||
free(buf); |
||||
return; |
||||
} |
||||
|
||||
fgets(buf, BUFSIZE, fp); |
||||
fgets(buf, BUFSIZE, fp); |
||||
|
||||
int port = conf.getInteger("global", "scan_port", DEFAULT_PORT); |
||||
FD_ZERO(&fdsel); |
||||
|
||||
while (fgets(buf, BUFSIZE, fp) != NULL) { |
||||
char* tok = strtok(buf, " :"); |
||||
|
||||
// TODO: check against config list
|
||||
|
||||
Socket* sock = Socket::createSocket(tok, port); |
||||
if (sock) { |
||||
FD_SET(sock->getFD(), &fdsel); |
||||
|
||||
sock->show(buf, BUFSIZE); |
||||
LogSystem::log(LOG_NOTICE, "adding Interface %s", buf); |
||||
|
||||
ifaceList.add(sock); |
||||
} |
||||
} |
||||
|
||||
fclose(fp); |
||||
free(buf); |
||||
} |
||||
|
||||
MultiSock::~MultiSock() |
||||
{ |
||||
while (!ifaceList.isEmpty()) |
||||
delete ifaceList.get(); |
||||
} |
||||
|
||||
|
||||
int MultiSock::getRecvSocket() |
||||
{ |
||||
fd_set fdcpy; |
||||
|
||||
while (1) { |
||||
memcpy(&fdcpy, &fdsel, sizeof(fdcpy)); |
||||
|
||||
select(FD_SETSIZE, &fdcpy, NULL, NULL, NULL); |
||||
|
||||
Iterator<Socket>* it = ifaceList.createIterator(); |
||||
while (it->hasNext()) { |
||||
Socket* sock = it->next(); |
||||
if (FD_ISSET(sock->getFD(), &fdcpy)) { |
||||
delete it; |
||||
return sock->getFD(); |
||||
} |
||||
} |
||||
delete it; |
||||
|
||||
LogSystem::log(LOG_ERROR, "getRecvSocket(): select()"); |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
@ -0,0 +1,53 @@
|
||||
#ifndef _MULTISOCK_H_ |
||||
#define _MULTISOCK_H_ |
||||
|
||||
#include <net/if.h> |
||||
#include <netinet/in.h> |
||||
|
||||
#include "list.h" |
||||
#include "config.h" |
||||
|
||||
class MultiSock { |
||||
public: |
||||
MultiSock(Config& conf); |
||||
~MultiSock(); |
||||
|
||||
int send(struct in_addr *dstip, int dport, char* data, int size); |
||||
int getRecvSocket(); |
||||
|
||||
protected: |
||||
MultiSock(const MultiSock& x); |
||||
MultiSock& operator=(const MultiSock& x); |
||||
|
||||
private: |
||||
class Socket { |
||||
public: |
||||
static Socket* createSocket(const char* name, int port); |
||||
int show(char* buf, int size); |
||||
|
||||
int getFD() { return fd; } |
||||
|
||||
~Socket(); |
||||
|
||||
protected: |
||||
Socket(const Socket& s); |
||||
Socket& operator=(const Socket& s); |
||||
|
||||
private: |
||||
Socket(); |
||||
|
||||
bool bindToDevice(const char* name); |
||||
bool bindToPort(int port); |
||||
|
||||
int fd; |
||||
char devname[IFNAMSIZ]; |
||||
struct sockaddr_in addr; |
||||
}; |
||||
|
||||
void addIface(const char* name, int port); |
||||
|
||||
List<Socket> ifaceList; |
||||
fd_set fdsel; |
||||
}; |
||||
|
||||
#endif // _MULTISOCK_H_
|
@ -0,0 +1,35 @@
|
||||
#ifndef _MUTEX_H_ |
||||
#define _MUTEX_H_ |
||||
|
||||
#include <pthread.h> |
||||
|
||||
class Mutex { |
||||
public: |
||||
Mutex() { pthread_mutex_init(&m, 0); } |
||||
~Mutex() { pthread_mutex_destroy(&m); } |
||||
void lock() { pthread_mutex_lock(&m); } |
||||
void unlock() { pthread_mutex_unlock(&m); } |
||||
|
||||
protected: |
||||
Mutex(const Mutex& m); |
||||
Mutex& operator=(const Mutex& m); |
||||
|
||||
private: |
||||
pthread_mutex_t m; |
||||
}; |
||||
|
||||
|
||||
class AutoMutex { |
||||
public: |
||||