2006-02-05 16:44:38 +01:00
|
|
|
#include <string.h>
|
|
|
|
#include "mod_gamespy1.h"
|
2006-04-16 21:02:41 +02:00
|
|
|
#include "modhelper.h"
|
|
|
|
#include "logging.h"
|
2006-02-05 16:44:38 +01:00
|
|
|
|
2006-03-07 20:30:11 +01:00
|
|
|
#define MODGS1_GC_TIMEOUT 5
|
|
|
|
|
2006-02-05 16:44:38 +01:00
|
|
|
static struct game_ports port_arr[] = {
|
2006-03-06 20:13:26 +01:00
|
|
|
{ 7777, 7788, ID_UT }, // ut, ut2k3, rune, ut2k4, aao, POSTAL2
|
2006-02-05 16:44:38 +01:00
|
|
|
{ 22000, 22010, ID_BF1942 }, // bf1942(16)
|
|
|
|
{ 23000, 23010, ID_BFV }, // bfv(35)
|
|
|
|
{ 26001, 26011, ID_IGI2 }, // igi2(19)
|
2006-03-06 20:13:26 +01:00
|
|
|
{ 27888, 27888, ID_AVP2 }, // avp2(17), FEAR
|
2006-02-05 16:44:38 +01:00
|
|
|
{ 0,0,0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char scanmsg[] = "\\status\\";
|
2006-03-06 20:13:26 +01:00
|
|
|
static const char search_queryid[] = "\\queryid\\";
|
|
|
|
static const char search_final[] = "\\final\\";
|
|
|
|
|
|
|
|
static const char search_hostport[] = "\\hostport\\";
|
|
|
|
static const char search_gamename[] = "\\gamename\\";
|
|
|
|
static const char search_gsgamename[] = "\\gsgamename\\";
|
|
|
|
static const char search_gameid[] = "\\game_id\\";
|
|
|
|
|
|
|
|
static const char reply_ut[] = "ut\\";
|
|
|
|
static const char reply_ut2k3[] = "ut2\\";
|
|
|
|
static const char reply_ut2k4[] = "ut2004\\";
|
|
|
|
static const char reply_bf1942[] = "bfield1942\\";
|
|
|
|
static const char reply_bfv1[] = "bfvietnam\\";
|
|
|
|
static const char reply_bfv2[] = "BFVIETNAM\\";
|
|
|
|
static const char reply_poe[] = "poe\\";
|
|
|
|
static const char reply_opk[] = "opk\\";
|
|
|
|
static const char reply_avp2[] = "avp2\\";
|
|
|
|
static const char reply_igi2[] = "projectigi2r\\";
|
|
|
|
static const char reply_aao[] = "armygame\\";
|
|
|
|
static const char reply_rune[] = "rune\\";
|
|
|
|
static const char reply_postal2[] = "postal2\\";
|
|
|
|
static const char reply_fear[] = "fear\\";
|
|
|
|
|
|
|
|
ModGameSpy1::ModGameSpy1()
|
|
|
|
{
|
2006-03-07 20:30:11 +01:00
|
|
|
TimerService::registerTimer(new Timer(new GcEvent(*this), MODGS1_GC_TIMEOUT));
|
2006-03-06 20:13:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ModGameSpy1::~ModGameSpy1()
|
|
|
|
{
|
2006-04-15 19:55:07 +02:00
|
|
|
while (!list.isEmpty())
|
|
|
|
delete list.get();
|
2006-03-06 20:13:26 +01:00
|
|
|
}
|
2006-02-05 16:44:38 +01:00
|
|
|
|
|
|
|
void ModGameSpy1::scan(MultiSock* msock)
|
|
|
|
{
|
2006-03-05 02:28:19 +01:00
|
|
|
ModHelper::send(msock, port_arr, scanmsg, strlen(scanmsg));
|
2006-02-05 16:44:38 +01:00
|
|
|
}
|
|
|
|
|
2006-03-06 20:13:26 +01:00
|
|
|
int ModGameSpy1::parse(NetPkt* pkt, GameList* glist)
|
|
|
|
{
|
|
|
|
NetPkt* pkt2;
|
|
|
|
int gameid, pos, offset, queryid, subid, retval;
|
|
|
|
bool final;
|
|
|
|
|
|
|
|
gameid = ModHelper::checkPorts(pkt, port_arr);
|
|
|
|
if (!gameid)
|
|
|
|
return PARSE_REJECT;
|
|
|
|
|
|
|
|
/* eat ut connection attemps */
|
|
|
|
if (gameid == 5 && pkt->getSize() <= 6)
|
|
|
|
return PARSE_ACCEPT_QUIRK;
|
|
|
|
|
|
|
|
offset = pkt->find(0, search_queryid, strlen(search_queryid));
|
|
|
|
if (offset == -1)
|
|
|
|
return PARSE_REJECT;
|
|
|
|
|
|
|
|
pos = offset + strlen(search_queryid);
|
|
|
|
offset = pkt->parse_int(pos, &queryid);
|
|
|
|
if (offset == 0)
|
|
|
|
return PARSE_REJECT;
|
|
|
|
|
|
|
|
pos += offset +1;
|
|
|
|
offset = pkt->parse_int(pos, &subid);
|
|
|
|
if (offset == 0)
|
|
|
|
return PARSE_REJECT;
|
|
|
|
|
|
|
|
offset = pkt->find(0, search_final, strlen(search_final));
|
|
|
|
final = (offset != -1);
|
|
|
|
|
2006-03-07 20:30:11 +01:00
|
|
|
char buf[64];
|
|
|
|
pkt->show(buf, sizeof(buf));
|
|
|
|
|
2006-03-06 20:13:26 +01:00
|
|
|
/* single final packet -> shortcut */
|
|
|
|
if (final && (subid == 1)) {
|
|
|
|
pkt2 = pkt;
|
|
|
|
|
|
|
|
/* non-final multi-part */
|
|
|
|
} else if (!final) {
|
2006-03-07 20:30:11 +01:00
|
|
|
LogSystem::log(LOG_DEBUG, "non final %s (%d/%d)", buf, queryid, subid);
|
2006-04-15 19:55:07 +02:00
|
|
|
list.add(new MultiPart(pkt, queryid, subid));
|
2006-03-07 20:30:11 +01:00
|
|
|
return PARSE_ACCEPT_FREED; // parser must not free pkt
|
2006-03-06 20:13:26 +01:00
|
|
|
|
|
|
|
/* final multipart */
|
|
|
|
} else {
|
2006-03-07 20:30:11 +01:00
|
|
|
LogSystem::log(LOG_DEBUG, "multi final %s (%d/%d)", buf, queryid, subid);
|
2006-03-06 20:13:26 +01:00
|
|
|
pkt2 = merge(pkt, queryid, subid);
|
|
|
|
if (pkt2 == NULL) {
|
2006-03-07 20:30:11 +01:00
|
|
|
LogSystem::log(LOG_NOTICE, "ModGameSpy1: failed to merge");
|
|
|
|
return PARSE_ACCEPT; // let parser free pkt
|
2006-03-06 20:13:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = parse_real(pkt2, glist, gameid);
|
|
|
|
|
|
|
|
if (pkt2 != pkt)
|
2006-03-07 20:30:11 +01:00
|
|
|
delete pkt2; // free merged packet
|
2006-03-06 20:13:26 +01:00
|
|
|
|
2006-03-07 20:30:11 +01:00
|
|
|
return retval; // ACCPET/REJECT -> let parser free pkt
|
2006-03-06 20:13:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ModGameSpy1::MultiPart::MultiPart(NetPkt* pkt, int queryid, int subid)
|
|
|
|
: pkt(pkt), queryid(queryid), subid(subid)
|
|
|
|
{
|
2006-03-07 20:30:11 +01:00
|
|
|
timeout = time(NULL) + MODGS1_GC_TIMEOUT;
|
2006-03-06 20:13:26 +01:00
|
|
|
}
|
|
|
|
|
2006-04-15 19:55:07 +02:00
|
|
|
ModGameSpy1::MultiPart::~MultiPart()
|
|
|
|
{
|
|
|
|
delete pkt;
|
|
|
|
}
|
|
|
|
|
2006-03-06 20:13:26 +01:00
|
|
|
NetPkt* ModGameSpy1::merge(NetPkt* pkt, int queryid, int subid)
|
|
|
|
{
|
2006-04-15 19:55:07 +02:00
|
|
|
Iterator<MultiPart>* it = list.createIterator();
|
2006-03-06 20:13:26 +01:00
|
|
|
|
|
|
|
NetPkt* tmppkt = new NetPkt(NULL, 0);
|
|
|
|
tmppkt->setAddress(pkt->getAddress());
|
|
|
|
|
|
|
|
bool found;
|
|
|
|
int searchid = 1;
|
|
|
|
do {
|
|
|
|
found = false;
|
|
|
|
while (it->hasNext()) {
|
|
|
|
MultiPart* mp = it->next();
|
|
|
|
if (!pkt->sameAddress(mp->pkt))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (queryid != mp->queryid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
it->remove();
|
|
|
|
found = true;
|
|
|
|
|
|
|
|
if (searchid == mp->subid) {
|
2006-04-15 19:55:07 +02:00
|
|
|
tmppkt->merge(mp->pkt);
|
|
|
|
delete mp;
|
2006-03-06 20:13:26 +01:00
|
|
|
searchid++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
it->reset();
|
|
|
|
} while (found && (searchid < subid));
|
|
|
|
|
|
|
|
delete it;
|
|
|
|
|
2006-04-15 19:55:07 +02:00
|
|
|
tmppkt->merge(pkt);
|
2006-03-06 20:13:26 +01:00
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
delete tmppkt;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmppkt;
|
|
|
|
}
|
|
|
|
|
2006-03-07 20:30:11 +01:00
|
|
|
void ModGameSpy1::gc()
|
|
|
|
{
|
2006-04-15 19:55:07 +02:00
|
|
|
Iterator<MultiPart>* it = list.createIterator();
|
2006-03-07 20:30:11 +01:00
|
|
|
long now = time(NULL);
|
|
|
|
char buf[64];
|
|
|
|
|
|
|
|
while (it->hasNext()) {
|
|
|
|
MultiPart* mp = it->next();
|
|
|
|
if (mp->timeout <= now) {
|
|
|
|
mp->pkt->show(buf, sizeof(buf));
|
|
|
|
LogSystem::log(LOG_NOTICE, "ModGameSpy1 gc removed: %s (%d/%d)",
|
|
|
|
buf, mp->queryid, mp->subid);
|
|
|
|
it->remove();
|
2006-04-15 19:55:07 +02:00
|
|
|
delete mp;
|
2006-03-07 20:30:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
delete it;
|
|
|
|
}
|
|
|
|
|
2006-03-06 20:13:26 +01:00
|
|
|
int ModGameSpy1::parse_real(NetPkt* pkt, GameList* glist, int gameid)
|
2006-02-05 16:44:38 +01:00
|
|
|
{
|
2006-03-06 20:13:26 +01:00
|
|
|
int port, offset, pos1, pos2;
|
|
|
|
|
|
|
|
pos1 = pkt->find(0, search_gamename, strlen(search_gamename));
|
|
|
|
pos1 += strlen(search_gamename);
|
|
|
|
|
|
|
|
switch (gameid) {
|
|
|
|
case ID_UT:
|
|
|
|
if (pkt->compare(pos1, reply_ut, strlen(reply_ut)))
|
|
|
|
gameid = ID_UT;
|
|
|
|
|
|
|
|
else if (pkt->compare(pos1, reply_ut2k3, strlen(reply_ut2k4)))
|
|
|
|
gameid = ID_UT2K3;
|
|
|
|
|
|
|
|
else if (pkt->compare(pos1, reply_ut2k4, strlen(reply_ut2k4)))
|
|
|
|
gameid = ID_UT2K4;
|
|
|
|
|
|
|
|
else if (pkt->compare(pos1, reply_aao, strlen(reply_aao)))
|
|
|
|
gameid = ID_AAO;
|
|
|
|
|
|
|
|
else if (pkt->compare(pos1, reply_postal2, strlen(reply_postal2)))
|
|
|
|
return PARSE_ACCEPT_FAKE;
|
|
|
|
|
|
|
|
else
|
|
|
|
return PARSE_REJECT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_BF1942:
|
|
|
|
case ID_BFV:
|
|
|
|
pos2 = pkt->find(0, search_gameid, strlen(search_gameid));
|
|
|
|
pos2 += strlen(search_gameid);
|
|
|
|
|
|
|
|
if (pkt->compare(pos1, reply_bf1942, strlen(reply_bf1942)))
|
|
|
|
gameid = ID_BF1942;
|
|
|
|
|
|
|
|
else if (pkt->compare(pos2, reply_bfv1, strlen(reply_bfv1)))
|
|
|
|
gameid = ID_BFV;
|
|
|
|
|
|
|
|
else if (pkt->compare(pos2, reply_bfv2, strlen(reply_bfv2)))
|
|
|
|
gameid = ID_BFV;
|
|
|
|
|
|
|
|
else if (pkt->compare(pos2, reply_poe, strlen(reply_poe)))
|
|
|
|
gameid = ID_BFV;
|
|
|
|
|
|
|
|
else if (pkt->compare(pos2, reply_opk, strlen(reply_opk)))
|
|
|
|
gameid = ID_BFV;
|
|
|
|
else
|
|
|
|
return PARSE_REJECT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_AVP2:
|
|
|
|
pos2 = pkt->find(0, search_gsgamename, strlen(search_gsgamename));
|
|
|
|
pos2 += strlen(search_gsgamename);
|
|
|
|
|
|
|
|
if (pkt->compare(pos1, reply_avp2, strlen(reply_avp2)))
|
|
|
|
gameid = ID_AVP2;
|
|
|
|
|
|
|
|
else if (pkt->compare(pos2, reply_fear, strlen(reply_fear)))
|
|
|
|
return PARSE_ACCEPT_FAKE;
|
|
|
|
|
|
|
|
else
|
|
|
|
return PARSE_REJECT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_RUNE:
|
|
|
|
if (pkt->compare(pos1, reply_rune, strlen(reply_rune)))
|
|
|
|
gameid = ID_RUNE;
|
|
|
|
else
|
|
|
|
return PARSE_REJECT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_IGI2:
|
|
|
|
if (pkt->compare(pos1, reply_igi2, strlen(reply_igi2)))
|
|
|
|
gameid = ID_IGI2;
|
|
|
|
else
|
|
|
|
return PARSE_REJECT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return PARSE_REJECT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* hostport angabe suchen */
|
|
|
|
offset = pkt->find(0, search_hostport, strlen(search_hostport));
|
|
|
|
if (offset != -1)
|
|
|
|
pkt->parse_int(offset + strlen(search_hostport), &port);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* wenn ein hostport angegeben wurde, und das nicht der src port ist
|
|
|
|
* beide ports in die serverliste uebernehmen
|
|
|
|
*/
|
|
|
|
if ((offset != -1) && (port != pkt->getPort())) {
|
2006-04-15 19:55:07 +02:00
|
|
|
glist->addGame(gameid, pkt, port);
|
2006-03-06 20:13:26 +01:00
|
|
|
|
|
|
|
} else {
|
|
|
|
glist->addGame(gameid, pkt);
|
|
|
|
}
|
|
|
|
return PARSE_ACCEPT;
|
2006-02-05 16:44:38 +01:00
|
|
|
}
|