Merge branch 'http-mserv' into 'master'

Make the HTTP Master Server official

See merge request KartKrew/Kart-Public!193
This commit is contained in:
Sal 2020-08-10 16:49:47 -04:00
commit 06f36224ee
22 changed files with 2070 additions and 980 deletions

View file

@ -35,6 +35,7 @@ set(SRB2_CORE_SOURCES
m_random.c
md5.c
mserv.c
http-mserv.c
s_sound.c
screen.c
sounds.c
@ -99,6 +100,7 @@ set(SRB2_CORE_HEADERS
m_swap.h
md5.h
mserv.h
http-mserv.h
p5prof.h
s_sound.h
screen.h

View file

@ -548,6 +548,7 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/w_wad.o \
$(OBJDIR)/filesrch.o \
$(OBJDIR)/mserv.o \
$(OBJDIR)/http-mserv.o\
$(OBJDIR)/i_tcp.o \
$(OBJDIR)/lzf.o \
$(OBJDIR)/vid_copy.o \

View file

@ -31,6 +31,7 @@
#include "i_video.h"
#include "z_zone.h"
#include "i_system.h"
#include "i_threads.h"
#include "d_main.h"
#include "m_menu.h"
#include "filesrch.h"
@ -45,6 +46,16 @@
#define MAXHUDLINES 20
#ifdef HAVE_THREADS
I_mutex con_mutex;
# define Lock_state() I_lock_mutex(&con_mutex)
# define Unlock_state() I_unlock_mutex(con_mutex)
#else/*HAVE_THREADS*/
# define Lock_state()
# define Unlock_state()
#endif/*HAVE_THREADS*/
static boolean con_started = false; // console has been initialised
boolean con_startup = false; // true at game startup, screen need refreshing
static boolean con_forcepic = true; // at startup toggle console translucency when first off
@ -170,6 +181,8 @@ static void CONS_hudlines_Change(void)
{
INT32 i;
Lock_state();
// Clear the currently displayed lines
for (i = 0; i < con_hudlines; i++)
con_hudtime[i] = 0;
@ -181,6 +194,8 @@ static void CONS_hudlines_Change(void)
con_hudlines = cons_hudlines.value;
Unlock_state();
CONS_Printf(M_GetText("Number of console HUD lines is now %d\n"), con_hudlines);
}
@ -188,12 +203,16 @@ static void CONS_hudlines_Change(void)
//
static void CONS_Clear_f(void)
{
Lock_state();
memset(con_buffer, 0, CON_BUFFERSIZE);
con_cx = 0;
con_cy = con_totallines-1;
con_line = &con_buffer[con_cy*con_width];
con_scrollup = 0;
Unlock_state();
}
// Choose english keymap
@ -369,20 +388,29 @@ void CON_Init(void)
for (i = 0; i < NUMINPUTS; i++)
bindtable[i] = NULL;
Lock_state();
// clear all lines
memset(con_buffer, 0, CON_BUFFERSIZE);
// make sure it is ready for the loading screen
con_width = 0;
Unlock_state();
CON_RecalcSize();
CON_SetupColormaps();
Lock_state();
//note: CON_Ticker should always execute at least once before D_Display()
con_clipviewtop = -1; // -1 does not clip
con_hudlines = atoi(cons_hudlines.defaultvalue);
Unlock_state();
// setup console input filtering
CON_InputInit();
@ -391,15 +419,23 @@ void CON_Init(void)
COM_AddCommand("cls", CONS_Clear_f);
//COM_AddCommand("english", CONS_English_f);
// set console full screen for game startup MAKE SURE VID_Init() done !!!
Lock_state();
con_destlines = vid.height;
con_curlines = vid.height;
Unlock_state();
if (!dedicated)
{
Lock_state();
con_started = true;
con_startup = true; // need explicit screen refresh until we are in Doom loop
consoletoggle = false;
Unlock_state();
CV_RegisterVar(&cons_msgtimeout);
CV_RegisterVar(&cons_hudlines);
CV_RegisterVar(&cons_speed);
@ -411,19 +447,27 @@ void CON_Init(void)
}
else
{
Lock_state();
con_started = true;
con_startup = false; // need explicit screen refresh until we are in Doom loop
consoletoggle = true;
Unlock_state();
}
}
// Console input initialization
//
static void CON_InputInit(void)
{
Lock_state();
// prepare the first prompt line
memset(inputlines, 0, sizeof (inputlines));
inputline = 0;
input_cur = input_sel = input_len = 0;
Unlock_state();
}
//======================================================================
@ -439,6 +483,8 @@ static void CON_RecalcSize(void)
char *tmp_buffer;
char *string;
Lock_state();
switch (cv_constextsize.value)
{
case V_NOSCALEPATCH:
@ -476,11 +522,18 @@ static void CON_RecalcSize(void)
// check for change of video width
if (conw == con_width)
{
Unlock_state();
return; // didn't change
}
Unlock_state();
tmp_buffer = Z_Malloc(CON_BUFFERSIZE, PU_STATIC, NULL);
string = Z_Malloc(CON_BUFFERSIZE, PU_STATIC, NULL); // BP: it is a line but who know
Lock_state();
oldcon_width = con_width;
oldnumlines = con_totallines;
oldcon_cy = con_cy;
@ -501,6 +554,8 @@ static void CON_RecalcSize(void)
con_line = &con_buffer[con_cy*con_width];
con_scrollup = 0;
Unlock_state();
// re-arrange console text buffer to keep text
if (oldcon_width) // not the first time
{
@ -525,7 +580,11 @@ static void CON_RecalcSize(void)
static void CON_ChangeHeight(void)
{
INT32 minheight = 20 * con_scalefactor; // 20 = 8+8+4
INT32 minheight;
Lock_state();
minheight = 20 * con_scalefactor; // 20 = 8+8+4
// toggle console in
con_destlines = (cons_height.value*vid.height)/100;
@ -535,13 +594,19 @@ static void CON_ChangeHeight(void)
con_destlines = vid.height;
con_destlines &= ~0x3; // multiple of text row height
Unlock_state();
}
// Handles Console moves in/out of screen (per frame)
//
static void CON_MoveConsole(void)
{
const fixed_t conspeed = FixedDiv(cons_speed.value*vid.fdupy, FRACUNIT);
fixed_t conspeed;
Lock_state();
conspeed = FixedDiv(cons_speed.value*vid.fdupy, FRACUNIT);
// instant
if (!cons_speed.value)
@ -563,6 +628,8 @@ static void CON_MoveConsole(void)
if (con_curlines < con_destlines)
con_curlines = con_destlines;
}
Unlock_state();
}
INT32 CON_ShiftChar(INT32 ch)
@ -587,27 +654,44 @@ void CON_ClearHUD(void)
{
INT32 i;
Lock_state();
for (i = 0; i < con_hudlines; i++)
con_hudtime[i] = 0;
Unlock_state();
}
// Force console to move out immediately
// note: con_ticker will set consoleready false
void CON_ToggleOff(void)
{
Lock_state();
if (!con_destlines)
{
Unlock_state();
return;
}
con_destlines = 0;
con_curlines = 0;
CON_ClearHUD();
con_forcepic = 0;
con_clipviewtop = -1; // remove console clipping of view
Unlock_state();
}
boolean CON_Ready(void)
{
return consoleready;
boolean ready;
Lock_state();
{
ready = consoleready;
}
Unlock_state();
return ready;
}
// Console ticker: handles console move in/out, cursor blinking
@ -615,7 +699,11 @@ boolean CON_Ready(void)
void CON_Ticker(void)
{
INT32 i;
INT32 minheight = 20 * con_scalefactor; // 20 = 8+8+4
INT32 minheight;
Lock_state();
minheight = 20 * con_scalefactor; // 20 = 8+8+4
// cursor blinking
con_tick++;
@ -673,6 +761,8 @@ void CON_Ticker(void)
if (con_hudtime[i] < 0)
con_hudtime[i] = 0;
}
Unlock_state();
}
//
@ -684,32 +774,51 @@ void CON_Ticker(void)
static void CON_InputClear(void)
{
Lock_state();
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
input_cur = input_sel = input_len = 0;
Unlock_state();
}
static void CON_InputSetString(const char *c)
{
Lock_state();
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
strcpy(inputlines[inputline], c);
input_cur = input_sel = input_len = strlen(c);
Unlock_state();
}
static void CON_InputAddString(const char *c)
{
size_t csize = strlen(c);
Lock_state();
if (input_len + csize > CON_MAXPROMPTCHARS-1)
{
Unlock_state();
return;
}
if (input_cur != input_len)
memmove(&inputlines[inputline][input_cur+csize], &inputlines[inputline][input_cur], input_len-input_cur);
memcpy(&inputlines[inputline][input_cur], c, csize);
input_len += csize;
input_sel = (input_cur += csize);
Unlock_state();
}
static void CON_InputDelSelection(void)
{
size_t start, end, len;
Lock_state();
if (input_cur > input_sel)
{
start = input_sel;
@ -728,27 +837,39 @@ static void CON_InputDelSelection(void)
input_len -= len;
input_sel = input_cur = start;
Unlock_state();
}
static void CON_InputAddChar(char c)
{
if (input_len >= CON_MAXPROMPTCHARS-1)
return;
Lock_state();
if (input_cur != input_len)
memmove(&inputlines[inputline][input_cur+1], &inputlines[inputline][input_cur], input_len-input_cur);
inputlines[inputline][input_cur++] = c;
inputlines[inputline][++input_len] = 0;
input_sel = input_cur;
Unlock_state();
}
static void CON_InputDelChar(void)
{
if (!input_cur)
return;
Lock_state();
if (input_cur != input_len)
memmove(&inputlines[inputline][input_cur-1], &inputlines[inputline][input_cur], input_len-input_cur);
inputlines[inputline][--input_len] = 0;
input_sel = --input_cur;
Unlock_state();
}
//
@ -1174,6 +1295,8 @@ static void CON_Print(char *msg)
S_StartSound(NULL, sfx_radio);
}
Lock_state();
if (!(*msg & 0x80))
{
con_line[con_cx++] = '\x80';
@ -1234,7 +1357,10 @@ static void CON_Print(char *msg)
}
if (*msg == '\0')
{
Unlock_state();
return;
}
// printable character
for (l = 0; l < (con_width-11) && msg[l] > ' '; l++)
@ -1252,6 +1378,8 @@ static void CON_Print(char *msg)
for (; l > 0; l--)
con_line[con_cx++] = *(msg++);
}
Unlock_state();
}
void CON_LogMessage(const char *msg)
@ -1283,6 +1411,7 @@ void CONS_Printf(const char *fmt, ...)
{
va_list argptr;
static char *txt = NULL;
boolean startup;
if (txt == NULL)
txt = malloc(8192);
@ -1315,11 +1444,16 @@ void CONS_Printf(const char *fmt, ...)
CON_LogMessage(txt);
#endif
Lock_state();
// make sure new text is visible
con_scrollup = 0;
startup = con_startup;
Unlock_state();
// if not in display loop, force screen update
if (con_startup)
if (startup)
{
#if (defined (_WINDOWS)) || (defined (__OS2__) && !defined (HAVE_SDL))
patch_t *con_backpic = W_CachePatchName("KARTKREW", PU_CACHE);
@ -1633,8 +1767,13 @@ static void CON_DrawConsole(void)
//
void CON_Drawer(void)
{
Lock_state();
if (!con_started || !graphics_started)
{
Unlock_state();
return;
}
if (con_recalc)
CON_RecalcSize();
@ -1644,4 +1783,6 @@ void CON_Drawer(void)
else if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE || gamestate == GS_CREDITS
|| gamestate == GS_VOTING || gamestate == GS_EVALUATION || gamestate == GS_WAITINGPLAYERS)
CON_DrawHudlines();
Unlock_state();
}

View file

@ -12,6 +12,7 @@
#include "d_event.h"
#include "command.h"
#include "i_threads.h"
#ifdef _WII
void CON_InitWii(void);
@ -21,6 +22,10 @@ void CON_Init(void);
boolean CON_Responder(event_t *ev);
#ifdef HAVE_THREADS
extern I_mutex con_mutex;
#endif
// set true when screen size has changed, to adapt console
extern boolean con_recalc;

View file

@ -76,7 +76,7 @@
boolean server = true; // true or false but !server == client
#define client (!server)
boolean nodownload = false;
static boolean serverrunning = false;
boolean serverrunning = false;
INT32 serverplayer = 0;
char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
@ -1748,7 +1748,7 @@ static void CL_LoadReceivedSavegame(void)
#endif
#ifndef NONET
static void SendAskInfo(INT32 node, boolean viams)
static void SendAskInfo(INT32 node)
{
const tic_t asktime = I_GetTime();
netbuffer->packettype = PT_ASKINFO;
@ -1759,10 +1759,6 @@ static void SendAskInfo(INT32 node, boolean viams)
// now allowed traffic from the host to us in, so once the MS relays
// our address to the host, it'll be able to speak to us.
HSendPacket(node, false, 0, sizeof (askinfo_pak));
// Also speak to the MS.
if (viams && node != 0 && node != BROADCASTADDR)
SendAskInfoViaMS(node, asktime);
}
serverelem_t serverlist[MAXSERVERLIST];
@ -1828,13 +1824,96 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
M_SortServerList();
}
#ifdef HAVE_THREADS
struct Fetch_servers_ctx
{
int room;
int id;
};
static void
Fetch_servers_thread (struct Fetch_servers_ctx *ctx)
{
msg_server_t *server_list;
server_list = GetShortServersList(ctx->room, ctx->id);
if (server_list)
{
I_lock_mutex(&ms_QueryId_mutex);
{
if (ctx->id != ms_QueryId)
{
free(server_list);
server_list = NULL;
}
}
I_unlock_mutex(ms_QueryId_mutex);
if (server_list)
{
I_lock_mutex(&m_menu_mutex);
{
if (m_waiting_mode == M_WAITING_SERVERS)
m_waiting_mode = M_NOT_WAITING;
}
I_unlock_mutex(m_menu_mutex);
I_lock_mutex(&ms_ServerList_mutex);
{
ms_ServerList = server_list;
}
I_unlock_mutex(ms_ServerList_mutex);
}
}
free(ctx);
}
#endif/*HAVE_THREADS*/
void CL_QueryServerList (msg_server_t *server_list)
{
INT32 i;
for (i = 0; server_list[i].header.buffer[0]; i++)
{
// Make sure MS version matches our own, to
// thwart nefarious servers who lie to the MS.
/* 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)
break; // no more node free
SendAskInfo(node);
// Force close the connection so that servers can't eat
// up nodes forever if we never get a reply back from them
// (usually when they've not forwarded their ports).
//
// Don't worry, we'll get in contact with the working
// servers again when they send SERVERINFO to us later!
//
// (Note: as a side effect this probably means every
// server in the list will probably be using the same node (e.g. node 1),
// not that it matters which nodes they use when
// the connections are closed afterwards anyway)
// -- Monster Iestyn 12/11/18
Net_CloseConnection(node|FORCECLOSE);
}
}
}
void CL_UpdateServerList(boolean internetsearch, INT32 room)
{
#ifdef HAVE_THREADS
struct Fetch_servers_ctx *ctx;
#endif
SL_ClearServerList(0);
if (!netgame && I_NetOpenSocket)
{
MSCloseUDPSocket(); // Tidy up before wiping the slate.
if (I_NetOpenSocket())
{
netgame = true;
@ -1844,56 +1923,36 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
// search for local servers
if (netgame)
SendAskInfo(BROADCASTADDR, false);
SendAskInfo(BROADCASTADDR);
if (internetsearch)
{
const msg_server_t *server_list;
INT32 i = -1;
server_list = GetShortServersList(room);
#ifdef HAVE_THREADS
ctx = malloc(sizeof *ctx);
/* This called from M_Refresh so I don't use a mutex */
m_waiting_mode = M_WAITING_SERVERS;
I_lock_mutex(&ms_QueryId_mutex);
{
ctx->id = ms_QueryId;
}
I_unlock_mutex(ms_QueryId_mutex);
ctx->room = room;
I_spawn_thread("fetch-servers", (I_thread_fn)Fetch_servers_thread, ctx);
#else
msg_server_t *server_list;
server_list = GetShortServersList(room, 0);
if (server_list)
{
char version[8] = "";
#if VERSION > 0 || SUBVERSION > 0
snprintf(version, sizeof (version), "%d.%d", VERSION, SUBVERSION);
#else
strcpy(version, GetRevisionString());
CL_QueryServerList(server_list);
free(server_list);
}
#endif
version[sizeof (version) - 1] = '\0';
for (i = 0; server_list[i].header.buffer[0]; i++)
{
// Make sure MS version matches our own, to
// thwart nefarious servers who lie to the MS.
if (strcmp(version, server_list[i].version) == 0)
{
INT32 node = I_NetMakeNodewPort(server_list[i].ip, server_list[i].port);
if (node == -1)
break; // no more node free
SendAskInfo(node, true);
// Force close the connection so that servers can't eat
// up nodes forever if we never get a reply back from them
// (usually when they've not forwarded their ports).
//
// Don't worry, we'll get in contact with the working
// servers again when they send SERVERINFO to us later!
//
// (Note: as a side effect this probably means every
// server in the list will probably be using the same node (e.g. node 1),
// not that it matters which nodes they use when
// the connections are closed afterwards anyway)
// -- Monster Iestyn 12/11/18
Net_CloseConnection(node|FORCECLOSE);
}
}
}
//no server list?(-1) or no servers?(0)
if (!i)
{
; /// TODO: display error or warning?
}
}
}
@ -1974,14 +2033,13 @@ static boolean CL_FinishedFileList(void)
/** Called by CL_ServerConnectionTicker
*
* \param viams ???
* \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit.
* \return False if the connection was aborted
* \sa CL_ServerConnectionTicker
* \sa CL_ConnectToServer
*
*/
static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
{
#ifndef NONET
INT32 i;
@ -2045,7 +2103,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
// Ask the info to the server (askinfo packet)
if (*asksent + NEWTICRATE < I_GetTime())
{
SendAskInfo(servernode, viams);
SendAskInfo(servernode);
*asksent = I_GetTime();
}
#else
@ -2060,7 +2118,6 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
/** Called by CL_ConnectToServer
*
* \param viams ???
* \param tmpsave The name of the gamestate file???
* \param oldtic Used for knowing when to poll events and redraw
* \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit.
@ -2069,7 +2126,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
* \sa CL_ConnectToServer
*
*/
static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic_t *oldtic, tic_t *asksent)
static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic_t *asksent)
{
boolean waitmore;
INT32 i;
@ -2081,7 +2138,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
switch (cl_mode)
{
case CL_SEARCHING:
if (!CL_ServerConnectionSearchTicker(viams, asksent))
if (!CL_ServerConnectionSearchTicker(asksent))
return false;
break;
@ -2246,11 +2303,10 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
/** Use adaptive send using net_bandwidth and stat.sendbytes
*
* \param viams ???
* \todo Better description...
*
*/
static void CL_ConnectToServer(boolean viams)
static void CL_ConnectToServer(void)
{
INT32 pnumnodes, nodewaited = doomcom->numnodes, i;
tic_t oldtic;
@ -2322,9 +2378,9 @@ static void CL_ConnectToServer(boolean viams)
{
// If the connection was aborted for some reason, leave
#ifndef NONET
if (!CL_ServerConnectionTicker(viams, tmpsave, &oldtic, &asksent))
if (!CL_ServerConnectionTicker(tmpsave, &oldtic, &asksent))
#else
if (!CL_ServerConnectionTicker(viams, (char*)NULL, &oldtic, (tic_t *)NULL))
if (!CL_ServerConnectionTicker((char*)NULL, &oldtic, (tic_t *)NULL))
#endif
return;
@ -2505,9 +2561,6 @@ static void Command_ReloadBan(void) //recheck ban.txt
static void Command_connect(void)
{
// Assume we connect directly.
boolean viams = false;
if (COM_Argc() < 2 || *COM_Argv(1) == 0)
{
CONS_Printf(M_GetText(
@ -2541,9 +2594,6 @@ static void Command_connect(void)
if (netgame && !stricmp(COM_Argv(1), "node"))
{
servernode = (SINT8)atoi(COM_Argv(2));
// Use MS to traverse NAT firewalls.
viams = true;
}
else if (netgame)
{
@ -2552,7 +2602,6 @@ static void Command_connect(void)
}
else if (I_NetOpenSocket)
{
MSCloseUDPSocket(); // Tidy up before wiping the slate.
I_NetOpenSocket();
netgame = true;
multiplayer = true;
@ -2581,7 +2630,7 @@ static void Command_connect(void)
}
botingame = false;
botskin = 0;
CL_ConnectToServer(viams);
CL_ConnectToServer();
}
#endif
@ -3626,7 +3675,6 @@ boolean SV_SpawnServer(void)
SV_GenContext();
if (netgame && I_NetOpenSocket)
{
MSCloseUDPSocket(); // Tidy up before wiping the slate.
I_NetOpenSocket();
if (ms_RoomId > 0)
RegisterServer();
@ -3634,7 +3682,7 @@ boolean SV_SpawnServer(void)
// non dedicated server just connect to itself
if (!dedicated)
CL_ConnectToServer(false);
CL_ConnectToServer();
else doomcom->numslots = 1;
}
@ -5460,7 +5508,13 @@ FILESTAMP
if (nowtime > resptime)
{
resptime = nowtime;
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
#endif
M_Ticker();
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
#endif
CON_Ticker();
}
SV_FileSendTicker();

View file

@ -18,6 +18,7 @@
#include "d_netcmd.h"
#include "tables.h"
#include "d_player.h"
#include "mserv.h"
/*
The 'packet version' is used to distinguish packet formats.
@ -531,6 +532,7 @@ typedef enum
} kickreason_t;
extern boolean server;
extern boolean serverrunning;
#define client (!server)
extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH;
@ -577,6 +579,7 @@ void CL_RemoveSplitscreenPlayer(UINT8 p);
void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum);
void CL_RemovePlayer(INT32 playernum, INT32 reason);
void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(boolean internetsearch, INT32 room);
// Is there a game running
boolean Playing(void);

View file

@ -50,6 +50,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
#include "hu_stuff.h"
#include "i_sound.h"
#include "i_system.h"
#include "i_threads.h"
#include "i_video.h"
#include "m_argv.h"
#include "m_menu.h"
@ -196,6 +197,8 @@ void D_ProcessEvents(void)
{
event_t *ev;
boolean eaten;
for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1))
{
ev = &events[eventtail];
@ -217,7 +220,17 @@ void D_ProcessEvents(void)
}
// Menu input
if (M_Responder(ev))
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
#endif
{
eaten = M_Responder(ev);
}
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
#endif
if (eaten)
continue; // menu ate the event
// Demo input:
@ -226,7 +239,17 @@ void D_ProcessEvents(void)
continue; // demo ate the event
// console input
if (CON_Responder(ev))
#ifdef HAVE_THREADS
I_lock_mutex(&con_mutex);
#endif
{
eaten = CON_Responder(ev);
}
#ifdef HAVE_THREADS
I_unlock_mutex(con_mutex);
#endif
if (eaten)
continue; // ate the event
G_Responder(ev);
@ -522,7 +545,13 @@ static void D_Display(void)
if (gamestate != GS_TIMEATTACK)
CON_Drawer();
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
#endif
M_Drawer(); // menu is drawn even on top of everything
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
#endif
// focus lost moved to M_Drawer
//

View file

@ -155,8 +155,8 @@ extern char logfilename[1024];
#else
#define VERSION 1 // Game version
#define SUBVERSION 2 // more precise version number
#define VERSIONSTRING "v1.2"
#define VERSIONSTRINGW L"v1.2"
#define VERSIONSTRING "v1.2 (HTTP MS)"
#define VERSIONSTRINGW L"v1.2 (HTTP MS)"
// Hey! If you change this, add 1 to the MODVERSION below! Otherwise we can't force updates!
// And change CMakeLists.txt, for CMake users!
// AND appveyor.yml, for the build bots!

View file

@ -24,6 +24,7 @@
#include "w_wad.h"
#include "z_zone.h"
#include "i_system.h"
#include "i_threads.h"
#include "m_menu.h"
#include "dehacked.h"
#include "g_input.h"
@ -317,7 +318,13 @@ void F_IntroDrawer(void)
{
I_OsPolling();
I_UpdateNoBlit();
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
#endif
M_Drawer(); // menu is drawn even on top of wipes
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
#endif
I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
}
}

View file

@ -22,6 +22,7 @@
#include "z_zone.h"
#include "i_system.h"
#include "i_threads.h"
#include "m_menu.h"
#include "console.h"
#include "d_main.h"
@ -379,7 +380,15 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
I_UpdateNoBlit();
if (drawMenu)
{
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
#endif
M_Drawer(); // menu is drawn even on top of wipes
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
#endif
}
I_FinishUpdate(); // page flip or blit buffer

675
src/http-mserv.c Normal file
View file

@ -0,0 +1,675 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// 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
/*
Documentation available here.
<http://mb.srb2.org/MS/tools/api/v1/>
*/
#include <curl/curl.h>
#include "doomdef.h"
#include "d_clisrv.h"
#include "command.h"
#include "m_argv.h"
#include "m_menu.h"
#include "mserv.h"
#include "i_tcp.h"/* for current_port */
#include "i_threads.h"
/* reasonable default I guess?? */
#define DEFAULT_BUFFER_SIZE (4096)
/* I just stop myself from making macros anymore. */
#define Blame( ... ) \
CONS_Printf("\x85" __VA_ARGS__)
static void MasterServer_Debug_OnChange (void);
consvar_t cv_masterserver_timeout = {
"masterserver_timeout", "5", CV_SAVE, CV_Unsigned,
NULL, 0, NULL, NULL, 0, 0, NULL/* C90 moment */
};
consvar_t cv_masterserver_debug = {
"masterserver_debug", "Off", CV_SAVE|CV_CALL, CV_OnOff,
MasterServer_Debug_OnChange, 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_api;
#ifdef HAVE_THREADS
static I_mutex hms_api_mutex;
#endif
static char *hms_server_token;
struct HMS_buffer
{
CURL *curl;
char *buffer;
int needle;
int end;
};
static void
Contact_error (void)
{
CONS_Alert(CONS_ERROR,
"There was a problem contacting the master server...\n"
);
}
static size_t
HMS_on_read (char *s, size_t _1, size_t n, void *userdata)
{
struct HMS_buffer *buffer;
size_t blocks;
(void)_1;
buffer = userdata;
if (n >= (size_t)( buffer->end - buffer->needle ))
{
/* resize to next multiple of buffer size */
blocks = ( n / DEFAULT_BUFFER_SIZE + 1 );
buffer->end += ( blocks * DEFAULT_BUFFER_SIZE );
buffer->buffer = realloc(buffer->buffer, buffer->end);
}
memcpy(&buffer->buffer[buffer->needle], s, n);
buffer->needle += n;
return n;
}
static struct HMS_buffer *
HMS_connect (const char *format, ...)
{
va_list ap;
CURL *curl;
char *url;
char *quack_token;
size_t seek;
size_t token_length;
struct HMS_buffer *buffer;
if (! hms_started)
{
if (curl_global_init(CURL_GLOBAL_ALL) != 0)
{
Contact_error();
Blame("From curl_global_init.\n");
return NULL;
}
else
{
atexit(curl_global_cleanup);
hms_started = 1;
}
}
curl = curl_easy_init();
if (! curl)
{
Contact_error();
Blame("From curl_easy_init.\n");
return NULL;
}
if (cv_masterserver_token.string[0])
{
quack_token = curl_easy_escape(curl, cv_masterserver_token.string, 0);
token_length = ( sizeof "?token="-1 )+ strlen(quack_token);
}
else
{
quack_token = NULL;
token_length = 0;
}
#ifdef HAVE_THREADS
I_lock_mutex(&hms_api_mutex);
#endif
seek = strlen(hms_api) + 1;/* + '/' */
va_start (ap, format);
url = malloc(seek + vsnprintf(0, 0, format, ap) + token_length + 1);
va_end (ap);
sprintf(url, "%s/", hms_api);
#ifdef HAVE_THREADS
I_unlock_mutex(hms_api_mutex);
#endif
va_start (ap, format);
seek += vsprintf(&url[seek], format, ap);
va_end (ap);
if (quack_token)
sprintf(&url[seek], "?token=%s", quack_token);
CONS_Printf("HMS: connecting '%s'...\n", url);
buffer = malloc(sizeof *buffer);
buffer->curl = curl;
buffer->end = DEFAULT_BUFFER_SIZE;
buffer->buffer = malloc(buffer->end);
buffer->needle = 0;
if (cv_masterserver_debug.value)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_STDERR, logstream);
}
if (M_CheckParm("-bindaddr") && M_IsNextParm())
{
curl_easy_setopt(curl, CURLOPT_INTERFACE, M_GetNextParm());
}
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer);
curl_free(quack_token);
free(url);
return buffer;
}
static int
HMS_do (struct HMS_buffer *buffer)
{
CURLcode cc;
long status;
char *p;
cc = curl_easy_perform(buffer->curl);
if (cc != CURLE_OK)
{
Contact_error();
Blame(
"From curl_easy_perform: %s\n",
curl_easy_strerror(cc)
);
return 0;
}
buffer->buffer[buffer->needle] = '\0';
curl_easy_getinfo(buffer->curl, CURLINFO_RESPONSE_CODE, &status);
if (status != 200)
{
p = strchr(buffer->buffer, '\n');
if (p)
*p = '\0';
Contact_error();
Blame(
"Master server error %ld: %s%s\n",
status,
buffer->buffer,
( (p) ? "" : " (malformed)" )
);
return 0;
}
else
return 1;
}
static void
HMS_end (struct HMS_buffer *buffer)
{
curl_easy_cleanup(buffer->curl);
free(buffer->buffer);
free(buffer);
}
int
HMS_fetch_rooms (int joining, int query_id)
{
struct HMS_buffer *hms;
int ok;
int doing_shit;
char *id;
char *title;
char *room_motd;
int id_no;
char *p;
char *end;
int i;
(void)query_id;
hms = HMS_connect("rooms");
if (! hms)
return 0;
if (HMS_do(hms))
{
doing_shit = 1;
p = hms->buffer;
for (i = 0; i < NUM_LIST_ROOMS && ( end = strstr(p, "\n\n\n") );)
{
*end = '\0';
id = strtok(p, "\n");
title = strtok(0, "\n");
room_motd = strtok(0, "");
if (id && title && room_motd)
{
id_no = atoi(id);
/*
Don't show the 'All' room if hosting. And it's a hack like this
because I'm way too lazy to add another feature to the MS.
*/
if (joining || id_no != 0)
{
#ifdef HAVE_THREADS
I_lock_mutex(&ms_QueryId_mutex);
{
if (query_id != ms_QueryId)
doing_shit = 0;
}
I_unlock_mutex(ms_QueryId_mutex);
if (! doing_shit)
break;
#endif
room_list[i].header.buffer[0] = 1;
room_list[i].id = id_no;
strlcpy(room_list[i].name, title, sizeof room_list[i].name);
strlcpy(room_list[i].motd, room_motd, sizeof room_list[i].motd);
i++;
}
p = ( end + 3 );/* skip the three linefeeds */
}
else
break;
}
if (doing_shit)
room_list[i].header.buffer[0] = 0;
ok = 1;
if (doing_shit)
{
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
#endif
{
for (i = 0; room_list[i].header.buffer[0]; i++)
{
if(*room_list[i].name != '\0')
{
MP_RoomMenu[i+1].text = room_list[i].name;
roomIds[i] = room_list[i].id;
MP_RoomMenu[i+1].status = IT_STRING|IT_CALL;
}
}
}
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
#endif
}
}
else
ok = 0;
HMS_end(hms);
return ok;
}
int
HMS_register (void)
{
struct HMS_buffer *hms;
int ok;
char post[256];
char *title;
hms = HMS_connect("rooms/%d/register", ms_RoomId);
if (! hms)
return 0;
title = curl_easy_escape(hms->curl, cv_servername.string, 0);
snprintf(post, sizeof post,
"port=%d&"
"title=%s&"
"version=%d.%d",
current_port,
title,
VERSION,
SUBVERSION
);
curl_free(title);
curl_easy_setopt(hms->curl, CURLOPT_POSTFIELDS, post);
ok = HMS_do(hms);
if (ok)
{
hms_server_token = strdup(strtok(hms->buffer, "\n"));
}
HMS_end(hms);
return ok;
}
int
HMS_unlist (void)
{
struct HMS_buffer *hms;
int ok;
hms = HMS_connect("servers/%s/unlist", hms_server_token);
if (! hms)
return 0;
curl_easy_setopt(hms->curl, CURLOPT_CUSTOMREQUEST, "POST");
ok = HMS_do(hms);
HMS_end(hms);
free(hms_server_token);
return ok;
}
int
HMS_update (void)
{
struct HMS_buffer *hms;
int ok;
char post[256];
char *title;
hms = HMS_connect("servers/%s/update", hms_server_token);
if (! hms)
return 0;
title = curl_easy_escape(hms->curl, cv_servername.string, 0);
snprintf(post, sizeof post,
"title=%s",
title
);
curl_free(title);
curl_easy_setopt(hms->curl, CURLOPT_POSTFIELDS, post);
ok = HMS_do(hms);
HMS_end(hms);
return ok;
}
void
HMS_list_servers (void)
{
struct HMS_buffer *hms;
char *p;
hms = HMS_connect("servers");
if (! hms)
return;
if (HMS_do(hms))
{
p = &hms->buffer[strlen(hms->buffer)];
while (*--p == '\n')
;
CONS_Printf("%s\n", hms->buffer);
}
HMS_end(hms);
}
msg_server_t *
HMS_fetch_servers (msg_server_t *list, int room_number, int query_id)
{
struct HMS_buffer *hms;
int doing_shit;
char local_version[9];
char *room;
char *address;
char *port;
char *title;
char *version;
char *end;
char *section_end;
char *p;
int i;
(void)query_id;
if (room_number > 0)
{
hms = HMS_connect("rooms/%d/servers", room_number);
}
else
hms = HMS_connect("servers");
if (! hms)
return NULL;
if (HMS_do(hms))
{
doing_shit = 1;
snprintf(local_version, sizeof local_version,
"%d.%d",
VERSION,
SUBVERSION
);
p = hms->buffer;
i = 0;
do
{
section_end = strstr(p, "\n\n");
room = strtok(p, "\n");
p = strtok(0, "");
if (! p)
break;
while (i < MAXSERVERLIST && ( end = strchr(p, '\n') ))
{
*end = '\0';
address = strtok(p, " ");
port = strtok(0, " ");
title = strtok(0, " ");
version = strtok(0, "");
if (address && port && title && version)
{
#ifdef HAVE_THREADS
I_lock_mutex(&ms_QueryId_mutex);
{
if (query_id != ms_QueryId)
doing_shit = 0;
}
I_unlock_mutex(ms_QueryId_mutex);
if (! doing_shit)
break;
#endif
if (strcmp(version, local_version) == 0)
{
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);
strlcpy(list[i].version, version, sizeof list[i].version);
list[i].room = atoi(room);
list[i].header.buffer[0] = 1;
i++;
}
if (end == section_end)/* end of list for this room */
break;
else
p = ( end + 1 );/* skip server delimiter */
}
else
{
section_end = 0;/* malformed so quit the parsing */
break;
}
}
if (! doing_shit)
break;
p = ( section_end + 2 );
}
while (section_end) ;
if (doing_shit)
list[i].header.buffer[0] = 0;
}
else
list = NULL;
HMS_end(hms);
return list;
}
int
HMS_compare_mod_version (char *buffer, size_t buffer_size)
{
struct HMS_buffer *hms;
int ok;
char *version;
char *version_name;
hms = HMS_connect("versions/%d", MODID);
if (! hms)
return 0;
ok = 0;
if (HMS_do(hms))
{
version = strtok(hms->buffer, " ");
version_name = strtok(0, "\n");
if (version && version_name)
{
if (atoi(version) != MODVERSION)
{
strlcpy(buffer, version_name, buffer_size);
ok = 1;
}
else
ok = -1;
}
}
HMS_end(hms);
return ok;
}
void
HMS_set_api (char *api)
{
#ifdef HAVE_THREADS
I_lock_mutex(&hms_api_mutex);
#endif
{
free(hms_api);
hms_api = api;
}
#ifdef HAVE_THREADS
I_unlock_mutex(hms_api_mutex);
#endif
}
static void
MasterServer_Debug_OnChange (void)
{
/* TODO: change to 'latest-log.txt' for log files revision. */
if (cv_masterserver_debug.value)
CONS_Printf("Master server debug messages will appear in log.txt\n");
}

39
src/i_threads.h Normal file
View file

@ -0,0 +1,39 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
/// \file i_threads.h
/// \brief Multithreading abstraction
#ifdef HAVE_THREADS
#ifndef I_THREADS_H
#define I_THREADS_H
typedef void (*I_thread_fn)(void *userdata);
typedef void * I_mutex;
typedef void * I_cond;
void I_start_threads (void);
void I_stop_threads (void);
void I_spawn_thread (const char *name, I_thread_fn, void *userdata);
/* check in your thread whether to return early */
int I_thread_is_stopped (void);
void I_lock_mutex (I_mutex *);
void I_unlock_mutex (I_mutex);
void I_hold_cond (I_cond *, I_mutex);
void I_wake_one_cond (I_cond *);
void I_wake_all_cond (I_cond *);
#endif/*I_THREADS_H*/
#endif/*HAVE_THREADS*/

View file

@ -32,6 +32,7 @@
#include "sounds.h"
#include "s_sound.h"
#include "i_system.h"
#include "i_threads.h"
// Addfile
#include "filesrch.h"
@ -118,6 +119,12 @@ typedef enum
NUM_QUITMESSAGES
} text_enum;
#ifdef HAVE_THREADS
I_mutex m_menu_mutex;
#endif
M_waiting_mode_t m_waiting_mode = M_NOT_WAITING;
const char *quitmsg[NUM_QUITMESSAGES];
// Stuff for customizing the player select screen Tails 09-22-2003
@ -1039,7 +1046,7 @@ enum
FIRSTSERVERLINE
};
static menuitem_t MP_RoomMenu[] =
menuitem_t MP_RoomMenu[] =
{
{IT_STRING | IT_CALL, NULL, "<Offline Mode>", M_ChooseRoom, 9},
{IT_DISABLED, NULL, "", M_ChooseRoom, 18},
@ -2896,7 +2903,6 @@ boolean M_Responder(event_t *ev)
//make sure the game doesn't still think we're in a netgame.
if (!Playing() && netgame && multiplayer)
{
MSCloseUDPSocket(); // Clean up so we can re-open the connection later.
netgame = false;
multiplayer = false;
}
@ -3304,6 +3310,30 @@ void M_SetupNextMenu(menu_t *menudef)
{
INT16 i;
#ifdef HAVE_THREADS
if (currentMenu == &MP_RoomDef || currentMenu == &MP_ConnectDef)
{
I_lock_mutex(&ms_QueryId_mutex);
{
ms_QueryId++;
}
I_unlock_mutex(ms_QueryId_mutex);
}
if (currentMenu == &MP_ConnectDef)
{
I_lock_mutex(&ms_ServerList_mutex);
{
if (ms_ServerList)
{
free(ms_ServerList);
ms_ServerList = NULL;
}
}
I_unlock_mutex(ms_ServerList_mutex);
}
#endif/*HAVE_THREADS*/
if (currentMenu->quitroutine)
{
// If you're going from a menu to itself, why are you running the quitroutine? You're not quitting it! -SH
@ -3361,6 +3391,19 @@ void M_Ticker(void)
if (--vidm_testingmode == 0)
setmodeneeded = vidm_previousmode + 1;
}
#ifdef HAVE_THREADS
I_lock_mutex(&ms_ServerList_mutex);
{
if (ms_ServerList)
{
CL_QueryServerList(ms_ServerList);
free(ms_ServerList);
ms_ServerList = NULL;
}
}
I_unlock_mutex(ms_ServerList_mutex);
#endif
}
//
@ -8327,22 +8370,65 @@ static INT32 menuRoomIndex = 0;
static void M_DrawRoomMenu(void)
{
static int frame = -12;
int dot_frame;
char text[4];
const char *rmotd;
const char *waiting_message;
int dots;
if (m_waiting_mode)
{
dot_frame = frame / 4;
dots = dot_frame + 3;
strcpy(text, " ");
if (dots > 0)
{
if (dot_frame < 0)
dot_frame = 0;
strncpy(&text[dot_frame], "...", min(dots, 3 - dot_frame));
}
if (++frame == 12)
frame = -12;
currentMenu->menuitems[0].text = text;
}
// use generic drawer for cursor, items and title
M_DrawGenericMenu();
V_DrawString(currentMenu->x - 16, currentMenu->y, highlightflags, M_GetText("Select a room"));
M_DrawTextBox(144, 24, 20, 20);
if (m_waiting_mode == M_NOT_WAITING)
{
M_DrawTextBox(144, 24, 20, 20);
if (itemOn == 0)
rmotd = M_GetText("Don't connect to the Master Server.");
else
rmotd = room_list[itemOn-1].motd;
if (itemOn == 0)
rmotd = M_GetText("Don't connect to the Master Server.");
else
rmotd = room_list[itemOn-1].motd;
rmotd = V_WordWrap(0, 20*8, 0, rmotd);
V_DrawString(144+8, 32, V_ALLOWLOWERCASE|V_RETURN8, rmotd);
rmotd = V_WordWrap(0, 20*8, 0, rmotd);
V_DrawString(144+8, 32, V_ALLOWLOWERCASE|V_RETURN8, rmotd);
}
if (m_waiting_mode)
{
// Display a little "please wait" message.
M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
if (m_waiting_mode == M_WAITING_VERSION)
waiting_message = "Checking for updates...";
else
waiting_message = "Fetching room info...";
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, waiting_message);
V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
}
}
static void M_DrawConnectMenu(void)
@ -8416,6 +8502,14 @@ static void M_DrawConnectMenu(void)
localservercount = serverlistcount;
M_DrawGenericMenu();
if (m_waiting_mode)
{
// Display a little "please wait" message.
M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "Searching for servers...");
V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
}
}
static boolean M_CancelConnect(void)
@ -8497,10 +8591,10 @@ void M_SortServerList(void)
#ifndef NONET
#ifdef UPDATE_ALERT
static boolean M_CheckMODVersion(void)
static boolean M_CheckMODVersion(int id)
{
char updatestring[500];
const char *updatecheck = GetMODVersion();
const char *updatecheck = GetMODVersion(id);
if(updatecheck)
{
sprintf(updatestring, UPDATE_ALERT_STRING, VERSIONSTRING, updatecheck);
@ -8509,7 +8603,62 @@ static boolean M_CheckMODVersion(void)
} else
return true;
}
#endif
#ifdef HAVE_THREADS
static void
Check_new_version_thread (int *id)
{
int hosting;
int okay;
okay = 0;
if (M_CheckMODVersion(*id))
{
I_lock_mutex(&ms_QueryId_mutex);
{
okay = ( *id == ms_QueryId );
}
I_unlock_mutex(ms_QueryId_mutex);
if (okay)
{
I_lock_mutex(&m_menu_mutex);
{
m_waiting_mode = M_WAITING_ROOMS;
hosting = ( currentMenu->prevMenu == &MP_ServerDef );
}
I_unlock_mutex(m_menu_mutex);
GetRoomsList(hosting, *id);
}
}
else
{
I_lock_mutex(&ms_QueryId_mutex);
{
okay = ( *id == ms_QueryId );
}
I_unlock_mutex(ms_QueryId_mutex);
}
if (okay)
{
I_lock_mutex(&m_menu_mutex);
{
if (m_waiting_mode)
{
m_waiting_mode = M_NOT_WAITING;
MP_RoomMenu[0].text = "<Offline Mode>";
}
}
I_unlock_mutex(m_menu_mutex);
}
free(id);
}
#endif/*HAVE_THREADS*/
#endif/*UPDATE_ALERT*/
static void M_ConnectMenu(INT32 choice)
{
@ -8545,11 +8694,14 @@ static void M_ConnectMenuModChecks(INT32 choice)
M_ConnectMenu(-1);
}
static UINT32 roomIds[NUM_LIST_ROOMS];
UINT32 roomIds[NUM_LIST_ROOMS];
static void M_RoomMenu(INT32 choice)
{
INT32 i;
#ifdef HAVE_THREADS
int *id;
#endif
(void)choice;
@ -8562,34 +8714,47 @@ static void M_RoomMenu(INT32 choice)
if (rendermode == render_soft)
I_FinishUpdate(); // page flip or blit buffer
if (GetRoomsList(currentMenu == &MP_ServerDef) < 0)
return;
#ifdef UPDATE_ALERT
if (!M_CheckMODVersion())
return;
#endif
for (i = 1; i < NUM_LIST_ROOMS+1; ++i)
MP_RoomMenu[i].status = IT_DISABLED;
memset(roomIds, 0, sizeof(roomIds));
for (i = 0; room_list[i].header.buffer[0]; i++)
{
if(*room_list[i].name != '\0')
{
MP_RoomMenu[i+1].text = room_list[i].name;
roomIds[i] = room_list[i].id;
MP_RoomMenu[i+1].status = IT_STRING|IT_CALL;
}
}
MP_RoomDef.prevMenu = currentMenu;
M_SetupNextMenu(&MP_RoomDef);
#ifdef UPDATE_ALERT
#ifdef HAVE_THREADS
m_waiting_mode = M_WAITING_VERSION;
MP_RoomMenu[0].text = "";
id = malloc(sizeof *id);
I_lock_mutex(&ms_QueryId_mutex);
{
*id = ms_QueryId;
}
I_unlock_mutex(ms_QueryId_mutex);
I_spawn_thread("check-new-version",
(I_thread_fn)Check_new_version_thread, id);
#else/*HAVE_THREADS*/
if (M_CheckMODVersion(0))
{
GetRoomsList(currentMenu->prevMenu == &MP_ServerDef, 0);
}
#endif/*HAVE_THREADS*/
#endif/*UPDATE_ALERT*/
}
static void M_ChooseRoom(INT32 choice)
{
#ifdef HAVE_THREADS
I_lock_mutex(&ms_QueryId_mutex);
{
ms_QueryId++;
}
I_unlock_mutex(ms_QueryId_mutex);
#endif
if (choice == 0)
ms_RoomId = -1;
else

View file

@ -17,6 +17,8 @@
#include "d_event.h"
#include "command.h"
#include "i_threads.h"
#include "mserv.h"
#include "r_things.h" // for SKINNAMESIZE
//
@ -72,6 +74,18 @@ typedef enum
} menumessagetype_t;
void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype);
typedef enum
{
M_NOT_WAITING,
M_WAITING_VERSION,
M_WAITING_ROOMS,
M_WAITING_SERVERS,
}
M_waiting_mode_t;
extern M_waiting_mode_t m_waiting_mode;
// Called by linux_x/i_video_xshm.c
void M_QuitResponse(INT32 ch);
@ -161,6 +175,9 @@ typedef struct menuitem_s
extern menuitem_t PlayerMenu[MAXSKINS];
extern menuitem_t MP_RoomMenu[];
extern UINT32 roomIds[NUM_LIST_ROOMS];
typedef struct menu_s
{
const char *menutitlepic;
@ -176,6 +193,10 @@ typedef struct menu_s
void M_SetupNextMenu(menu_t *menudef);
void M_ClearMenus(boolean callexitmenufunc);
#ifdef HAVE_THREADS
extern I_mutex m_menu_mutex;
#endif
extern menu_t *currentMenu;
extern menu_t MainDef;

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2018 by Sonic Team Junior.
// Copyright (C) 2020 by James R.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -13,7 +14,7 @@
#ifndef _MSERV_H_
#define _MSERV_H_
#define MASTERSERVERS21 // MasterServer v2.1
#include "i_threads.h"
// lowered from 32 due to menu changes
#define NUM_LIST_ROOMS 16
@ -64,33 +65,47 @@ typedef struct
// ================================ GLOBALS ===============================
extern consvar_t cv_masterserver, cv_servername;
extern consvar_t cv_masterserver_update_rate;
extern consvar_t cv_masterserver_timeout;
extern consvar_t cv_masterserver_debug;
extern consvar_t cv_masterserver_token;
// < 0 to not connect (usually -1) (offline mode)
// == 0 to show all rooms, not a valid hosting room
// anything else is whatever room the MS assigns to that number (online mode)
extern INT16 ms_RoomId;
const char *GetMasterServerPort(void);
const char *GetMasterServerIP(void);
#ifdef HAVE_THREADS
extern int ms_QueryId;
extern I_mutex ms_QueryId_mutex;
void MSOpenUDPSocket(void);
void MSCloseUDPSocket(void);
void SendAskInfoViaMS(INT32 node, tic_t asktime);
extern msg_server_t *ms_ServerList;
extern I_mutex ms_ServerList_mutex;
#endif
void RegisterServer(void);
void UnregisterServer(void);
void MasterClient_Ticker(void);
const msg_server_t *GetShortServersList(INT32 room);
INT32 GetRoomsList(boolean hosting);
msg_server_t *GetShortServersList(INT32 room, int id);
INT32 GetRoomsList(boolean hosting, int id);
#ifdef UPDATE_ALERT
const char *GetMODVersion(void);
char *GetMODVersion(int id);
void GetMODVersion_Console(void);
#endif
extern msg_rooms_t room_list[NUM_LIST_ROOMS+1];
void AddMServCommands(void);
/* HTTP */
void HMS_set_api (char *api);
int HMS_fetch_rooms (int joining, int id);
int HMS_register (void);
int HMS_unlist (void);
int HMS_update (void);
void HMS_list_servers (void);
msg_server_t * HMS_fetch_servers (msg_server_t *list, int room, int id);
int HMS_compare_mod_version (char *buffer, size_t size_of_buffer);
#endif

View file

@ -83,6 +83,11 @@ else
SDL_LDFLAGS+=-lSDL2_mixer
endif
ifndef NOTHREADS
OPTS+=-DHAVE_THREADS
OBJS+=$(OBJDIR)/i_threads.o
endif
ifdef SDL_TTF
OPTS+=-DHAVE_TTF
SDL_LDFLAGS+=-lSDL2_ttf -lfreetype -lz

View file

@ -249,6 +249,7 @@
<ClInclude Include="..\lzf.h" />
<ClInclude Include="..\md5.h" />
<ClInclude Include="..\mserv.h" />
<ClInclude Include="..\http-mserv.h" />
<ClInclude Include="..\m_aatree.h" />
<ClInclude Include="..\m_anigif.h" />
<ClInclude Include="..\m_argv.h" />
@ -399,6 +400,7 @@
<ClCompile Include="..\lzf.c" />
<ClCompile Include="..\md5.c" />
<ClCompile Include="..\mserv.c" />
<ClCompile Include="..\http-mserv.c" />
<ClCompile Include="..\m_aatree.c" />
<ClCompile Include="..\m_anigif.c" />
<ClCompile Include="..\m_argv.c" />

View file

@ -291,6 +291,9 @@
<ClInclude Include="..\mserv.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\http-mserv.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\lua_hook.h">
<Filter>LUA</Filter>
</ClInclude>
@ -663,6 +666,9 @@
<ClCompile Include="..\mserv.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\http-mserv.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\lua_baselib.c">
<Filter>LUA</Filter>
</ClCompile>

View file

@ -2782,6 +2782,50 @@
RelativePath="..\mserv.h"
>
</File>
<File
RelativePath="..\http-mserv.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File
RelativePath="..\http-mserv.h"
>
</File>
</Filter>
<Filter
Name="M_Misc"

View file

@ -168,6 +168,7 @@ static char returnWadPath[256];
#include "../i_video.h"
#include "../i_sound.h"
#include "../i_system.h"
#include "../i_threads.h"
#include "../screen.h" //vid.WndParent
#include "../d_net.h"
#include "../g_game.h"
@ -3134,6 +3135,10 @@ INT32 I_StartupSystem(void)
SDL_version SDLlinked;
SDL_VERSION(&SDLcompiled)
SDL_GetVersion(&SDLlinked);
#ifdef HAVE_THREADS
I_start_threads();
I_AddExitFunc(I_stop_threads);
#endif
I_StartupConsole();
#ifdef NEWSIGNALHANDLER
I_Fork();

356
src/sdl/i_threads.c Normal file
View file

@ -0,0 +1,356 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
/// \file i_threads.c
/// \brief Multithreading abstraction
#include "../doomdef.h"
#include "../i_threads.h"
#include <SDL.h>
typedef void * (*Create_fn)(void);
struct Link;
struct Thread;
typedef struct Link * Link;
typedef struct Thread * Thread;
struct Link
{
void * data;
Link next;
Link prev;
};
struct Thread
{
I_thread_fn entry;
void * userdata;
SDL_Thread * thread;
};
static Link i_thread_pool;
static Link i_mutex_pool;
static Link i_cond_pool;
static I_mutex i_thread_pool_mutex;
static I_mutex i_mutex_pool_mutex;
static I_mutex i_cond_pool_mutex;
static SDL_atomic_t i_threads_running = {1};
static Link
Insert_link (
Link * head,
Link link
){
link->prev = NULL;
link->next = (*head);
if ((*head))
(*head)->prev = link;
(*head) = link;
return link;
}
static void
Free_link (
Link * head,
Link link
){
if (link->prev)
link->prev->next = link->next;
else
(*head) = link->next;
if (link->next)
link->next->prev = link->prev;
free(link->data);
free(link);
}
static Link
New_link (void *data)
{
Link link;
link = malloc(sizeof *link);
if (! link)
abort();
link->data = data;
return link;
}
static void *
Identity (
Link * pool_anchor,
I_mutex pool_mutex,
void ** anchor,
Create_fn create_fn
){
void * id;
id = SDL_AtomicGetPtr(anchor);
if (! id)
{
I_lock_mutex(&pool_mutex);
{
id = SDL_AtomicGetPtr(anchor);
if (! id)
{
id = (*create_fn)();
if (! id)
abort();
Insert_link(pool_anchor, New_link(id));
SDL_AtomicSetPtr(anchor, id);
}
}
I_unlock_mutex(pool_mutex);
}
return id;
}
static int
Worker (
Link link
){
Thread th;
th = link->data;
(*th->entry)(th->userdata);
if (SDL_AtomicGet(&i_threads_running))
{
I_lock_mutex(&i_thread_pool_mutex);
{
if (SDL_AtomicGet(&i_threads_running))
{
SDL_DetachThread(th->thread);
Free_link(&i_thread_pool, link);
}
}
I_unlock_mutex(i_thread_pool_mutex);
}
return 0;
}
void
I_spawn_thread (
const char * name,
I_thread_fn entry,
void * userdata
){
Link link;
Thread th;
th = malloc(sizeof *th);
if (! th)
abort();/* this is pretty GNU of me */
th->entry = entry;
th->userdata = userdata;
I_lock_mutex(&i_thread_pool_mutex);
{
link = Insert_link(&i_thread_pool, New_link(th));
if (SDL_AtomicGet(&i_threads_running))
{
th->thread = SDL_CreateThread(
(SDL_ThreadFunction)Worker,
name,
link
);
if (! th->thread)
abort();
}
}
I_unlock_mutex(i_thread_pool_mutex);
}
int
I_thread_is_stopped (void)
{
return ( ! SDL_AtomicGet(&i_threads_running) );
}
void
I_start_threads (void)
{
i_thread_pool_mutex = SDL_CreateMutex();
i_mutex_pool_mutex = SDL_CreateMutex();
i_cond_pool_mutex = SDL_CreateMutex();
if (!(
i_thread_pool_mutex &&
i_mutex_pool_mutex &&
i_cond_pool_mutex
)){
abort();
}
}
void
I_stop_threads (void)
{
Link link;
Link next;
Thread th;
SDL_mutex * mutex;
SDL_cond * cond;
if (i_threads_running.value)
{
/* rely on the good will of thread-san */
SDL_AtomicSet(&i_threads_running, 0);
I_lock_mutex(&i_thread_pool_mutex);
{
for (
link = i_thread_pool;
link;
link = next
){
next = link->next;
th = link->data;
SDL_WaitThread(th->thread, NULL);
free(th);
free(link);
}
}
I_unlock_mutex(i_thread_pool_mutex);
for (
link = i_mutex_pool;
link;
link = next
){
next = link->next;
mutex = link->data;
SDL_DestroyMutex(mutex);
free(link);
}
for (
link = i_cond_pool;
link;
link = next
){
next = link->next;
cond = link->data;
SDL_DestroyCond(cond);
free(link);
}
SDL_DestroyMutex(i_thread_pool_mutex);
SDL_DestroyMutex(i_mutex_pool_mutex);
SDL_DestroyMutex(i_cond_pool_mutex);
}
}
void
I_lock_mutex (
I_mutex * anchor
){
SDL_mutex * mutex;
mutex = Identity(
&i_mutex_pool,
i_mutex_pool_mutex,
anchor,
(Create_fn)SDL_CreateMutex
);
if (SDL_LockMutex(mutex) == -1)
abort();
}
void
I_unlock_mutex (
I_mutex id
){
if (SDL_UnlockMutex(id) == -1)
abort();
}
void
I_hold_cond (
I_cond * cond_anchor,
I_mutex mutex_id
){
SDL_cond * cond;
cond = Identity(
&i_cond_pool,
i_cond_pool_mutex,
cond_anchor,
(Create_fn)SDL_CreateCond
);
if (SDL_CondWait(cond, mutex_id) == -1)
abort();
}
void
I_wake_one_cond (
I_cond * anchor
){
SDL_cond * cond;
cond = Identity(
&i_cond_pool,
i_cond_pool_mutex,
anchor,
(Create_fn)SDL_CreateCond
);
if (SDL_CondSignal(cond) == -1)
abort();
}
void
I_wake_all_cond (
I_cond * anchor
){
SDL_cond * cond;
cond = Identity(
&i_cond_pool,
i_cond_pool_mutex,
anchor,
(Create_fn)SDL_CreateCond
);
if (SDL_CondBroadcast(cond) == -1)
abort();
}