get it working

This commit is contained in:
Olaf Rempel 2006-04-15 19:55:07 +02:00
parent c4df94c900
commit 17f64ec0f9
25 changed files with 519 additions and 423 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@
hlswmaster hlswmaster
hlswmaster.log hlswmaster.log
doc/* doc/*
masterquery
hlswmaster-ng.tar.gz

View File

@ -1,8 +1,9 @@
CFLAGS := -O2 -pipe -Wall -Wunused -Wno-deprecated CFLAGS := -O2 -pipe -Wall
CXXFLAGS := -O2 -pipe -Wall -Wunused -Wno-deprecated
LIBS := -lpthread LIBS := -lpthread
HLSWMASTER_SRC := config.o gameentry.o gamelist.o gameparser.o gamescanner.o \ HLSWMASTER_SRC := config.o gameentry.o gamelist.o gameparser.o gamescanner.o \
hlswmaster.o hlswserver.o list.o logging.o modhelper.o modulelist.o \ hlswmaster.o hlswserver.o logging.o modhelper.o modulelist.o \
multisock.o netpkt.o recvqueue.o socket.o timerservice.o thread.o \ multisock.o netpkt.o recvqueue.o socket.o timerservice.o thread.o \
mod_d3engine.o mod_gamespy1.o mod_gamespy2.o mod_halflife.o \ mod_d3engine.o mod_gamespy1.o mod_gamespy2.o mod_halflife.o \
mod_hlswproxy.o mod_q3engine.o mod_quake2.o mod_ut.o mod_hlswproxy.o mod_q3engine.o mod_quake2.o mod_ut.o
@ -10,22 +11,29 @@ HLSWMASTER_SRC := config.o gameentry.o gamelist.o gameparser.o gamescanner.o \
all: hlswmaster masterquery all: hlswmaster masterquery
hlswmaster: $(HLSWMASTER_SRC) hlswmaster.o hlswmaster: $(HLSWMASTER_SRC) hlswmaster.o
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ $(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@
masterquery: masterquery.o masterquery: masterquery.o
$(CC) $(CFLAGS) $^ $(LIBS) -o $@ $(CC) $(CFLAGS) $^ $(LIBS) -o $@
%.o: %.cpp %.o: %.cpp
$(CXX) $(CFLAGS) -c $< -o $@ $(CXX) $(CXXFLAGS) -c $< -o $@
%.d: %.cpp %.d: %.cpp
$(CXX) $(CFLAGS) -MM -c $< -o $@ $(CXX) $(CXXFLAGS) -MM -c $< -o $@
dist: dist: clean
git-tar-tree HEAD hlswmaster-ng | gzip -9 -c > hlswmaster-ng.tar.gz ln -s . hlswmaster-ng
tar -czhf hlswmaster-ng.tar.gz hlswmaster-ng/ \
--exclude hlswmaster-ng/.git \
--exclude hlswmaster-ng/.gitignore \
--exclude hlswmaster-ng/hlswmaster-ng.tar.gz \
--exclude hlswmaster-ng/hlswmaster-ng
rm hlswmaster-ng
clean: clean:
rm -f hlswmaster masterquery *.d *.o *.log rm -f hlswmaster masterquery *.d *.o *.log \
hlswmaster-ng hlswmaster-ng.tar.gz
##DEPS := $(wildcard *.cpp) ##DEPS := $(wildcard *.cpp)
##-include $(DEPS:.cpp=.d) ##-include $(DEPS:.cpp=.d)

View File

@ -42,12 +42,12 @@ bool Config::Section::addTupel(const char* name, const char* value)
return false; return false;
Tupel* t = new Tupel(name, value); Tupel* t = new Tupel(name, value);
tupelList.addTail(t); tupelList.add(t);
return true; return true;
} }
void Config::Section::show() const void Config::Section::show()
{ {
Iterator<Tupel>* it = tupelList.createIterator(); Iterator<Tupel>* it = tupelList.createIterator();
LogSystem::log(LOG_INFO, "[%s]", name); LogSystem::log(LOG_INFO, "[%s]", name);
@ -60,7 +60,7 @@ void Config::Section::show() const
delete it; delete it;
} }
const char* Config::Section::getTupelValue(const char* name) const const char* Config::Section::getTupelValue(const char* name)
{ {
const char* retval = 0; const char* retval = 0;
Iterator<Tupel>* it = this->tupelList.createIterator(); Iterator<Tupel>* it = this->tupelList.createIterator();
@ -121,7 +121,7 @@ Config::~Config()
Config::Section* Config::addSection(const char* name) Config::Section* Config::addSection(const char* name)
{ {
Section* s = new Section(name); Section* s = new Section(name);
sectionList.addTail(s); sectionList.add(s);
return s; return s;
} }
@ -184,7 +184,7 @@ bool Config::parseFile(const char* name)
return ret; return ret;
} }
void Config::show() const void Config::show()
{ {
LogSystem::log(LOG_INFO, "Config Dump:"); LogSystem::log(LOG_INFO, "Config Dump:");
Iterator<Section>* it = sectionList.createIterator(); Iterator<Section>* it = sectionList.createIterator();
@ -194,7 +194,7 @@ void Config::show() const
delete it; delete it;
} }
Config::Section* Config::getSection(const char* name) const Config::Section* Config::getSection(const char* name)
{ {
Section* retval = 0; Section* retval = 0;
@ -211,13 +211,13 @@ Config::Section* Config::getSection(const char* name) const
return retval; return retval;
} }
const char* Config::getParameter(const char* section, const char* option) const const char* Config::getParameter(const char* section, const char* option)
{ {
Section* s = getSection(section); Section* s = getSection(section);
return s ? s->getTupelValue(option) : 0; return s ? s->getTupelValue(option) : 0;
} }
const char* Config::getString(const char* section, const char* option, char* def) const const char* Config::getString(const char* section, const char* option, char* def)
{ {
const char* retval = getParameter(section, option); const char* retval = getParameter(section, option);
if (!retval) { if (!retval) {
@ -229,7 +229,7 @@ const char* Config::getString(const char* section, const char* option, char* def
return retval; return retval;
} }
int Config::getInteger(const char* section, const char* option, int def) const int Config::getInteger(const char* section, const char* option, int def)
{ {
const char* retval = getParameter(section, option); const char* retval = getParameter(section, option);
if (!retval) { if (!retval) {

View File

@ -8,16 +8,16 @@ public:
~Config(); ~Config();
bool parseFile(const char* name); bool parseFile(const char* name);
void show() const; void show();
const char* getParameter(const char* section, const char* name) const; const char* getParameter(const char* section, const char* name);
const char* getString(const char* section, const char* name, char* def) const; const char* getString(const char* section, const char* name, char* def);
int getInteger(const char* section, const char* name, int def) const; int getInteger(const char* section, const char* name, int def);
Iterator<char>* createIterator(const char* section, const char* name); Iterator<char>* createIterator(const char* section, const char* name);
private: private:
class Tupel { class Tupel : private ListEntry<Tupel> {
public: public:
Tupel(const char* name, const char* value); Tupel(const char* name, const char* value);
~Tupel(); ~Tupel();
@ -26,7 +26,7 @@ private:
const char* value; const char* value;
}; };
class Section { class Section : private ListEntry<Section> {
public: public:
class SectionIterator : public Iterator<char> { class SectionIterator : public Iterator<char> {
public: public:
@ -47,8 +47,8 @@ private:
~Section(); ~Section();
bool addTupel(const char* name, const char* option); bool addTupel(const char* name, const char* option);
const char* getTupelValue(const char* name) const; const char* getTupelValue(const char* name);
void show() const; void show();
const char* name; const char* name;
@ -56,7 +56,7 @@ private:
}; };
Section* addSection(const char* name); Section* addSection(const char* name);
Section* getSection(const char* name) const; Section* getSection(const char* name);
List<Section> sectionList; List<Section> sectionList;
}; };

View File

@ -1,5 +1,24 @@
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "gameentry.h" #include "gameentry.h"
GameEntry::GameEntry(int gameid, NetPkt* pkt, int port2)
: port2(port2), gameid(gameid)
{
memcpy(&addr, &pkt->getAddress()->sin_addr, sizeof(addr));
this->port1 = pkt->getPort();
if (port2 != 0) {
this->port2 = this->port1;
this->port1 = port2;
}
update();
}
int GameEntry::compare(const GameEntry* ge) int GameEntry::compare(const GameEntry* ge)
{ {
if (this->addr.s_addr > ge->addr.s_addr) if (this->addr.s_addr > ge->addr.s_addr)
@ -14,5 +33,36 @@ int GameEntry::compare(const GameEntry* ge)
if (this->port1 < ge->port1) if (this->port1 < ge->port1)
return 1; return 1;
// only compare IP:port
// gameid and port2 are useless
return 0; return 0;
} }
int GameEntry::hash(int max)
{
unsigned int hash = 0x12345678;
// IP
hash = ((hash<<5) ^ (hash>>27)) ^ ((addr.s_addr>>0) & 0xFF);
hash = ((hash<<5) ^ (hash>>27)) ^ ((addr.s_addr>>8) & 0xFF);
hash = ((hash<<5) ^ (hash>>27)) ^ ((addr.s_addr>>16) & 0xFF);
hash = ((hash<<5) ^ (hash>>27)) ^ ((addr.s_addr>>24) & 0xFF);
// port
hash = ((hash<<5) ^ (hash>>27)) ^ ((port1>>0) & 0xFF);
hash = ((hash<<5) ^ (hash>>27)) ^ ((port1>>8) & 0xFF);
return hash % max;
}
void GameEntry::update()
{
modtime = time(NULL);
}
int GameEntry::show(char* buf, int size)
{
return snprintf(buf, size, "(%2d:%15s:%5d:%5d)",
this->gameid, inet_ntoa(this->addr),
this->port1, this->port2);
}

View File

@ -4,12 +4,18 @@
#include <net/if.h> #include <net/if.h>
#include <netinet/in.h> #include <netinet/in.h>
class GameEntry { #include "netpkt.h"
class GameEntry : private ListEntry<GameEntry> {
public: public:
GameEntry() {}; GameEntry(int gameid, NetPkt* pkt, int port2);
~GameEntry() {}; ~GameEntry() {}
int compare(const GameEntry* ge); int compare(const GameEntry* ge);
int hash(int max);
void update();
int show(char* buf, int size);
struct in_addr addr; struct in_addr addr;
int port1; int port1;

View File

@ -3,43 +3,123 @@
#define DEFAULT_TIMEOUT 180 #define DEFAULT_TIMEOUT 180
/*
** TODO: replace list with sorted list, or even better with a hash
*/
GameList::GameList(Config& conf) GameList::GameList(Config& conf)
: lastUpdate(0)
{ {
int interval = conf.getInteger("global", "game_timeout", DEFAULT_TIMEOUT); timeout = conf.getInteger("global", "game_timeout", DEFAULT_TIMEOUT);
TimerService::registerTimer(new Timer(new CleanupEvent(*this), interval)); TimerService::registerTimer(new Timer(new CleanupEvent(*this), timeout));
} }
GameList::~GameList() GameList::~GameList()
{ {
while (!glist.isEmpty()) Iterator<GameEntry>* it = createIterator();
delete glist.get(); while (it->hasNext())
delete it->next();
delete it;
} }
void GameList::cleanup() void GameList::cleanup()
{ {
long now = time(NULL);
Iterator<GameEntry>* it = createIterator();
while (it->hasNext()) {
GameEntry* ge = it->next();
if (ge->modtime + timeout <= now) {
it->remove();
char buf[64];
ge->show(buf, sizeof(buf));
LogSystem::log(LOG_NOTICE, "Game Timeout: %s", buf);
delete ge;
}
}
delete it;
} }
long GameList::getLastUpdate() void GameList::addGame(int gameid, NetPkt* pkt, int port2)
{ {
return lastUpdate; GameEntry* ge = new GameEntry(gameid, pkt, port2);
int hash = ge->hash(MAX_BUCKETS);
bool found = false;
Iterator<GameEntry>* it = buckets[hash].createIterator();
while (it->hasNext()) {
GameEntry* tmp = it->next();
if (ge->compare(tmp) == 0) {
tmp->update();
found = true;
break;
}
}
if (!found) {
char buf[64];
ge->show(buf, sizeof(buf));
LogSystem::log(LOG_NOTICE, "Adding Game : %s", buf);
buckets[hash].add(ge);
} else {
delete ge;
}
// it holds the lock!
delete it;
} }
Iterator<GameEntry>* GameList::createIterator() Iterator<GameEntry>* GameList::createIterator()
{ {
return glist.createIterator(); return new GameListIterator(this);
} }
void GameList::addGame(int gameid, NetPkt* pkt, int port2, bool swap)
GameList::GameListIterator::GameListIterator(GameList* gl)
: gl(gl), it(0)
{ {
char buf[64]; gl->mutex.lock();
pkt->show(buf, sizeof(buf)); reset();
LogSystem::log(LOG_NOTICE, "Adding Game %d: %s", gameid, buf); }
glist.add(new GameEntry()); GameList::GameListIterator::~GameListIterator()
lastUpdate++; {
delete it;
gl->mutex.unlock();
}
bool GameList::GameListIterator::hasNext()
{
if (it->hasNext())
return true;
while (bucket < MAX_BUCKETS -1) {
delete it;
bucket++;
it = gl->buckets[bucket].createIterator();
if (it->hasNext())
return true;
}
return false;
}
GameEntry* GameList::GameListIterator::next()
{
return it->next();
}
void GameList::GameListIterator::remove()
{
it->remove();
}
void GameList::GameListIterator::reset()
{
if (it != NULL)
delete it;
bucket = 0;
it = gl->buckets[bucket].createIterator();
} }

