diff --git a/.gitignore b/.gitignore index 93d8e80..964ab9f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ hlswmaster hlswmaster.log doc/* +masterquery +hlswmaster-ng.tar.gz diff --git a/Makefile b/Makefile index ed2ac9b..017e20e 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,9 @@ -CFLAGS := -O2 -pipe -Wall -Wunused -Wno-deprecated +CFLAGS := -O2 -pipe -Wall +CXXFLAGS := -O2 -pipe -Wall -Wunused -Wno-deprecated LIBS := -lpthread 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 \ mod_d3engine.o mod_gamespy1.o mod_gamespy2.o mod_halflife.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 hlswmaster: $(HLSWMASTER_SRC) hlswmaster.o - $(CXX) $(CFLAGS) $^ $(LIBS) -o $@ + $(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@ masterquery: masterquery.o $(CC) $(CFLAGS) $^ $(LIBS) -o $@ %.o: %.cpp - $(CXX) $(CFLAGS) -c $< -o $@ + $(CXX) $(CXXFLAGS) -c $< -o $@ %.d: %.cpp - $(CXX) $(CFLAGS) -MM -c $< -o $@ + $(CXX) $(CXXFLAGS) -MM -c $< -o $@ -dist: - git-tar-tree HEAD hlswmaster-ng | gzip -9 -c > hlswmaster-ng.tar.gz +dist: clean + 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: - rm -f hlswmaster masterquery *.d *.o *.log + rm -f hlswmaster masterquery *.d *.o *.log \ + hlswmaster-ng hlswmaster-ng.tar.gz ##DEPS := $(wildcard *.cpp) ##-include $(DEPS:.cpp=.d) diff --git a/config.cpp b/config.cpp index ba395cb..7a571f3 100644 --- a/config.cpp +++ b/config.cpp @@ -42,12 +42,12 @@ bool Config::Section::addTupel(const char* name, const char* value) return false; Tupel* t = new Tupel(name, value); - tupelList.addTail(t); + tupelList.add(t); return true; } -void Config::Section::show() const +void Config::Section::show() { Iterator* it = tupelList.createIterator(); LogSystem::log(LOG_INFO, "[%s]", name); @@ -60,7 +60,7 @@ void Config::Section::show() const delete it; } -const char* Config::Section::getTupelValue(const char* name) const +const char* Config::Section::getTupelValue(const char* name) { const char* retval = 0; Iterator* it = this->tupelList.createIterator(); @@ -121,7 +121,7 @@ Config::~Config() Config::Section* Config::addSection(const char* name) { Section* s = new Section(name); - sectionList.addTail(s); + sectionList.add(s); return s; } @@ -184,7 +184,7 @@ bool Config::parseFile(const char* name) return ret; } -void Config::show() const +void Config::show() { LogSystem::log(LOG_INFO, "Config Dump:"); Iterator
* it = sectionList.createIterator(); @@ -194,7 +194,7 @@ void Config::show() const delete it; } -Config::Section* Config::getSection(const char* name) const +Config::Section* Config::getSection(const char* name) { Section* retval = 0; @@ -211,13 +211,13 @@ Config::Section* Config::getSection(const char* name) const 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); 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); if (!retval) { @@ -229,7 +229,7 @@ const char* Config::getString(const char* section, const char* option, char* def 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); if (!retval) { diff --git a/config.h b/config.h index 93034c8..f09dbf8 100644 --- a/config.h +++ b/config.h @@ -8,16 +8,16 @@ public: ~Config(); bool parseFile(const char* name); - void show() const; + void show(); - const char* getParameter(const char* section, const char* name) const; - const char* getString(const char* section, const char* name, char* def) const; - int getInteger(const char* section, const char* name, int def) const; + const char* getParameter(const char* section, const char* name); + const char* getString(const char* section, const char* name, char* def); + int getInteger(const char* section, const char* name, int def); Iterator* createIterator(const char* section, const char* name); private: - class Tupel { + class Tupel : private ListEntry { public: Tupel(const char* name, const char* value); ~Tupel(); @@ -26,7 +26,7 @@ private: const char* value; }; - class Section { + class Section : private ListEntry
{ public: class SectionIterator : public Iterator { public: @@ -47,8 +47,8 @@ private: ~Section(); bool addTupel(const char* name, const char* option); - const char* getTupelValue(const char* name) const; - void show() const; + const char* getTupelValue(const char* name); + void show(); const char* name; @@ -56,7 +56,7 @@ private: }; Section* addSection(const char* name); - Section* getSection(const char* name) const; + Section* getSection(const char* name); List
sectionList; }; diff --git a/gameentry.cpp b/gameentry.cpp index 456ecd2..d807f5f 100644 --- a/gameentry.cpp +++ b/gameentry.cpp @@ -1,5 +1,24 @@ +#include +#include +#include +#include + #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) { if (this->addr.s_addr > ge->addr.s_addr) @@ -14,5 +33,36 @@ int GameEntry::compare(const GameEntry* ge) if (this->port1 < ge->port1) return 1; + // only compare IP:port + // gameid and port2 are useless 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); +} diff --git a/gameentry.h b/gameentry.h index 403b57f..22be4cc 100644 --- a/gameentry.h +++ b/gameentry.h @@ -4,12 +4,18 @@ #include #include -class GameEntry { +#include "netpkt.h" + +class GameEntry : private ListEntry { public: - GameEntry() {}; - ~GameEntry() {}; + GameEntry(int gameid, NetPkt* pkt, int port2); + ~GameEntry() {} int compare(const GameEntry* ge); + int hash(int max); + void update(); + + int show(char* buf, int size); struct in_addr addr; int port1; diff --git a/gamelist.cpp b/gamelist.cpp index 8231873..20ed270 100644 --- a/gamelist.cpp +++ b/gamelist.cpp @@ -3,43 +3,123 @@ #define DEFAULT_TIMEOUT 180 -/* -** TODO: replace list with sorted list, or even better with a hash -*/ - GameList::GameList(Config& conf) -: lastUpdate(0) { - int interval = conf.getInteger("global", "game_timeout", DEFAULT_TIMEOUT); - TimerService::registerTimer(new Timer(new CleanupEvent(*this), interval)); + timeout = conf.getInteger("global", "game_timeout", DEFAULT_TIMEOUT); + TimerService::registerTimer(new Timer(new CleanupEvent(*this), timeout)); } GameList::~GameList() { - while (!glist.isEmpty()) - delete glist.get(); + Iterator* it = createIterator(); + while (it->hasNext()) + delete it->next(); + + delete it; } void GameList::cleanup() { + long now = time(NULL); + + Iterator* 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* 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* 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]; - pkt->show(buf, sizeof(buf)); - LogSystem::log(LOG_NOTICE, "Adding Game %d: %s", gameid, buf); - - glist.add(new GameEntry()); - lastUpdate++; + gl->mutex.lock(); + reset(); +} + +GameList::GameListIterator::~GameListIterator() +{ + 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(); } diff --git a/gamelist.h b/gamelist.h index 92de8c6..c770d6d 100644 --- a/gamelist.h +++ b/gamelist.h @@ -6,18 +6,19 @@ #include "gameentry.h" #include "timerservice.h" #include "list.h" +#include "mutex.h" + +// 127 is prime! +#define MAX_BUCKETS 127 class GameList { public: GameList(Config& conf); ~GameList(); - void addGame(int gameid, NetPkt* pkt, int port2 = 0, bool swap = false); - - long getLastUpdate(); - Iterator* createIterator(); - void cleanup(); + void addGame(int gameid, NetPkt* pkt, int port2 = 0); + Iterator* createIterator(); protected: GameList(const GameList& gl); @@ -34,8 +35,26 @@ private: GameList& gl; }; - List glist; - long lastUpdate; + class GameListIterator : public Iterator { + public: + GameListIterator(GameList* gl); + ~GameListIterator(); + + bool hasNext(); + GameEntry* next(); + void remove(); + void reset(); + + private: + GameList* gl; + Iterator* it; + int bucket; + }; + + Mutex mutex; + List buckets[MAX_BUCKETS]; + + int timeout; }; #endif // _GAMELIST_H_ diff --git a/gameparser.cpp b/gameparser.cpp index a5c3db9..e9fbd91 100644 --- a/gameparser.cpp +++ b/gameparser.cpp @@ -35,7 +35,7 @@ int GameParser::execute(void* arg) p = pkt->showfull(); LogSystem::log(LOG_DEBUG, "%s", p); - delete p; + delete [] p; delete pkt; break; } diff --git a/hlswmaster.conf b/hlswmaster.conf index a12b6ee..888aa69 100644 --- a/hlswmaster.conf +++ b/hlswmaster.conf @@ -3,13 +3,13 @@ scan_port 7130 # broadcast scan every X seconds -scan_interval 30 +scan_interval 60 # use this interface(s) scan_deny_iface # server timeout after X seconds -game_timeout 30 +game_timeout 180 # master answers with this source IP master_ip 0.0.0.0 @@ -20,6 +20,3 @@ rebuild_interval 5 # logging logfile hlswmaster.log logprio DEBUG - -[hlswproxy] -master_ip 10.10.0.30 10.10.0.31 diff --git a/hlswmaster.cpp b/hlswmaster.cpp index 4469cbd..b61df7e 100644 --- a/hlswmaster.cpp +++ b/hlswmaster.cpp @@ -33,6 +33,11 @@ static struct option opts[] = { {0, 0, 0, 0} }; +#include +#include +#include +#include + int main(int argc, char *argv[]) { LogSystem::init(DEFAULT_LOGPRIO, new StdErrLog()); diff --git a/hlswserver.cpp b/hlswserver.cpp index 56379e0..24a98f0 100644 --- a/hlswserver.cpp +++ b/hlswserver.cpp @@ -22,45 +22,7 @@ struct hlsw_entry { #define HLSW_MAX_PACKET_SIZE (sizeof(hlsw_header) + 140 * sizeof(struct hlsw_entry)) #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) -: lastUpdate(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); @@ -74,11 +36,14 @@ HlswServer::HlswServer(Config& conf, GameList& glist) int interval = conf.getInteger("global", "rebuild_interval", DEFAULT_REBUILD_INTERVAL); TimerService::registerTimer(new Timer(new RebuildEvent(*this, glist), interval)); - pktlist = new HlswPacket(NULL); + pktlist = new List(); } HlswServer::~HlswServer() { + while (!pktlist->isEmpty()) + delete pktlist->get(); + delete pktlist; delete socket; } @@ -87,39 +52,61 @@ int HlswServer::execute(void* arg) { while (1) { 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"); continue; } mutex.lock(); - pktlist->send(socket, pkt->getAddress()); - mutex.unlock(); + Iterator* it = pktlist->createIterator(); + while (it->hasNext()) + socket->sendto(it->next(), pkt->getAddress()); + delete it; + mutex.unlock(); } return 0; } void HlswServer::rebuild(GameList& glist) { - if (glist.getLastUpdate() > lastUpdate) { - HlswPacket* newlist = new HlswPacket(NULL); + List* newlist = new List(); - Iterator* it = glist.createIterator(); - while (it->hasNext()) { - GameEntry* d = it->next(); - if (!newlist->addGame(d)) { - newlist = new HlswPacket(newlist); - newlist->addGame(d); - } + // header + NetPkt* pkt = new NetPkt(HLSW_MAX_PACKET_SIZE); + pkt->append(hlsw_header, sizeof(hlsw_header)); + newlist->add(pkt); + + Iterator* 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(); - HlswPacket* oldlist = pktlist; - pktlist = newlist; - mutex.unlock(); - - delete oldlist; + addGame(last, it->next()); } + delete it; + + mutex.lock(); + List* 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)); } diff --git a/hlswserver.h b/hlswserver.h index 4b1a8f3..ef2d9b0 100644 --- a/hlswserver.h +++ b/hlswserver.h @@ -34,23 +34,11 @@ private: GameList& gl; }; - class HlswPacket : private NetPkt { - public: - HlswPacket(HlswPacket* next); - ~HlswPacket(); + void addGame(NetPkt* pkt, GameEntry* entry); - bool addGame(GameEntry* ge); - void send(Socket* socket, struct sockaddr_in* dst); - - private: - HlswPacket* next; - }; - - Socket* socket; - HlswPacket* pktlist; + List* pktlist; Mutex mutex; - - long lastUpdate; + Socket* socket; }; #endif // _HLSWSERVER_H_ diff --git a/list.cpp b/list.cpp deleted file mode 100644 index 3c4b5be..0000000 --- a/list.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include -#include -#include - -#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; -} - diff --git a/list.h b/list.h index 6ec974d..76a8da6 100644 --- a/list.h +++ b/list.h @@ -3,141 +3,229 @@ #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 Iterator : public IteratorBase { +class Iterator { 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 NullIterator : public Iterator { public: NullIterator() {} - ~NullIterator() {} - - bool hasNext() { return false; } - T* next() { return NULL; } - void remove() {} - void reset() {} + virtual ~NullIterator() {} + virtual bool hasNext() { return false; } + virtual T* next() { return NULL; } + virtual void remove() {} + virtual void reset() {} }; + template -class List : public ListBase { +class ListEntry; + + +template +class List { public: - List() {} + List() : head(0), tail(0) {} ~List() {} - void add(const T* part) { ListBase::add(part); } - void addTail(const T* part) { ListBase::addTail(part); } - T* get() { return (T*)ListBase::get(); } - T* getTail() { return (T*)ListBase::getTail(); } - bool isEmpty() const { return ListBase::isEmpty(); } + void add(T* entry) + { + ListEntry* tmp = (ListEntry*)entry; + tmp->next = NULL; - Iterator* createIterator() const { return new ListIteratorRO(this); } - Iterator* createIteratorRW() { return new ListIteratorRW(this); } + if (!head) + head = tmp; + + if (tail) + tail->next = tmp; + tail = tmp; + } + + T* get() + { + ListEntry* 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* createIterator() + { + return new ListIterator(this); + } + +protected: + List(const List& l); + List& operator=(const List& l); + + template + class ListIterator : public Iterator { + public: + ListIterator(List* 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* list; + + private: + ListEntry* pos; + ListEntry* prev; + }; + +private: + ListEntry *head; + ListEntry *tail; +}; + + +template +class ListEntry { +friend class List; +friend class List::ListIterator; +public: + ListEntry() {} + ~ListEntry() {} + +private: + ListEntry* next; +}; + + +template +class LockedList : private List { +public: + LockedList() {} + ~LockedList() {} + void add(T* entry) + { + AutoMutex am(mutex); + List::add(entry); + } + + T* get() + { + AutoMutex am(mutex); + return List::get(); + } + + T* peekFirst() + { + return NULL; // not with lockedlist + } + + T* peekLast() + { + return NULL; // not with lockedlist + } + + bool isEmpty() + { + AutoMutex am(mutex); + return List::isEmpty(); + } + + Iterator* createIterator() + { + return new LockedListIterator(this); + } private: template - class ListIteratorRO : public Iterator, private ListIteratorBase { + class LockedListIterator : public List::ListIterator { public: - ListIteratorRO(const List* list) : ListIteratorBase((ListBase*)list) {} - ~ListIteratorRO() {} + LockedListIterator(LockedList* list) + : List::ListIterator(list) + { + list->mutex.lock(); + } - bool hasNext() { return ListIteratorBase::hasNext(); } - TT* next() { return (TT*)ListIteratorBase::next(); } - void remove() {} - void reset() { ListIteratorBase::reset(); } - }; - - template - class ListIteratorRW : public Iterator, private ListIteratorBase { - public: - ListIteratorRW(List* list) : ListIteratorBase(list) {} - ~ListIteratorRW() {} - - bool hasNext() { return ListIteratorBase::hasNext(); } - TT* next() { return (TT*)ListIteratorBase::next(); } - void remove() { ListIteratorBase::remove(); } - void reset() { ListIteratorBase::reset(); } + virtual ~LockedListIterator() + { + ((LockedList*)list)->mutex.unlock(); + } }; + Mutex mutex; }; #endif //_LIST_H_ diff --git a/mod_gamespy1.cpp b/mod_gamespy1.cpp index 9d4bf76..b0aff0f 100644 --- a/mod_gamespy1.cpp +++ b/mod_gamespy1.cpp @@ -45,11 +45,8 @@ ModGameSpy1::ModGameSpy1() ModGameSpy1::~ModGameSpy1() { - while (!list.isEmpty()) { - MultiPart* mp = list.get(); - delete mp->pkt; - delete mp; - } + while (!list.isEmpty()) + delete list.get(); } void ModGameSpy1::scan(MultiSock* msock) @@ -98,7 +95,7 @@ int ModGameSpy1::parse(NetPkt* pkt, GameList* glist) /* non-final multi-part */ } else if (!final) { 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 /* final multipart */ @@ -125,9 +122,14 @@ ModGameSpy1::MultiPart::MultiPart(NetPkt* pkt, int queryid, int subid) timeout = time(NULL) + MODGS1_GC_TIMEOUT; } +ModGameSpy1::MultiPart::~MultiPart() +{ + delete pkt; +} + NetPkt* ModGameSpy1::merge(NetPkt* pkt, int queryid, int subid) { - Iterator* it = list.createIteratorRW(); + Iterator* it = list.createIterator(); NetPkt* tmppkt = new NetPkt(NULL, 0); tmppkt->setAddress(pkt->getAddress()); @@ -148,8 +150,8 @@ NetPkt* ModGameSpy1::merge(NetPkt* pkt, int queryid, int subid) found = true; if (searchid == mp->subid) { - tmppkt->append(mp->pkt); - delete mp->pkt; + tmppkt->merge(mp->pkt); + delete mp; searchid++; } } @@ -159,7 +161,7 @@ NetPkt* ModGameSpy1::merge(NetPkt* pkt, int queryid, int subid) delete it; - tmppkt->append(pkt); + tmppkt->merge(pkt); if (!found) { delete tmppkt; @@ -171,7 +173,7 @@ NetPkt* ModGameSpy1::merge(NetPkt* pkt, int queryid, int subid) void ModGameSpy1::gc() { - Iterator* it = list.createIteratorRW(); + Iterator* it = list.createIterator(); long now = time(NULL); char buf[64]; @@ -182,9 +184,9 @@ void ModGameSpy1::gc() LogSystem::log(LOG_NOTICE, "ModGameSpy1 gc removed: %s (%d/%d)", buf, mp->queryid, mp->subid); it->remove(); + delete mp; } } - delete it; } @@ -281,7 +283,7 @@ int ModGameSpy1::parse_real(NetPkt* pkt, GameList* glist, int gameid) * beide ports in die serverliste uebernehmen */ if ((offset != -1) && (port != pkt->getPort())) { - glist->addGame(gameid, pkt, port, true); + glist->addGame(gameid, pkt, port); } else { glist->addGame(gameid, pkt); diff --git a/mod_gamespy1.h b/mod_gamespy1.h index ed6fcf2..fd2873b 100644 --- a/mod_gamespy1.h +++ b/mod_gamespy1.h @@ -17,10 +17,10 @@ public: void gc(); private: - class MultiPart { + class MultiPart : private ListEntry { public: MultiPart(NetPkt* pkt, int queryid, int subid); - ~MultiPart() {} + ~MultiPart(); NetPkt* pkt; int queryid; @@ -42,7 +42,7 @@ private: NetPkt* merge(NetPkt* pkt, int queryid, int subid); int parse_real(NetPkt* pkt, GameList* glist, int gameid); - List list; + LockedList list; }; #endif // _MODGAMESPY1_H_ diff --git a/mod_gamespy2.cpp b/mod_gamespy2.cpp index cc180a1..9f57eac 100644 --- a/mod_gamespy2.cpp +++ b/mod_gamespy2.cpp @@ -78,7 +78,7 @@ int ModGameSpy2::parse(NetPkt* pkt, GameList* glist) * beide ports in die serverliste uebernehmen */ if ((pos2 != -1) && (port != pkt->getPort())) { - glist->addGame(gameid, pkt, port, true); + glist->addGame(gameid, pkt, port); } else { glist->addGame(gameid, pkt); diff --git a/module.h b/module.h index 985c847..00413ce 100644 --- a/module.h +++ b/module.h @@ -64,7 +64,7 @@ struct game_ports { int gameid; }; -class Module { +class Module : private ListEntry { public: virtual ~Module() {}; virtual void init(Config* conf) {} diff --git a/modulelist.cpp b/modulelist.cpp index 252dd44..7c91ca6 100644 --- a/modulelist.cpp +++ b/modulelist.cpp @@ -16,7 +16,7 @@ void ModuleList::reg(Module* mod) { LogSystem::log(LOG_NOTICE, "Registering module '%s'", mod->getName()); mod->init(&conf); - mlist.addTail(mod); + mlist.add(mod); } void ModuleList::scan(MultiSock* msock) diff --git a/netpkt.cpp b/netpkt.cpp index 63cf499..452354c 100644 --- a/netpkt.cpp +++ b/netpkt.cpp @@ -163,7 +163,7 @@ bool NetPkt::sameAddress(NetPkt* pkt) (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; @@ -179,3 +179,14 @@ void NetPkt::append(NetPkt* pkt) memcpy((void*)(data + size), pkt->data, 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; +} diff --git a/netpkt.h b/netpkt.h index 98e6948..be7f0cd 100644 --- a/netpkt.h +++ b/netpkt.h @@ -4,6 +4,8 @@ #include #include +#include "list.h" + #define PARSE_ACCEPT 1 #define PARSE_ACCEPT_FREED 2 #define PARSE_ACCEPT_FAKE 3 @@ -13,7 +15,7 @@ /* avoid cyclic deps */ class Socket; -class NetPkt { +class NetPkt : private ListEntry { friend class Socket; public: NetPkt(const char* data, int size); @@ -33,7 +35,8 @@ public: struct sockaddr_in * getAddress(); bool sameAddress(NetPkt* pkt); - void append(NetPkt* pkt); + void merge(NetPkt* pkt); + bool append(const char* buf, unsigned int len); int getPort(); int getSize(); diff --git a/recvqueue.cpp b/recvqueue.cpp index 0c33f17..c287616 100644 --- a/recvqueue.cpp +++ b/recvqueue.cpp @@ -9,7 +9,7 @@ RecvQueue::~RecvQueue() void RecvQueue::addPkt(NetPkt* pkt) { if (pkt != NULL) { - pktList.addTail(pkt); + pktList.add(pkt); pktCount.post(); } } diff --git a/recvqueue.h b/recvqueue.h index 064af64..3dec760 100644 --- a/recvqueue.h +++ b/recvqueue.h @@ -19,7 +19,7 @@ protected: private: Semaphore pktCount; - List pktList; + LockedList pktList; }; #endif // _RECVQUEUE_H_ diff --git a/socket.h b/socket.h index dc5fe33..c6b32f9 100644 --- a/socket.h +++ b/socket.h @@ -6,7 +6,7 @@ #include "netpkt.h" -class Socket { +class Socket : private ListEntry { public: Socket(); ~Socket();