Port the HTTP / CURL download stuff from q2dos.

This is a very first cut:
* It compiles
* It doesn't crash

What's missing:
* cmake integration
* CURL should be loaded dynamically
* Integration between download code and filesystem
* Likely UTF-8 stuff
* cl_http.c needs cleanup
* Windows support
This commit is contained in:
Yamagi Burmeister 2018-11-20 18:15:19 +01:00
parent 380642468b
commit 0a94a8ee92
9 changed files with 1422 additions and 5 deletions

View file

@ -25,6 +25,10 @@
# User configurable options
# -------------------------
# Enables HTTP support through cURL. Used for
# HTTP download.
WITH_CURL:=yes
# Enables the optional OpenAL sound system.
# To use it your system needs libopenal.so.1
# or openal32.dll (we recommend openal-soft)
@ -373,6 +377,11 @@ endif
release/quake2 : CFLAGS += -Wno-unused-result
ifeq ($(WITH_CURL),yes)
release/quake2 : CFLAGS += -DUSE_CURL
release/quake2 : LDFLAGS += -lcurl
endif
ifeq ($(WITH_OPENAL),yes)
ifeq ($(YQ2_OSTYPE), OpenBSD)
release/quake2 : CFLAGS += -DUSE_OPENAL -DDEFAULT_OPENAL_DRIVER='"libopenal.so"'
@ -668,6 +677,7 @@ CLIENT_OBJS_ := \
src/client/cl_download.o \
src/client/cl_effects.o \
src/client/cl_entities.o \
src/client/cl_http.o \
src/client/cl_input.o \
src/client/cl_inventory.o \
src/client/cl_keyboard.o \

View file