View File

@ -6,18 +6,19 @@
#include "gameentry.h" #include "gameentry.h"
#include "timerservice.h" #include "timerservice.h"
#include "list.h" #include "list.h"
#include "mutex.h"
// 127 is prime!
#define MAX_BUCKETS 127
class GameList { class GameList {
public: public:
GameList(Config& conf); GameList(Config& conf);
~GameList(); ~GameList();
void addGame(int gameid, NetPkt* pkt, int port2 = 0, bool swap = false);
long getLastUpdate();
Iterator<GameEntry>* createIterator();
void cleanup(); void cleanup();
void addGame(int gameid, NetPkt* pkt, int port2 = 0);
Iterator<GameEntry>* createIterator();
protected: protected:
GameList(const GameList& gl); GameList(const GameList& gl);
@ -34,8 +35,26 @@ private:
GameList& gl; GameList& gl;
}; };
List<GameEntry> glist; class GameListIterator : public Iterator<GameEntry> {
long lastUpdate; public:
GameListIterator(GameList* gl);
~GameListIterator();
bool hasNext();
GameEntry* next();
void remove();
void reset();
private:
GameList* gl;
Iterator<GameEntry>* it;
int bucket;
};
Mutex mutex;
List<GameEntry> buckets[MAX_BUCKETS];
int timeout;
}; };
#endif // _GAMELIST_H_ #endif // _GAMELIST_H_

