Initial Commit
This commit is contained in:
commit
ba91546d88
|
@ -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:
|
||||||
|
AutoMutex(Mutex& x) : m(x) { m.lock(); }
|
||||||
|
~AutoMutex() { m.unlock(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AutoMutex(const AutoMutex& am);
|
||||||
|
AutoMutex& operator=(const AutoMutex& am);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Mutex& m;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_MUTEX_H_
|
|
@ -0,0 +1,55 @@
|
||||||
|
#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 "netpkt.h"
|
||||||
|
|
||||||
|
NetPkt::NetPkt(int size)
|
||||||
|
:size(size)
|
||||||
|
{
|
||||||
|
LogSystem::log(LOG_DEBUG, "NetPkt()");
|
||||||
|
data = (char*)malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetPkt::~NetPkt()
|
||||||
|
{
|
||||||
|
free(data);
|
||||||
|
LogSystem::log(LOG_DEBUG, "~NetPkt()");
|
||||||
|
}
|
||||||
|
|
||||||
|
int NetPkt::readFromSocket(int fd)
|
||||||
|
{
|
||||||
|
socklen_t i = sizeof(struct sockaddr_in);
|
||||||
|
return recvfrom(fd, this->data, this->size, 0, (struct sockaddr *)&this->addr, &i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int NetPkt::show(char* buf, int size)
|
||||||
|
{
|
||||||
|
return snprintf(buf, size, "(%s:%d) %d bytes",
|
||||||
|
inet_ntoa(this->addr.sin_addr),
|
||||||
|
ntohs(this->addr.sin_port),
|
||||||
|
this->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetPkt* NetPkt::createFromSocket(int fd)
|
||||||
|
{
|
||||||
|
int recvsize = 0;
|
||||||
|
|
||||||
|
if (ioctl(fd, FIONREAD, &recvsize) == -1) {
|
||||||
|
LogSystem::log(LOG_WARNING, "NetPkt::createFromSocket()");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetPkt* retval = new NetPkt(recvsize);
|
||||||
|
retval->readFromSocket(fd);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef _NETPKT_H_
|
||||||
|
#define _NETPKT_H_
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#define PKT_ACCEPT 1
|
||||||
|
#define PKT_ACCEPT_FREED 2
|
||||||
|
#define PKT_REJECT 4
|
||||||
|
|
||||||
|
class NetPkt {
|
||||||
|
public:
|
||||||
|
~NetPkt();
|
||||||
|
|
||||||
|
static NetPkt* createFromSocket(int fd);
|
||||||
|
NetPkt* append(NetPkt* pkt);
|
||||||
|
int show(char* buf, int size);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
NetPkt(const NetPkt& x);
|
||||||
|
NetPkt& operator=(const NetPkt& x);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NetPkt(int size);
|
||||||
|
int readFromSocket(int fd);
|
||||||
|
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int size;
|
||||||
|
char *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _NETPKT_H_
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef _RECVQUEUE_H_
|
||||||
|
#define _RECVQUEUE_H_
|
||||||
|
|
||||||
|
#include "netpkt.h"
|
||||||
|
|
||||||
|
class RecvQueue {
|
||||||
|
public:
|
||||||
|
virtual ~RecvQueue() {};
|
||||||
|
virtual NetPkt* getPkt() =0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RecvQueue() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _RECVQUEUE_H_
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef _SEMAPHORE_H_
|
||||||
|
#define _SEMAPHORE_H_
|
||||||
|
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
class Semaphore {
|
||||||
|
public:
|
||||||
|
Semaphore(int i) { sem_init(&s, 0, i); }
|
||||||
|
~Semaphore() { sem_destroy(&s); }
|
||||||
|
void wait() { sem_wait(&s); }
|
||||||
|
void post() { sem_post(&s); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Semaphore(const Semaphore& s);
|
||||||
|
Semaphore& operator=(const Semaphore& s);
|
||||||
|
|
||||||
|
private:
|
||||||
|
sem_t s;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_SEMAPHORE_H_
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
#define THREAD_STACKSIZE 65536
|
||||||
|
|
||||||
|
#define THREAD_READY 0x01
|
||||||
|
#define THREAD_RUNNING 0x02
|
||||||
|
#define THREAD_ENDED 0x03
|
||||||
|
|
||||||
|
|
||||||
|
Thread::Thread()
|
||||||
|
: arg(0), tid(0), state(THREAD_READY)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Thread::~Thread()
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case THREAD_RUNNING:
|
||||||
|
cancel();
|
||||||
|
|
||||||
|
case THREAD_ENDED:
|
||||||
|
join();
|
||||||
|
|
||||||
|
case THREAD_READY:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Thread::start(void* arg_)
|
||||||
|
{
|
||||||
|
pthread_attr_t attr;
|
||||||
|
|
||||||
|
if (state != THREAD_READY)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
arg = arg_;
|
||||||
|
state = THREAD_RUNNING;
|
||||||
|
|
||||||
|
pthread_attr_init(&attr);
|
||||||
|
pthread_attr_setstacksize(&attr, THREAD_STACKSIZE);
|
||||||
|
|
||||||
|
if (pthread_create(&tid, &attr, (Thread::entry), this) != 0) {
|
||||||
|
state = THREAD_READY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::cancel()
|
||||||
|
{
|
||||||
|
pthread_cancel(tid);
|
||||||
|
state = THREAD_ENDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Thread::isRunning() const
|
||||||
|
{
|
||||||
|
return (state == THREAD_RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Thread::join()
|
||||||
|
{
|
||||||
|
void* retval;
|
||||||
|
pthread_join(tid, &retval);
|
||||||
|
state = THREAD_READY;
|
||||||
|
|
||||||
|
return (int)retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Thread::entry(void* myself)
|
||||||
|
{
|
||||||
|
Thread* thread = (Thread*)myself;
|
||||||
|
|
||||||
|
int retval = thread->execute(thread->arg);
|
||||||
|
thread->state = THREAD_ENDED;
|
||||||
|
|
||||||
|
return (void*)retval;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef _THREAD_H_
|
||||||
|
#define _THREAD_H_
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
class Thread {
|
||||||
|
public:
|
||||||
|
Thread();
|
||||||
|
virtual ~Thread();
|
||||||
|
|
||||||
|
virtual int execute(void* arg) =0;
|
||||||
|
|
||||||
|
int start(void* arg = 0);
|
||||||
|
void cancel();
|
||||||
|
int join();
|
||||||
|
bool isRunning() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Thread(const Thread& t);
|
||||||
|
Thread& operator=(const Thread& t);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* arg;
|
||||||
|
pthread_t tid;
|
||||||
|
volatile int state;
|
||||||
|
|
||||||
|
static void* entry(void* myself);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _THREAD_H_
|
|
@ -0,0 +1,71 @@
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "timerservice.h"
|
||||||
|
|
||||||
|
Timer::Timer(Command* cmd, unsigned int timeval)
|
||||||
|
: next(0), cmd(cmd), timeval(timeval)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer::~Timer()
|
||||||
|
{
|
||||||
|
delete cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimerService::~TimerService()
|
||||||
|
{
|
||||||
|
Timer* search = firstTimer;
|
||||||
|
while (search != NULL) {
|
||||||
|
Timer* next = search->next;
|
||||||
|
delete search;
|
||||||
|
search = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimerService::addTimer(Timer* te, bool trigger)
|
||||||
|
{
|
||||||
|
te->timeout = time(NULL) + ((!trigger) ? te->timeval : 0);
|
||||||
|
|
||||||
|
Timer** search = &firstTimer;
|
||||||
|
while ((*search) != NULL && (*search)->timeout <= te->timeout)
|
||||||
|
search = &((*search)->next);
|
||||||
|
|
||||||
|
te->next = (*search);
|
||||||
|
(*search) = te;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimerService::checkTimeouts()
|
||||||
|
{
|
||||||
|
long now = time(NULL);
|
||||||
|
Timer* search = firstTimer;
|
||||||
|
while (search != NULL && search->timeout <= now) {
|
||||||
|
search->cmd->execute();
|
||||||
|
|
||||||
|
firstTimer = search->next;
|
||||||
|
addTimer(search, false);
|
||||||
|
|
||||||
|
search = firstTimer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TimerService* TimerService::getInstance()
|
||||||
|
{
|
||||||
|
static TimerService ts;
|
||||||
|
return &ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimerService::registerTimer(Timer* te)
|
||||||
|
{
|
||||||
|
TimerService* ts = getInstance();
|
||||||
|
|
||||||
|
AutoMutex am(ts->mutex);
|
||||||
|
ts->addTimer(te, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimerService::checkTimers()
|
||||||
|
{
|
||||||
|
TimerService* ts = getInstance();
|
||||||
|
|
||||||
|
AutoMutex am(ts->mutex);
|
||||||
|
ts->checkTimeouts();
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef _TIMERSERVICE_H_
|
||||||
|
#define _TIMERSERVICE_H_
|
||||||
|
|
||||||
|
#include "mutex.h"
|
||||||
|
|
||||||
|
class Command {
|
||||||
|
public:
|
||||||
|
virtual ~Command() {};
|
||||||
|
virtual void execute() =0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Command() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Timer {
|
||||||
|
friend class TimerService;
|
||||||
|
public:
|
||||||
|
Timer(Command* cmd, unsigned int timeval);
|
||||||
|
~Timer();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Timer(const Timer& te);
|
||||||
|
Timer& operator=(const Timer& te);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Timer* next;
|
||||||
|
Command* cmd;
|
||||||
|
int timeval;
|
||||||
|
long timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TimerService {
|
||||||
|
public:
|
||||||
|
static void registerTimer(Timer* te);
|
||||||
|
static void checkTimers();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TimerService(const TimerService& ts);
|
||||||
|
TimerService& operator=(const TimerService& ts);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimerService() {}
|
||||||
|
~TimerService();
|
||||||
|
|
||||||
|
static TimerService* getInstance();
|
||||||
|
|
||||||
|
void addTimer(Timer* te, bool trigger);
|
||||||
|
void checkTimeouts();
|
||||||
|
|
||||||
|
Timer* firstTimer;
|
||||||
|
Mutex mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _TIMERSERVICE_H_
|
Loading…
Reference in New Issue