@ -678,7 +678,11 @@ Con_DrawConsole(float frac)
}
/* draw the download bar, figure out width */
#ifdef USE_CURL
if (cls.downloadname[0] && (cls.download || cls.downloadposition))
#else
if (cls.download)
#endif
{
if ((text = strrchr(cls.downloadname, '/')) != NULL)
{

View file

@ -103,6 +103,14 @@ CL_RequestNextDownload(void)
precache_model_skin = 1;
}
#ifdef USE_CURL
/* Wait for the models to download before checking * skins. */
if (CL_PendingHTTPDownloads())
{
return;
}
#endif
/* checking for skins in the model */
if (!precache_model)
{
@ -338,6 +346,14 @@ CL_RequestNextDownload(void)
precache_check = ENV_CNT;
}
#ifdef USE_CURL
/* Wait for pending downloads. */
if (CL_PendingHTTPDownloads())
{
return;
}
#endif
if (precache_check == ENV_CNT)
{
precache_check = ENV_CNT + 1;
@ -412,8 +428,15 @@ CL_RequestNextDownload(void)
precache_check = TEXTURE_CNT + 999;
}
CL_RegisterSounds();
#ifdef USE_CURL
/* Wait for pending downloads. */
if (CL_PendingHTTPDownloads())
{
return;
}
#endif
CL_RegisterSounds();
CL_PrepRefresh();
MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
@ -464,6 +487,18 @@ CL_CheckOrDownloadFile(char *filename)
return true;
}
#ifdef USE_CURL
if (CL_QueueHTTPDownload(filename))
{
/* We return true so that the precache check
keeps feeding us more files. Since we have
multiple HTTP connections we want to
minimize latency and be constantly sending
requests, not one at a time. */
return true;
}
#endif
strcpy(cls.downloadname, filename);
/* download to a temp name, and only rename

1182
src/client/cl_http.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -461,6 +461,10 @@ CL_Precache_f(void)
precache_model = 0;
precache_model_skin = 0;
#ifdef USE_CURL
CL_HTTP_ResetMapAbort();
#endif
CL_RequestNextDownload();
}
@ -541,6 +545,13 @@ CL_InitLocal(void)
cl_vwep = Cvar_Get("cl_vwep", "1", CVAR_ARCHIVE);
#ifdef USE_CURL
cl_http_proxy = Cvar_Get("cl_http_proxy", "", 0);
cl_http_filelists = Cvar_Get("cl_http_filelists", "1", 0);
cl_http_downloads = Cvar_Get("cl_http_downloads", "1", CVAR_ARCHIVE);
cl_http_max_connections = Cvar_Get("cl_http_max_connections", "4", 0);
#endif
/* register our commands */
Cmd_AddCommand("cmd", CL_ForwardToServer_f);
Cmd_AddCommand("pause", CL_Pause_f);
@ -757,7 +768,15 @@ CL_Frame(int packetdelta, int renderdelta, int timedelta, qboolean packetframe,
}
}
// Update input stuff
// Run HTTP downloads more often while connecting.
#ifdef USE_CURL
if (cls.state == ca_connected)
{
CL_RunHTTPDownloads();
}
#endif
// Update input stuff.
if (packetframe || renderframe)
{
CL_ReadPackets();
@ -786,6 +805,11 @@ CL_Frame(int packetdelta, int renderdelta, int timedelta, qboolean packetframe,
{
CL_SendCmd();
CL_CheckForResend();
// Run HTTP downloads during game.
#ifdef USE_CURL
CL_RunHTTPDownloads();
#endif
}
if (renderframe)
@ -880,6 +904,10 @@ CL_Init(void)
M_Init();
#ifdef USE_CURL
CL_InitHTTPDownloads();
#endif
cls.disable_screen = true; /* don't draw yet */
CL_InitLocal();
@ -902,6 +930,10 @@ CL_Shutdown(void)
isdown = true;
#ifdef USE_CURL
CL_HTTP_Cleanup(true);
#endif
CL_WriteConfiguration();
Key_WriteConsoleHistory();

View file

@ -346,6 +346,15 @@ CL_Disconnect(void)
cls.download = NULL;
}
#ifdef USE_CURL
CL_CancelHTTPDownloads(true);
cls.downloadReferer[0] = 0;
cls.downloadname[0] = 0;
cls.downloadposition = 0;
// TODO CURL: Rausreißen?
// CL_Download_Reset_KBps_counter();
#endif
cls.state = ca_disconnected;
snd_is_underwater = false;
@ -437,10 +446,15 @@ CL_Changing_f(void)
}
SCR_BeginLoadingPlaque();
cls.state = ca_connected; /* not active anymore, but not disconnected */
Com_Printf("\nChanging map...\n");
#ifdef USE_CURL
if (cls.downloadServerRetry[0] != 0)
{
CL_SetHTTPServer(cls.downloadServerRetry);
}
#endif
}
/*
@ -583,6 +597,32 @@ CL_ConnectionlessPacket(void)
Netchan_Setup(NS_CLIENT, &cls.netchan, net_from, cls.quakePort);
// TODO CURL: Das erscheint mir sinnlos kompliziert und ist für
// den Fall ohne CURL wahrscheinlich recht spammy.
char *buff = NET_AdrToString(cls.netchan.remote_address);
for (int i = 1; i < Cmd_Argc(); i++)
{
char *p = Cmd_Argv(i);
if (!strncmp (p, "dlserver=", 9))
{
#ifdef USE_CURL
p += 9;
Com_sprintf(cls.downloadReferer, sizeof(cls.downloadReferer), "quake2://%s", buff);
CL_SetHTTPServer (p);
if (cls.downloadServer[0])
{
Com_Printf("HTTP downloading enabled, URL: %s\n", cls.downloadServer);
}
#else
Com_Printf("HTTP downloading supported by server but not the client.\n");
#endif
}
}
MSG_WriteChar(&cls.netchan.message, clc_stringcmd);
MSG_WriteString(&cls.netchan.message, "new");
cls.state = ca_connected;

View file

@ -54,6 +54,7 @@
#include "../vid/header/ref.h"
#include "../vid/header/vid.h"
#include "http.h"
#include "screen.h"
#include "keyboard.h"
#include "console.h"
@ -240,12 +241,22 @@ typedef struct
char downloadname[MAX_OSPATH];
int downloadnumber;
dltype_t downloadtype;
size_t downloadposition;
int downloadpercent;
/* demo recording info must be here, so it isn't cleared on level change */
qboolean demorecording;
qboolean demowaiting; /* don't record until a non-delta message is received */
FILE *demofile;
#ifdef USE_CURL
/* http downloading */
dlqueue_t downloadQueue; /* queues with files to download. */
dlhandle_t HTTPHandles[MAX_HTTP_HANDLES]; /* download handles. */
char downloadServer[512]; /* URL prefix to dowload from .*/
char downloadServerRetry[512]; /* retry count. */
char downloadReferer[32]; /* referer string. */
#endif
} client_static_t;
extern client_static_t cls;

