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.log
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
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)

View File

@ -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<Tupel>* 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<Tupel>* 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<Section>* 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) {

View File

@ -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<char>* createIterator(const char* section, const char* name);
private:
class Tupel {
class Tupel : private ListEntry<Tupel> {
public:
Tupel(const char* name, const char* value);
~Tupel();
@ -26,7 +26,7 @@ private:
const char* value;
};
class Section {
class Section : private ListEntry<Section> {
public:
class SectionIterator : public Iterator<char> {
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<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"
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);
}

View File

@ -4,12 +4,18 @@
#include <net/if.h>
#include <netinet/in.h>
class GameEntry {
#include "netpkt.h"
class GameEntry : private ListEntry<GameEntry> {
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;

View File

@ -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<GameEntry>* it = createIterator();
while (it->hasNext())
delete it->next();
delete it;
}
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()
{
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();
}

View File

@ -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<GameEntry>* createIterator();
void cleanup();
void addGame(int gameid, NetPkt* pkt, int port2 = 0);
Iterator<GameEntry>* createIterator();
protected:
GameList(const GameList& gl);
@ -34,8 +35,26 @@ private:
GameList& gl;
};
List<GameEntry> glist;
long lastUpdate;
class GameListIterator : public Iterator<GameEntry> {
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_

View File

@ -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;
}

View File

@ -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

View File

@ -33,6 +33,11 @@ static struct option opts[] = {
{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[])
{
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 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<NetPkt>();
}
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<NetPkt>* 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<NetPkt>* newlist = new List<NetPkt>();
Iterator<GameEntry>* 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<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();
HlswPacket* oldlist = pktlist;
pktlist = newlist;
mutex.unlock();
delete oldlist;
addGame(last, it->next());
}
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;
};
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<NetPkt>* pktlist;
Mutex mutex;
long lastUpdate;
Socket* socket;
};
#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"
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>
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 T>
class NullIterator : public Iterator<T> {
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 T>
class List : public ListBase {
class ListEntry;
template <class T>
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<T>* tmp = (ListEntry<T>*)entry;
tmp->next = NULL;
Iterator<T>* createIterator() const { return new ListIteratorRO<T>(this); }
Iterator<T>* createIteratorRW() { return new ListIteratorRW<T>(this); }
if (!head)
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:
template <class TT>
class ListIteratorRO : public Iterator<TT>, private ListIteratorBase {
class LockedListIterator : public List<TT>::ListIterator<TT> {
public:
ListIteratorRO(const List<TT>* list) : ListIteratorBase((ListBase*)list) {}
~ListIteratorRO() {}
LockedListIterator(LockedList<TT>* list)
: List<TT>::ListIterator<TT>(list)
{
list->mutex.lock();
}
bool hasNext() { return ListIteratorBase::hasNext(); }
TT* next() { return (TT*)ListIteratorBase::next(); }
void remove() {}
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(); }
virtual ~LockedListIterator()
{
((LockedList<TT>*)list)->mutex.unlock();
}
};
Mutex mutex;
};
#endif //_LIST_H_

View File

@ -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<MultiPart>* it = list.createIteratorRW();
Iterator<MultiPart>* 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<MultiPart>* it = list.createIteratorRW();
Iterator<MultiPart>* 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);

View File

@ -17,10 +17,10 @@ public:
void gc();
private:
class MultiPart {
class MultiPart : private ListEntry<MultiPart> {
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<MultiPart> list;
LockedList<MultiPart> list;
};
#endif // _MODGAMESPY1_H_

View File

@ -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);

View File

@ -64,7 +64,7 @@ struct game_ports {
int gameid;
};
class Module {
class Module : private ListEntry<Module> {
public:
virtual ~Module() {};
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());
mod->init(&conf);
mlist.addTail(mod);
mlist.add(mod);
}
void ModuleList::scan(MultiSock* msock)

View File

@ -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;
}

View File

@ -4,6 +4,8 @@
#include <net/if.h>
#include <netinet/in.h>
#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<NetPkt> {
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();

View File

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

View File

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

View File

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