View File

@ -35,7 +35,7 @@ int GameParser::execute(void* arg)
p = pkt->showfull(); p = pkt->showfull();
LogSystem::log(LOG_DEBUG, "%s", p); LogSystem::log(LOG_DEBUG, "%s", p);
delete p; delete [] p;
delete pkt; delete pkt;
break; break;
} }

View File

@ -3,13 +3,13 @@
scan_port 7130 scan_port 7130
# broadcast scan every X seconds # broadcast scan every X seconds
scan_interval 30 scan_interval 60
# use this interface(s) # use this interface(s)
scan_deny_iface scan_deny_iface
# server timeout after X seconds # server timeout after X seconds
game_timeout 30 game_timeout 180
# master answers with this source IP # master answers with this source IP
master_ip 0.0.0.0 master_ip 0.0.0.0
@ -20,6 +20,3 @@ rebuild_interval 5
# logging # logging
logfile hlswmaster.log logfile hlswmaster.log
logprio DEBUG logprio DEBUG
[hlswproxy]
master_ip 10.10.0.30 10.10.0.31

View File

@ -33,6 +33,11 @@ static struct option opts[] = {
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
LogSystem::init(DEFAULT_LOGPRIO, new StdErrLog()); LogSystem::init(DEFAULT_LOGPRIO, new StdErrLog());

View File

@ -22,45 +22,7 @@ struct hlsw_entry {
#define HLSW_MAX_PACKET_SIZE (sizeof(hlsw_header) + 140 * sizeof(struct hlsw_entry)) #define HLSW_MAX_PACKET_SIZE (sizeof(hlsw_header) + 140 * sizeof(struct hlsw_entry))
#define DEFAULT_REBUILD_INTERVAL 5 #define DEFAULT_REBUILD_INTERVAL 5
HlswServer::HlswPacket::HlswPacket(HlswPacket* next)
: NetPkt(HLSW_MAX_PACKET_SIZE), next(next)
{
memcpy((void*)data, hlsw_header, sizeof(hlsw_header));
size = sizeof(hlsw_header);
}
HlswServer::HlswPacket::~HlswPacket()
{
if (next)
delete next;
}
bool HlswServer::HlswPacket::addGame(GameEntry* ge)
{
if (size >= HLSW_MAX_PACKET_SIZE)
return false;
struct hlsw_entry tmp;
tmp.gameid = ge->gameid;
tmp.ip = ge->addr.s_addr;
tmp.port1 = ge->port1;
tmp.port2 = ge->port2;
memcpy((void*)(data + size), &tmp, sizeof(tmp));
size += sizeof(tmp);
return true;
}
void HlswServer::HlswPacket::send(Socket* socket, struct sockaddr_in* dst)
{
if (next)
next->send(socket, dst);
socket->sendto(this, dst);
}
HlswServer::HlswServer(Config& conf, GameList& glist) HlswServer::HlswServer(Config& conf, GameList& glist)
: lastUpdate(0)
{ {
const char *ip = conf.getString("global", "master_ip", "0.0.0.0"); const char *ip = conf.getString("global", "master_ip", "0.0.0.0");
LogSystem::log(LOG_NOTICE, "HlswServer listen on %s:%d", ip, HLSW_MASTER_PORT); LogSystem::log(LOG_NOTICE, "HlswServer listen on %s:%d", ip, HLSW_MASTER_PORT);
@ -74,11 +36,14 @@ HlswServer::HlswServer(Config& conf, GameList& glist)
int interval = conf.getInteger("global", "rebuild_interval", DEFAULT_REBUILD_INTERVAL); int interval = conf.getInteger("global", "rebuild_interval", DEFAULT_REBUILD_INTERVAL);
TimerService::registerTimer(new Timer(new RebuildEvent(*this, glist), interval)); TimerService::registerTimer(new Timer(new RebuildEvent(*this, glist), interval));
pktlist = new HlswPacket(NULL); pktlist = new List<NetPkt>();
} }
HlswServer::~HlswServer() HlswServer::~HlswServer()
{ {
while (!pktlist->isEmpty())
delete pktlist->get();
delete pktlist; delete pktlist;
delete socket; delete socket;
} }
@ -87,39 +52,61 @@ int HlswServer::execute(void* arg)
{ {
while (1) { while (1) {
NetPkt* pkt = socket->recv(); NetPkt* pkt = socket->recv();
if (!pkt->compare(0, hlsw_header, sizeof(hlsw_header))) { if (!pkt->compare(0, hlsw_header, strlen(hlsw_header))) {
LogSystem::log(LOG_NOTICE, "HlswServer: not a hlsw packet"); LogSystem::log(LOG_NOTICE, "HlswServer: not a hlsw packet");
continue; continue;
} }
mutex.lock(); mutex.lock();
pktlist->send(socket, pkt->getAddress()); Iterator<NetPkt>* it = pktlist->createIterator();
mutex.unlock(); while (it->hasNext())
socket->sendto(it->next(), pkt->getAddress());
delete it;
mutex.unlock();
} }
return 0; return 0;
} }
void HlswServer::rebuild(GameList& glist) { void HlswServer::rebuild(GameList& glist) {
if (glist.getLastUpdate() > lastUpdate) { List<NetPkt>* newlist = new List<NetPkt>();
HlswPacket* newlist = new HlswPacket(NULL);
Iterator<GameEntry>* it = glist.createIterator(); // header
while (it->hasNext()) { NetPkt* pkt = new NetPkt(HLSW_MAX_PACKET_SIZE);
GameEntry* d = it->next(); pkt->append(hlsw_header, sizeof(hlsw_header));
if (!newlist->addGame(d)) { newlist->add(pkt);
newlist = new HlswPacket(newlist);
newlist->addGame(d); Iterator<GameEntry>* it = glist.createIterator();
} while (it->hasNext()) {
NetPkt* last = newlist->peekTail();
if (last->getSize() == HLSW_MAX_PACKET_SIZE) {
last = new NetPkt(HLSW_MAX_PACKET_SIZE);
last->append(hlsw_header, sizeof(hlsw_header));
newlist->add(last);
} }
lastUpdate = glist.getLastUpdate();
delete it;
mutex.lock(); addGame(last, it->next());
HlswPacket* oldlist = pktlist;
pktlist = newlist;
mutex.unlock();
delete oldlist;
} }
delete it;
mutex.lock();
List<NetPkt>* oldlist = pktlist;
pktlist = newlist;
mutex.unlock();
while (!oldlist->isEmpty())
delete oldlist->get();
delete oldlist;
}
void HlswServer::addGame(NetPkt* pkt, GameEntry* entry)
{
struct hlsw_entry tmp;
tmp.gameid = entry->gameid;
tmp.ip = entry->addr.s_addr;
tmp.port1 = entry->port1;
tmp.port2 = entry->port2;
pkt->append((char*)&tmp, sizeof(tmp));
} }

View File

@ -34,23 +34,11 @@ private:
GameList& gl; GameList& gl;
}; };
class HlswPacket : private NetPkt { void addGame(NetPkt* pkt, GameEntry* entry);
public:
HlswPacket(HlswPacket* next);
~HlswPacket();
bool addGame(GameEntry* ge); List<NetPkt>* pktlist;
void send(Socket* socket, struct sockaddr_in* dst);
private:
HlswPacket* next;
};
Socket* socket;
HlswPacket* pktlist;
Mutex mutex; Mutex mutex;
Socket* socket;
long lastUpdate;
}; };
#endif // _HLSWSERVER_H_ #endif // _HLSWSERVER_H_

