Artifact 4bb1ac1ee818e2cb87fbf5df048a64d9d50985798e6656f06dbb14a35cb8e2f0:
- File
src/serverms.mm
— part of check-in
[489124a92f]
at
2025-03-16 10:11:39
on branch trunk
— Use one autorelease pool per frame
This way, nowhere else autorelease pools need to be managed. (user: js, size: 4643) [annotate] [blame] [check-ins using]
// 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]; 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) { 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) { 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) { 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"); } }