From 06da1425b3381617c0d31592b7b24cc66ca70b63 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 1 Mar 2020 02:36:56 -0800 Subject: [PATCH] The big bad HTTP master server Cvars: http_masterserver is the url to the master server's API. masterserver_token may be an authentication token. --- src/Makefile | 3 + src/d_clisrv.c | 3 +- src/hms123311.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++++ src/mserv.c | 56 ++++++++ src/mserv.h | 2 + 5 files changed, 409 insertions(+), 1 deletion(-) create mode 100644 src/hms123311.c diff --git a/src/Makefile b/src/Makefile index fdf9c78b7..160847e09 100644 --- a/src/Makefile +++ b/src/Makefile @@ -324,6 +324,8 @@ else NOPNG=1 endif +LIBS+=-lcurl + ifdef STATIC LIBS:=-static $(LIBS) endif @@ -480,6 +482,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/w_wad.o \ $(OBJDIR)/filesrch.o \ $(OBJDIR)/mserv.o \ + $(OBJDIR)/hms123311.o\ $(OBJDIR)/i_tcp.o \ $(OBJDIR)/lzf.o \ $(OBJDIR)/vid_copy.o \ diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 43321d92d..3455f21c4 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1843,7 +1843,8 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) // Make sure MS version matches our own, to // thwart nefarious servers who lie to the MS. - if (strcmp(version, server_list[i].version) == 0) + /* lol bruh, that version COMES from the servers */ + //if (strcmp(version, server_list[i].version) == 0) { INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port); if (node == -1) diff --git a/src/hms123311.c b/src/hms123311.c new file mode 100644 index 000000000..4ce05bfa0 --- /dev/null +++ b/src/hms123311.c @@ -0,0 +1,346 @@ +// SONIC ROBO BLAST 2 JART +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by James R. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +// \brief HTTP based master server + +#include + +#include "doomdef.h" +#include "d_clisrv.h" +#include "command.h" +#include "mserv.h" +#include "i_tcp.h"/* for current_port */ + +consvar_t cv_http_masterserver = { + "http_masterserver", + "http://www.jameds.org/MS/0", + CV_SAVE, + + NULL, NULL, 0, NULL, NULL, 0, 0, NULL/* C90 moment */ +}; + +consvar_t cv_masterserver_token = { + "masterserver_token", + "", + CV_SAVE, + + NULL, NULL, 0, NULL, NULL, 0, 0, NULL/* C90 moment */ +}; + +static int hms_started; + +static char hms_server_token[sizeof "xxx.xxx.xxx.xxx/xxxxx"]; + +struct HMS_buffer +{ + CURL *curl; + char *buffer; + int needle; + int end; +}; + +static size_t +HMS_on_read (char *s, size_t _1, size_t n, void *userdata) +{ + struct HMS_buffer *buffer; + buffer = userdata; + if (n < ( buffer->end - buffer->needle )) + { + memcpy(&buffer->buffer[buffer->needle], s, n); + buffer->needle += n; + return n; + } + else + return 0; +} + +static struct HMS_buffer * +HMS_connect (const char *format, ...) +{ + va_list ap; + CURL *curl; + char *url; + size_t seek; + struct HMS_buffer *buffer; + + if (! hms_started) + { + curl_global_init(CURL_GLOBAL_ALL); + hms_started = 1; + } + + curl = curl_easy_init(); + + seek = strlen(cv_http_masterserver.string) + 1;/* + '/' */ + + va_start (ap, format); + url = malloc(seek + vsnprintf(0, 0, format, ap) + 1); + va_end (ap); + + sprintf(url, "%s/", cv_http_masterserver.string); + + va_start (ap, format); + vsprintf(&url[seek], format, ap); + va_end (ap); + + CONS_Printf("HMS: connecting '%s'...\n", url); + + buffer = malloc(sizeof *buffer); + buffer->curl = curl; + /* I just allocated 4k and fuck it! */ + buffer->end = 4096; + buffer->buffer = malloc(buffer->end); + buffer->needle = 0; + + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); + + free(url); + + return buffer; +} + +static int +HMS_do (struct HMS_buffer *buffer) +{ + long status; + curl_easy_perform(buffer->curl); + curl_easy_getinfo(buffer->curl, CURLINFO_RESPONSE_CODE, &status); + buffer->buffer[buffer->needle] = '\0'; + if (status != 200) + { + CONS_Alert(CONS_ERROR, + "Master server error %ld: %s", + status, + buffer->buffer + ); + return 0; + } + else + return 1; +} + +static void +HMS_end (struct HMS_buffer *buffer) +{ + free(buffer->buffer); + curl_easy_cleanup(buffer->curl); + free(buffer); +} + +int +HMS_in_use (void) +{ + return cv_http_masterserver.string[0]; +} + +void +HMS_fetch_rooms (void) +{ + struct HMS_buffer *hms; + char *p; + char *end; + + char *id; + char *title; + char *motd; + + int i; + + hms = HMS_connect("rooms?token=%s&verbose", cv_masterserver_token.string); + if (HMS_do(hms)) + { + p = hms->buffer; + for (i = 0; i < NUM_LIST_ROOMS && ( end = strstr(p, "\n\n\n") ); ++i) + { + *end = '\0'; + id = strtok(p, "\n"); + title = strtok(0, "\n"); + motd = strtok(0, ""); + if (id && title && motd) + { + room_list[i].header.buffer[0] = 1; + + room_list[i].id = atoi(id); + strlcpy(room_list[i].name, title, sizeof room_list[i].name); + strlcpy(room_list[i].motd, motd, sizeof room_list[i].motd); + + p = ( end + 3 ); + } + else + break; + } + + room_list[i].header.buffer[0] = 1; + room_list[i].id = 0; + strcpy(room_list[i].name, "All"); + strcpy(room_list[i].motd, "Wildcard."); + + room_list[i + 1].header.buffer[0] = 0; + } + HMS_end(hms); +} + +int +HMS_register (void) +{ + char post[256]; + struct HMS_buffer *hms; + char *title; + int ok; + + hms = HMS_connect("rooms/%d/register?token=%s", + ms_RoomId, + cv_masterserver_token.string + ); + title = curl_easy_escape(hms->curl, cv_servername.string, 0); + sprintf(post, + "port=%d&title=%s", + current_port, + title + ); + curl_easy_setopt(hms->curl, CURLOPT_POSTFIELDS, post); + + ok = HMS_do(hms); + + if (ok) + { + strlcpy(hms_server_token, strtok(hms->buffer, "\n"), + sizeof hms_server_token); + } + + curl_free(title); + HMS_end(hms); + + return ok; +} + +void +HMS_unlist (void) +{ + struct HMS_buffer *hms; + hms = HMS_connect("servers/%s/unlist?token=%s", + hms_server_token, + cv_masterserver_token.string + ); + curl_easy_setopt(hms->curl, CURLOPT_CUSTOMREQUEST, "POST"); + /*curl_easy_setopt(hms->curl, CURLOPT_POSTFIELDS, + cv_masterserver_token.string);*/ + HMS_do(hms); + HMS_end(hms); +} + +void +HMS_update (void) +{ + char post[256]; + struct HMS_buffer *hms; + char *title; + + hms = HMS_connect("servers/%s/update?token=%s", + hms_server_token, + cv_masterserver_token.string + ); + + title = curl_easy_escape(hms->curl, cv_servername.string, 0); + sprintf(post, "title=%s", title); + curl_free(title); + + curl_easy_setopt(hms->curl, CURLOPT_POSTFIELDS, post); + + HMS_do(hms); + HMS_end(hms); +} + +void +HMS_list_servers (void) +{ + struct HMS_buffer *hms; + hms = HMS_connect("servers?token=%s", cv_masterserver_token.string); + HMS_do(hms); + CONS_Printf("%s", hms->buffer); + HMS_end(hms); +} + +void +HMS_fetch_servers (msg_server_t *list, int room_number) +{ + struct HMS_buffer *hms; + char *end; + char *section_end; + char *p; + + char *room; + char *address; + char *port; + char *title; + + int i; + + if (room_number > 0) + { + hms = HMS_connect("rooms/%d/servers?token=%s", + room_number, + cv_masterserver_token.string + ); + } + else + hms = HMS_connect("servers?token=%s", cv_masterserver_token.string); + + if (HMS_do(hms)) + { + p = hms->buffer; + i = 0; + do + { + section_end = strstr(p, "\n\n"); + room = strtok(p, "\n"); + p = strtok(0, ""); + for (; i < MAXSERVERLIST && ( end = strchr(p, '\n') ); ++i) + { + *end = '\0'; + + address = strtok(p, " "); + port = strtok(0, " "); + title = strtok(0, ""); + + if (address && port && title) + { + strlcpy(list[i].ip, address, sizeof list[i].ip); + strlcpy(list[i].port, port, sizeof list[i].port); + strlcpy(list[i].name, title, sizeof list[i].name); + list[i].room = atoi(room); + + list[i].header.buffer[0] = 1; + + if (end == section_end) + { + i++;/* lol */ + break; + } + + p = ( end + 1 ); + } + else + { + section_end = 0; + break; + } + } + p = ( section_end + 2 ); + } + while (section_end) ; + + list[i].header.buffer[0] = 0; + } + + HMS_end(hms); +} diff --git a/src/mserv.c b/src/mserv.c index 05a5344ba..f43468e66 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -68,6 +68,15 @@ #include "i_addrinfo.h" +/* HTTP */ +int HMS_in_use (void); +void HMS_fetch_rooms (void); +int HMS_register (void); +void HMS_unlist (void); +void HMS_update (void); +void HMS_list_servers (void); +void HMS_fetch_servers (msg_server_t *list, int room); + // ================================ DEFINITIONS =============================== #define PACKET_SIZE 1024 @@ -222,6 +231,8 @@ void AddMServCommands(void) { #ifndef NONET CV_RegisterVar(&cv_masterserver); + CV_RegisterVar(&cv_http_masterserver); + CV_RegisterVar(&cv_masterserver_token); CV_RegisterVar(&cv_servername); COM_AddCommand("listserv", Command_Listserv_f); #endif @@ -455,6 +466,12 @@ const msg_server_t *GetShortServersList(INT32 room) msg_t msg; INT32 i; + if (HMS_in_use()) + { + HMS_fetch_servers(server_list, room); + return server_list; + } + // we must be connected to the master server before writing to it if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0)) { @@ -496,6 +513,12 @@ INT32 GetRoomsList(boolean hosting) msg_t msg; INT32 i; + if (HMS_in_use()) + { + HMS_fetch_rooms(); + return 1; + } + // we must be connected to the master server before writing to it if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0)) { @@ -561,6 +584,9 @@ const char *GetMODVersion(void) { static msg_t msg; + if (HMS_in_use()) + return NULL; + // we must be connected to the master server before writing to it if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0)) { @@ -604,6 +630,9 @@ void GetMODVersion_Console(void) { static msg_t msg; + if (HMS_in_use()) + return; + // we must be connected to the master server before writing to it if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0)) { @@ -649,6 +678,12 @@ static void Command_Listserv_f(void) CONS_Printf(M_GetText("Retrieving server list...\n")); + if (HMS_in_use()) + { + HMS_list_servers(); + return; + } + if (MS_Connect(GetMasterServerIP(), GetMasterServerPort(), 0)) { CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n")); @@ -703,6 +738,12 @@ static INT32 AddToMasterServer(boolean firstadd) UINT32 signature, tmp; const char *insname; + if (HMS_in_use()) + { + HMS_update(); + return MS_NO_ERROR; + } + M_Memcpy(&tset, &wset, sizeof (tset)); res = select(255, NULL, &tset, NULL, &select_timeout); if (res != ERRSOCKET && !res) @@ -873,6 +914,13 @@ void RegisterServer(void) CONS_Printf(M_GetText("Registering this server on the Master Server...\n")); + if (HMS_in_use()) + { + if (HMS_register()) + con_state = MSCS_REGISTERED; + return; + } + strcpy(registered_server.ip, GetMasterServerIP()); strcpy(registered_server.port, GetMasterServerPort()); @@ -888,6 +936,8 @@ void RegisterServer(void) static inline void SendPingToMasterServer(void) { + if (HMS_in_use()) + return; /* static tic_t next_time = 0; tic_t cur_time; char *inbuffer = (char*)netbuffer; @@ -973,6 +1023,12 @@ void UnregisterServer(void) CONS_Printf(M_GetText("Removing this server from the Master Server...\n")); + if (HMS_in_use()) + { + HMS_unlist(); + return; + } + if (MS_Connect(registered_server.ip, registered_server.port, 0)) { CONS_Alert(CONS_ERROR, M_GetText("Cannot connect to the Master Server\n")); diff --git a/src/mserv.h b/src/mserv.h index 5f9b8da5f..7c042d42a 100644 --- a/src/mserv.h +++ b/src/mserv.h @@ -64,6 +64,8 @@ typedef struct // ================================ GLOBALS =============================== extern consvar_t cv_masterserver, cv_servername; +extern consvar_t cv_http_masterserver; +extern consvar_t cv_masterserver_token; // < 0 to not connect (usually -1) (offline mode) // == 0 to show all rooms, not a valid hosting room