150
list.cpp
View File

@ -1,150 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "list.h"
ListBase::ListBase()
{
}
ListBase::~ListBase()
{
AutoMutex am(mutex);
while(!head.isEmpty())
head.getNext()->del();
}
void ListBase::add(const void* part)
{
ListEntryBase* entry = new ListEntryBase(part);
AutoMutex am(mutex);
entry->add(&head, head.getNext());
}
void ListBase::addTail(const void* part)
{
ListEntryBase* entry = new ListEntryBase(part);
AutoMutex am(mutex);
entry->add(head.getPrev(), &head);
}
void* ListBase::get()
{
AutoMutex am(mutex);
ListEntryBase* entry = head.getNext();
void* retval = entry->getPart();
if (!head.isEmpty()) {
entry->del();
delete entry;
}
return retval;
}
void* ListBase::getTail()
{
AutoMutex am(mutex);
ListEntryBase* entry = head.getPrev();
void* retval = entry->getPart();
if (!head.isEmpty()) {
entry->del();
delete entry;
}
return retval;
}
bool ListBase::isEmpty() const
{
AutoMutex am((Mutex&)mutex);
return head.isEmpty();
}
IteratorBase* ListBase::createIterator()
{
return new ListIteratorBase(this);
}
ListBase::ListEntryBase::ListEntryBase(const void* part)
: prev(this), next(this), part(part)
{
}
ListBase::ListEntryBase::~ListEntryBase()
{
}
void ListBase::ListEntryBase::add(ListEntryBase* prev_, ListEntryBase* next_)
{
this->next = next_;
this->prev = prev_;
next_->prev = this;
prev_->next = this;
}
void ListBase::ListEntryBase::del()
{
next->prev = prev;
prev->next = next;
next = prev = this;
}
bool ListBase::ListEntryBase::isEmpty() const
{
return (this->prev == this) && (this->next == this);
}
void* ListBase::ListEntryBase::getPart() const
{
// const void* -> void*
return (void*)part;
}
ListBase::ListEntryBase* ListBase::ListEntryBase::getPrev() const
{
return prev;
}
ListBase::ListEntryBase* ListBase::ListEntryBase::getNext() const
{
return next;
}
ListBase::ListIteratorBase::ListIteratorBase(ListBase* list)
: list(list)
{
list->mutex.lock();
reset();
}
ListBase::ListIteratorBase::~ListIteratorBase()
{
list->mutex.unlock();
}
bool ListBase::ListIteratorBase::hasNext()
{
return (pos->getNext() != &list->head);
}
void* ListBase::ListIteratorBase::next()
{
pos = pos->getNext();
return pos->getPart();
}
void ListBase::ListIteratorBase::remove()
{
ListEntryBase* tmp = pos->getPrev();
pos->del();
pos = tmp;
}
void ListBase::ListIteratorBase::reset()
{
pos = &list->head;
}

