FossilOrigin-Name: 3e5cb10d19eb7d5dbe346bff2f443f7e112e88ef6e870a30c887083690b71a86
182 lines
4.7 KiB
Text
182 lines
4.7 KiB
Text
// all server side masterserver and pinging functionality
|
|
|
|
#include "cube.h"
|
|
|
|
static ENetSocket mssock = ENET_SOCKET_NULL;
|
|
|
|
static void
|
|
httpgetsend(ENetAddress &ad, OFString *hostname, OFString *req, OFString *ref,
|
|
OFString *agent)
|
|
{
|
|
if (ad.host == ENET_HOST_ANY) {
|
|
[OFStdOut writeFormat:@"looking up %@...\n", hostname];
|
|
@autoreleasepool {
|
|
enet_address_set_host(&ad, hostname.UTF8String);
|
|
}
|
|
if (ad.host == ENET_HOST_ANY)
|
|
return;
|
|
}
|
|
if (mssock != ENET_SOCKET_NULL)
|
|
enet_socket_destroy(mssock);
|
|
mssock = enet_socket_create(ENET_SOCKET_TYPE_STREAM, NULL);
|
|
if (mssock == ENET_SOCKET_NULL) {
|
|
printf("could not open socket\n");
|
|
return;
|
|
}
|
|
if (enet_socket_connect(mssock, &ad) < 0) {
|
|
printf("could not connect\n");
|
|
return;
|
|
}
|
|
ENetBuffer buf;
|
|
OFString *httpget = [OFString stringWithFormat:@"GET %@ HTTP/1.0\n"
|
|
@"Host: %@\n"
|
|
@"Referer: %@\n"
|
|
@"User-Agent: %@\n\n",
|
|
req, hostname, ref, agent];
|
|
buf.data = (void *)httpget.UTF8String;
|
|
buf.dataLength = httpget.UTF8StringLength;
|
|
[OFStdOut writeFormat:@"sending request to %@...\n", hostname];
|
|
enet_socket_send(mssock, NULL, &buf, 1);
|
|
}
|
|
|
|
static void
|
|
httpgetrecieve(ENetBuffer &buf)
|
|
{
|
|
if (mssock == ENET_SOCKET_NULL)
|
|
return;
|
|
enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
|
|
if (enet_socket_wait(mssock, &events, 0) >= 0 && events) {
|
|
int len = enet_socket_receive(mssock, NULL, &buf, 1);
|
|
if (len <= 0) {
|
|
enet_socket_destroy(mssock);
|
|
mssock = ENET_SOCKET_NULL;
|
|
return;
|
|
}
|
|
buf.data = ((char *)buf.data) + len;
|
|
((char *)buf.data)[0] = 0;
|
|
buf.dataLength -= len;
|
|
}
|
|
}
|
|
|
|
static uchar *
|
|
stripheader(uchar *b)
|
|
{
|
|
char *s = strstr((char *)b, "\n\r\n");
|
|
if (!s)
|
|
s = strstr((char *)b, "\n\n");
|
|
return s ? (uchar *)s : b;
|
|
}
|
|
|
|
static ENetAddress masterserver = { ENET_HOST_ANY, 80 };
|
|
static int updmaster = 0;
|
|
static OFString *masterbase;
|
|
static OFString *masterpath;
|
|
static uchar masterrep[MAXTRANS];
|
|
static ENetBuffer masterb;
|
|
|
|
static void
|
|
updatemasterserver(int seconds)
|
|
{
|
|
// send alive signal to masterserver every hour of uptime
|
|
if (seconds > updmaster) {
|
|
@autoreleasepool {
|
|
OFString *path = [OFString
|
|
stringWithFormat:@"%@register.do?action=add",
|
|
masterpath];
|
|
httpgetsend(masterserver, masterbase, path,
|
|
@"cubeserver", @"Cube Server");
|
|
}
|
|
masterrep[0] = 0;
|
|
masterb.data = masterrep;
|
|
masterb.dataLength = MAXTRANS - 1;
|
|
updmaster = seconds + 60 * 60;
|
|
}
|
|
}
|
|
|
|
static void
|
|
checkmasterreply()
|
|
{
|
|
bool busy = mssock != ENET_SOCKET_NULL;
|
|
httpgetrecieve(masterb);
|
|
if (busy && mssock == ENET_SOCKET_NULL)
|
|
printf("masterserver reply: %s\n", stripheader(masterrep));
|
|
}
|
|
|
|
uchar *
|
|
retrieveservers(uchar *buf, int buflen)
|
|
{
|
|
@autoreleasepool {
|
|
OFString *path = [OFString
|
|
stringWithFormat:@"%@retrieve.do?item=list", masterpath];
|
|
httpgetsend(masterserver, masterbase, path, @"cubeserver",
|
|
@"Cube Server");
|
|
}
|
|
ENetBuffer eb;
|
|
buf[0] = 0;
|
|
eb.data = buf;
|
|
eb.dataLength = buflen - 1;
|
|
while (mssock != ENET_SOCKET_NULL)
|
|
httpgetrecieve(eb);
|
|
return stripheader(buf);
|
|
}
|
|
|
|
static ENetSocket pongsock = ENET_SOCKET_NULL;
|
|
static OFString *serverdesc;
|
|
|
|
void
|
|
serverms(int mode, int numplayers, int minremain, OFString *smapname,
|
|
int seconds, bool isfull)
|
|
{
|
|
checkmasterreply();
|
|
updatemasterserver(seconds);
|
|
|
|
// reply all server info requests
|
|
ENetBuffer buf;
|
|
ENetAddress addr;
|
|
uchar pong[MAXTRANS], *p;
|
|
int len;
|
|
enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
|
|
buf.data = pong;
|
|
while (enet_socket_wait(pongsock, &events, 0) >= 0 && events) {
|
|
buf.dataLength = sizeof(pong);
|
|
len = enet_socket_receive(pongsock, &addr, &buf, 1);
|
|
if (len < 0)
|
|
return;
|
|
p = &pong[len];
|
|
putint(p, PROTOCOL_VERSION);
|
|
putint(p, mode);
|
|
putint(p, numplayers);
|
|
putint(p, minremain);
|
|
OFString *mname =
|
|
[OFString stringWithFormat:@"%@%@",
|
|
(isfull ? @"[FULL] " : @""), smapname];
|
|
sendstring(mname, p);
|
|
sendstring(serverdesc, p);
|
|
buf.dataLength = p - pong;
|
|
enet_socket_send(pongsock, &addr, &buf, 1);
|
|
}
|
|
}
|
|
|
|
void
|
|
servermsinit(OFString *master_, OFString *sdesc, bool listen)
|
|
{
|
|
@autoreleasepool {
|
|
const char *master = master_.UTF8String;
|
|
const char *mid = strstr(master, "/");
|
|
if (!mid)
|
|
mid = master;
|
|
masterpath = @(mid);
|
|
masterbase = [[OFString alloc] initWithUTF8String:master
|
|
length:mid - master];
|
|
serverdesc = sdesc;
|
|
|
|
if (listen) {
|
|
ENetAddress address = { ENET_HOST_ANY,
|
|
CUBE_SERVINFO_PORT };
|
|
pongsock = enet_socket_create(
|
|
ENET_SOCKET_TYPE_DATAGRAM, &address);
|
|
if (pongsock == ENET_SOCKET_NULL)
|
|
fatal(@"could not create server info socket\n");
|
|
}
|
|
}
|
|
}
|