75
src/client/header/http.h Normal file
View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*
* =======================================================================
*
* Header for the HTTP / cURL download stuff.
*
* =======================================================================
*/
#ifdef USE_CURL
// Number of max. parallel downloads.
#define MAX_HTTP_HANDLES 16
#include <curl/curl.h>
typedef enum
{
DLQ_STATE_NOT_STARTED,
DLQ_STATE_RUNNING,
DLQ_STATE_DONE
} dlq_state;
typedef struct dlqueue_s
{
struct dlqueue_s *next;
char quakePath[MAX_QPATH];
dlq_state state;
} dlqueue_t;
typedef struct dlhandle_s
{
CURL *curl;
char filePath[MAX_OSPATH];
FILE *file;
dlqueue_t *queueEntry;
size_t fileSize;
size_t position;
double speed;
char URL[576];
char *tempBuffer;
} dlhandle_t;
extern cvar_t *cl_http_downloads;
extern cvar_t *cl_http_filelists;
extern cvar_t *cl_http_proxy;
extern cvar_t *cl_http_max_connections;
void CL_CancelHTTPDownloads(qboolean permKill);
void CL_InitHTTPDownloads(void);
qboolean CL_QueueHTTPDownload(const char *quakePath);
void CL_RunHTTPDownloads(void);
qboolean CL_PendingHTTPDownloads(void);
void CL_SetHTTPServer(const char *URL);
void CL_HTTP_Cleanup(qboolean fullShutdown);
void CL_HTTP_ResetMapAbort(void);
#endif

View file

@ -3538,6 +3538,11 @@ static menuframework_s s_downloadoptions_menu;
static menuseparator_s s_download_title;
static menulist_s s_allow_download_box;
#ifdef USE_CURL
static menulist_s s_allow_download_http_box;
#endif
static menulist_s s_allow_download_maps_box;
static menulist_s s_allow_download_models_box;
static menulist_s s_allow_download_players_box;
@ -3552,6 +3557,12 @@ DownloadCallback(void *self)
{
Cvar_SetValue("allow_download", (float)f->curvalue);
}
#ifdef USE_CURL
else if (f == &s_allow_download_http_box)
{
Cvar_SetValue("cl_http_downloads", f->curvalue);
}
#endif
else if (f == &s_allow_download_maps_box)
{
Cvar_SetValue("allow_download_maps", (float)f->curvalue);
@ -3596,9 +3607,21 @@ DownloadOptions_MenuInit(void)
s_allow_download_box.itemnames = yes_no_names;
s_allow_download_box.curvalue = (Cvar_VariableValue("allow_download") != 0);
#ifdef USE_CURL
s_allow_download_http_box.generic.type = MTYPE_SPINCONTROL;
s_allow_download_http_box.generic.x = 0;
s_allow_download_http_box.generic.y = y += 20;
s_allow_download_http_box.generic.name = "http downloading";
s_allow_download_http_box.generic.callback = DownloadCallback;
s_allow_download_http_box.itemnames = yes_no_names;
s_allow_download_http_box.curvalue = (Cvar_VariableValue("cl_http_downloads") != 0);
#else
y += 10;
#endif
s_allow_download_maps_box.generic.type = MTYPE_SPINCONTROL;
s_allow_download_maps_box.generic.x = 0;
s_allow_download_maps_box.generic.y = y += 20;
s_allow_download_maps_box.generic.y = y += 10;
s_allow_download_maps_box.generic.name = "maps";
s_allow_download_maps_box.generic.callback = DownloadCallback;
s_allow_download_maps_box.itemnames = yes_no_names;
@ -3634,6 +3657,11 @@ DownloadOptions_MenuInit(void)
Menu_AddItem(&s_downloadoptions_menu, &s_download_title);
Menu_AddItem(&s_downloadoptions_menu, &s_allow_download_box);
#ifdef USE_CURL
Menu_AddItem(&s_downloadoptions_menu, &s_allow_download_http_box);
#endif
Menu_AddItem(&s_downloadoptions_menu, &s_allow_download_maps_box);
Menu_AddItem(&s_downloadoptions_menu, &s_allow_download_players_box);
Menu_AddItem(&s_downloadoptions_menu, &s_allow_download_models_box);