314
list.h
View File

@ -3,141 +3,229 @@
#include "mutex.h" #include "mutex.h"
class IteratorBase {
public:
virtual ~IteratorBase() {}
virtual bool hasNext() =0;
virtual void* next() =0;
virtual void remove() =0;
virtual void reset() =0;
protected:
IteratorBase() {}
IteratorBase(const IteratorBase& it);
IteratorBase& operator=(const IteratorBase& it);
};
class ListBase {
public:
ListBase();
~ListBase();
void add(const void* part);
void addTail(const void* part);
void* get();
void* getTail();
bool isEmpty() const;
IteratorBase* createIterator();
protected:
ListBase(const ListBase& l);
ListBase& operator=(const ListBase& l);
class ListEntryBase {
public:
ListEntryBase(const void* part = 0);
~ListEntryBase();
void add(ListEntryBase* prev, ListEntryBase* next);
void del();
bool isEmpty() const;
void* getPart() const;
ListEntryBase* getPrev() const;
ListEntryBase* getNext() const;
protected:
ListEntryBase(const ListEntryBase& l);
ListEntryBase& operator=(const ListEntryBase& l);
private:
ListEntryBase* prev;
ListEntryBase* next;
const void* part;
};
class ListIteratorBase : public IteratorBase {
public:
ListIteratorBase(ListBase* list);
~ListIteratorBase();
bool hasNext();
void* next();
void remove();
void reset();
private:
ListBase* list;
ListEntryBase* pos;
};
private:
ListEntryBase head;
Mutex mutex;
friend class ListIteratorBase;
};
template <class T> template <class T>
class Iterator : public IteratorBase { class Iterator {
public: public:
virtual T* next() =0; virtual ~Iterator() {}
virtual bool hasNext() =0;
virtual T* next() =0;
virtual void remove() =0;
virtual void reset() =0;
protected:
Iterator() {}
Iterator(const Iterator& it);
Iterator& operator=(const Iterator& it);
}; };
template <class T> template <class T>
class NullIterator : public Iterator<T> { class NullIterator : public Iterator<T> {
public: public:
NullIterator() {} NullIterator() {}
~NullIterator() {} virtual ~NullIterator() {}
virtual bool hasNext() { return false; }
bool hasNext() { return false; } virtual T* next() { return NULL; }
T* next() { return NULL; } virtual void remove() {}
void remove() {} virtual void reset() {}
void reset() {}
}; };
template <class T> template <class T>
class List : public ListBase { class ListEntry;
template <class T>
class List {
public: public:
List() {} List() : head(0), tail(0) {}
~List() {} ~List() {}
void add(const T* part) { ListBase::add(part); } void add(T* entry)
void addTail(const T* part) { ListBase::addTail(part); } {
T* get() { return (T*)ListBase::get(); } ListEntry<T>* tmp = (ListEntry<T>*)entry;
T* getTail() { return (T*)ListBase::getTail(); } tmp->next = NULL;
bool isEmpty() const { return ListBase::isEmpty(); }
Iterator<T>* createIterator() const { return new ListIteratorRO<T>(this); } if (!head)
Iterator<T>* createIteratorRW() { return new ListIteratorRW<T>(this); } head = tmp;
if (tail)
tail->next = tmp;
tail = tmp;
}
T* get()
{
ListEntry<T>* retval = head;
if (head)
head = head->next;
if (!head)
tail = NULL;
return (T*)retval;
}
T* peekHead()
{
return (T*)head;
}
T* peekTail()
{
return (T*)tail;
}
bool isEmpty()
{
return (head == NULL);
}
Iterator<T>* createIterator()
{
return new ListIterator<T>(this);
}
protected:
List(const List& l);
List& operator=(const List& l);
template <class TT>
class ListIterator : public Iterator<TT> {
public:
ListIterator(List<TT>* list)
: list(list)
{
reset();
}
virtual ~ListIterator() {}
virtual bool hasNext()
{
return (pos == NULL) ? (list->head != NULL) : (pos->next != NULL);
}
virtual TT* next()
{
prev = pos;
pos = (pos == NULL) ? list->head : pos->next;
return (TT*)pos;
}
virtual void remove()
{
// remove pre-head -> bail out
if (pos == NULL)
return;
// remove first
if (pos == list->head)
list->head = pos->next;
// remove middle
if (prev)
prev->next = pos->next;
// remove last
if (pos == list->tail)
list->tail = (prev == NULL) ? NULL : prev;
pos = prev;
}
virtual void reset()
{
pos = NULL;
prev = NULL;
}
protected:
ListIterator(const ListIterator& li);
ListIterator& operator=(const ListIterator& li);
List<TT>* list;
private:
ListEntry<TT>* pos;
ListEntry<TT>* prev;
};
private:
ListEntry<T> *head;
ListEntry<T> *tail;
};
template <class T>
class ListEntry {
friend class List<T>;
friend class List<T>::ListIterator<T>;
public:
ListEntry() {}
~ListEntry() {}
private:
ListEntry* next;
};
template <class T>
class LockedList : private List<T> {
public:
LockedList() {}
~LockedList() {}
void add(T* entry)
{
AutoMutex am(mutex);
List<T>::add(entry);
}
T* get()
{
AutoMutex am(mutex);
return List<T>::get();
}
T* peekFirst()
{
return NULL; // not with lockedlist
}
T* peekLast()
{
return NULL; // not with lockedlist
}
bool isEmpty()
{
AutoMutex am(mutex);
return List<T>::isEmpty();
}
Iterator<T>* createIterator()
{
return new LockedListIterator<T>(this);
}
private: private:
template <class TT> template <class TT>
class ListIteratorRO : public Iterator<TT>, private ListIteratorBase { class LockedListIterator : public List<TT>::ListIterator<TT> {
public: public:
ListIteratorRO(const List<TT>* list) : ListIteratorBase((ListBase*)list) {} LockedListIterator(LockedList<TT>* list)
~ListIteratorRO() {} : List<TT>::ListIterator<TT>(list)
{
list->mutex.lock();
}
bool hasNext() { return ListIteratorBase::hasNext(); } virtual ~LockedListIterator()
TT* next() { return (TT*)ListIteratorBase::next(); } {
void remove() {} ((LockedList<TT>*)list)->mutex.unlock();
void reset() { ListIteratorBase::reset(); } }
};
template <class TT>
class ListIteratorRW : public Iterator<TT>, private ListIteratorBase {
public:
ListIteratorRW(List<TT>* list) : ListIteratorBase(list) {}
~ListIteratorRW() {}
bool hasNext() { return ListIteratorBase::hasNext(); }
TT* next() { return (TT*)ListIteratorBase::next(); }
void remove() { ListIteratorBase::remove(); }
void reset() { ListIteratorBase::reset(); }
}; };
Mutex mutex;
}; };
#endif //_LIST_H_ #endif //_LIST_H_

