// all server side masterserver and pinging functionality #include "cube.h" ENetSocket mssock = ENET_SOCKET_NULL; void httpgetsend(ENetAddress &ad, char *hostname, char *req, char *ref, char *agent) { if(ad.host==ENET_HOST_ANY) { printf("looking up %s...\n", hostname); enet_address_set_host(&ad, hostname); 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; sprintf_sd(httpget)("GET %s HTTP/1.0\nHost: %s\nReferer: %s\nUser-Agent: %s\n\n", req, hostname, ref, agent); buf.data = httpget; buf.dataLength = strlen((char *)buf.data); printf("sending request to %s...\n", hostname); enet_socket_send(mssock, NULL, &buf, 1); }; 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; }; }; 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; }; ENetAddress masterserver = { ENET_HOST_ANY, 80 }; int updmaster = 0; string masterbase; string masterpath; uchar masterrep[MAXTRANS]; ENetBuffer masterb; void updatemasterserver(int seconds) { if(seconds>updmaster) // send alive signal to masterserver every hour of uptime { sprintf_sd(path)("%sregister.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; }; }; 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) { sprintf_sd(path)("%sretrieve.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); }; ENetSocket pongsock = ENET_SOCKET_NULL; string serverdesc; void serverms(int mode, int numplayers, int minremain, char *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); string mname; strcpy_s(mname, isfull ? "[FULL] " : ""); strcat_s(mname, smapname); sendstring(mname, p); sendstring(serverdesc, p); buf.dataLength = p - pong; enet_socket_send(pongsock, &addr, &buf, 1); }; }; void servermsinit(const char *master, char *sdesc, bool listen) { const char *mid = strstr(master, "/"); if(!mid) mid = master; strcpy_s(masterpath, mid); strn0cpy(masterbase, master, mid-master+1); strcpy_s(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"); }; };