View File

@ -45,11 +45,8 @@ ModGameSpy1::ModGameSpy1()
ModGameSpy1::~ModGameSpy1() ModGameSpy1::~ModGameSpy1()
{ {
while (!list.isEmpty()) { while (!list.isEmpty())
MultiPart* mp = list.get(); delete list.get();
delete mp->pkt;
delete mp;
}
} }
void ModGameSpy1::scan(MultiSock* msock) void ModGameSpy1::scan(MultiSock* msock)
@ -98,7 +95,7 @@ int ModGameSpy1::parse(NetPkt* pkt, GameList* glist)
/* non-final multi-part */ /* non-final multi-part */
} else if (!final) { } else if (!final) {
LogSystem::log(LOG_DEBUG, "non final %s (%d/%d)", buf, queryid, subid); LogSystem::log(LOG_DEBUG, "non final %s (%d/%d)", buf, queryid, subid);
list.addTail(new MultiPart(pkt, queryid, subid)); list.add(new MultiPart(pkt, queryid, subid));
return PARSE_ACCEPT_FREED; // parser must not free pkt return PARSE_ACCEPT_FREED; // parser must not free pkt
/* final multipart */ /* final multipart */
@ -125,9 +122,14 @@ ModGameSpy1::MultiPart::MultiPart(NetPkt* pkt, int queryid, int subid)
timeout = time(NULL) + MODGS1_GC_TIMEOUT; timeout = time(NULL) + MODGS1_GC_TIMEOUT;
} }
ModGameSpy1::MultiPart::~MultiPart()
{
delete pkt;
}
NetPkt* ModGameSpy1::merge(NetPkt* pkt, int queryid, int subid) NetPkt* ModGameSpy1::merge(NetPkt* pkt, int queryid, int subid)
{ {
Iterator<MultiPart>* it = list.createIteratorRW(); Iterator<MultiPart>* it = list.createIterator();
NetPkt* tmppkt = new NetPkt(NULL, 0); NetPkt* tmppkt = new NetPkt(NULL, 0);
tmppkt->setAddress(pkt->getAddress()); tmppkt->setAddress(pkt->getAddress());
@ -148,8 +150,8 @@ NetPkt* ModGameSpy1::merge(NetPkt* pkt, int queryid, int subid)
found = true; found = true;
if (searchid == mp->subid) { if (searchid == mp->subid) {
tmppkt->append(mp->pkt); tmppkt->merge(mp->pkt);
delete mp->pkt; delete mp;
searchid++; searchid++;
} }
} }
@ -159,7 +161,7 @@ NetPkt* ModGameSpy1::merge(NetPkt* pkt, int queryid, int subid)
delete it; delete it;
tmppkt->append(pkt); tmppkt->merge(pkt);
if (!found) { if (!found) {
delete tmppkt; delete tmppkt;
@ -171,7 +173,7 @@ NetPkt* ModGameSpy1::merge(NetPkt* pkt, int queryid, int subid)
void ModGameSpy1::gc() void ModGameSpy1::gc()
{ {
Iterator<MultiPart>* it = list.createIteratorRW(); Iterator<MultiPart>* it = list.createIterator();
long now = time(NULL); long now = time(NULL);
char buf[64]; char buf[64];
@ -182,9 +184,9 @@ void ModGameSpy1::gc()
LogSystem::log(LOG_NOTICE, "ModGameSpy1 gc removed: %s (%d/%d)", LogSystem::log(LOG_NOTICE, "ModGameSpy1 gc removed: %s (%d/%d)",
buf, mp->queryid, mp->subid); buf, mp->queryid, mp->subid);
it->remove(); it->remove();
delete mp;
} }
} }
delete it; delete it;
} }
@ -281,7 +283,7 @@ int ModGameSpy1::parse_real(NetPkt* pkt, GameList* glist, int gameid)
* beide ports in die serverliste uebernehmen * beide ports in die serverliste uebernehmen
*/ */
if ((offset != -1) && (port != pkt->getPort())) { if ((offset != -1) && (port != pkt->getPort())) {
glist->addGame(gameid, pkt, port, true); glist->addGame(gameid, pkt, port);
} else { } else {
glist->addGame(gameid, pkt); glist->addGame(gameid, pkt);

View File

@ -17,10 +17,10 @@ public:
void gc(); void gc();
private: private:
class MultiPart { class MultiPart : private ListEntry<MultiPart> {
public: public:
MultiPart(NetPkt* pkt, int queryid, int subid); MultiPart(NetPkt* pkt, int queryid, int subid);
~MultiPart() {} ~MultiPart();
NetPkt* pkt; NetPkt* pkt;
int queryid; int queryid;
@ -42,7 +42,7 @@ private:
NetPkt* merge(NetPkt* pkt, int queryid, int subid); NetPkt* merge(NetPkt* pkt, int queryid, int subid);
int parse_real(NetPkt* pkt, GameList* glist, int gameid); int parse_real(NetPkt* pkt, GameList* glist, int gameid);
List<MultiPart> list; LockedList<MultiPart> list;
}; };
#endif // _MODGAMESPY1_H_ #endif // _MODGAMESPY1_H_

View File

@ -78,7 +78,7 @@ int ModGameSpy2::parse(NetPkt* pkt, GameList* glist)
* beide ports in die serverliste uebernehmen * beide ports in die serverliste uebernehmen
*/ */
if ((pos2 != -1) && (port != pkt->getPort())) { if ((pos2 != -1) && (port != pkt->getPort())) {
glist->addGame(gameid, pkt, port, true); glist->addGame(gameid, pkt, port);
} else { } else {
glist->addGame(gameid, pkt); glist->addGame(gameid, pkt);

View File

@ -64,7 +64,7 @@ struct game_ports {
int gameid; int gameid;
}; };
class Module { class Module : private ListEntry<Module> {
public: public:
virtual ~Module() {}; virtual ~Module() {};
virtual void init(Config* conf) {} virtual void init(Config* conf) {}

View File

@ -16,7 +16,7 @@ void ModuleList::reg(Module* mod)
{ {
LogSystem::log(LOG_NOTICE, "Registering module '%s'", mod->getName()); LogSystem::log(LOG_NOTICE, "Registering module '%s'", mod->getName());
mod->init(&conf); mod->init(&conf);
mlist.addTail(mod); mlist.add(mod);
} }
void ModuleList::scan(MultiSock* msock) void ModuleList::scan(MultiSock* msock)

View File

@ -163,7 +163,7 @@ bool NetPkt::sameAddress(NetPkt* pkt)
(this->addr.sin_port == pkt->addr.sin_port); (this->addr.sin_port == pkt->addr.sin_port);
} }
void NetPkt::append(NetPkt* pkt) void NetPkt::merge(NetPkt* pkt)
{ {
unsigned int new_alloc = size + pkt->size; unsigned int new_alloc = size + pkt->size;
@ -179,3 +179,14 @@ void NetPkt::append(NetPkt* pkt)
memcpy((void*)(data + size), pkt->data, pkt->size); memcpy((void*)(data + size), pkt->data, pkt->size);
size += pkt->size; size += pkt->size;
} }
bool NetPkt::append(const char* buf, unsigned int len)
{
if (alloc < size + len)
return false;
memcpy((void*)(data + size), buf, len);
size += len;
return true;
}

View File

@ -4,6 +4,8 @@
#include <net/if.h> #include <net/if.h>
#include <netinet/in.h> #include <netinet/in.h>
#include "list.h"
#define PARSE_ACCEPT 1 #define PARSE_ACCEPT 1
#define PARSE_ACCEPT_FREED 2 #define PARSE_ACCEPT_FREED 2
#define PARSE_ACCEPT_FAKE 3 #define PARSE_ACCEPT_FAKE 3
@ -13,7 +15,7 @@
/* avoid cyclic deps */ /* avoid cyclic deps */
class Socket; class Socket;
class NetPkt { class NetPkt : private ListEntry<NetPkt> {
friend class Socket; friend class Socket;
public: public:
NetPkt(const char* data, int size); NetPkt(const char* data, int size);
@ -33,7 +35,8 @@ public:
struct sockaddr_in * getAddress(); struct sockaddr_in * getAddress();
bool sameAddress(NetPkt* pkt); bool sameAddress(NetPkt* pkt);
void append(NetPkt* pkt); void merge(NetPkt* pkt);
bool append(const char* buf, unsigned int len);
int getPort(); int getPort();
int getSize(); int getSize();

View File

@ -9,7 +9,7 @@ RecvQueue::~RecvQueue()
void RecvQueue::addPkt(NetPkt* pkt) void RecvQueue::addPkt(NetPkt* pkt)
{ {
if (pkt != NULL) { if (pkt != NULL) {
pktList.addTail(pkt); pktList.add(pkt);
pktCount.post(); pktCount.post();
} }
} }

View File

@ -19,7 +19,7 @@ protected:
private: private:
Semaphore pktCount; Semaphore pktCount;
List<NetPkt> pktList; LockedList<NetPkt> pktList;
}; };
#endif // _RECVQUEUE_H_ #endif // _RECVQUEUE_H_

View File

@ -6,7 +6,7 @@
#include "netpkt.h" #include "netpkt.h"
class Socket { class Socket : private ListEntry<Socket> {
public: public:
Socket(); Socket();
~Socket(); ~Socket();