* add cURL support for HTTP/FTP downloading (bug 2661)

This commit is contained in:
Tony J. White = 2006-09-11 16:41:55 +00:00
parent fa904ff235
commit 2af23e813d
18 changed files with 2829 additions and 6 deletions

View file

@ -100,6 +100,18 @@ ifndef USE_OPENAL_DLOPEN
USE_OPENAL_DLOPEN=0 USE_OPENAL_DLOPEN=0
endif endif
ifndef USE_CURL
USE_CURL=1
endif
ifndef USE_CURL_DLOPEN
ifeq ($(PLATFORM),mingw32)
USE_CURL_DLOPEN=0
else
USE_CURL_DLOPEN=1
endif
endif
ifndef USE_CODEC_VORBIS ifndef USE_CODEC_VORBIS
USE_CODEC_VORBIS=0 USE_CODEC_VORBIS=0
endif endif
@ -187,6 +199,13 @@ ifeq ($(PLATFORM),linux)
BASE_CFLAGS += -DUSE_OPENAL_DLOPEN=1 BASE_CFLAGS += -DUSE_OPENAL_DLOPEN=1
endif endif
endif endif
ifeq ($(USE_CURL),1)
BASE_CFLAGS += -DUSE_CURL=1
ifeq ($(USE_CURL_DLOPEN),1)
BASE_CFLAGS += -DUSE_CURL_DLOPEN=1
endif
endif
ifeq ($(USE_CODEC_VORBIS),1) ifeq ($(USE_CODEC_VORBIS),1)
BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 BASE_CFLAGS += -DUSE_CODEC_VORBIS=1
@ -249,6 +268,12 @@ ifeq ($(PLATFORM),linux)
CLIENT_LDFLAGS += -lopenal CLIENT_LDFLAGS += -lopenal
endif endif
endif endif
ifeq ($(USE_CURL),1)
ifneq ($(USE_CURL_DLOPEN),1)
CLIENT_LDFLAGS += -lcurl
endif
endif
ifeq ($(USE_CODEC_VORBIS),1) ifeq ($(USE_CODEC_VORBIS),1)
CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg
@ -348,6 +373,15 @@ ifeq ($(PLATFORM),darwin)
BASE_CFLAGS += -DUSE_OPENAL_DLOPEN=1 BASE_CFLAGS += -DUSE_OPENAL_DLOPEN=1
endif endif
endif endif
ifeq ($(USE_CURL),1)
BASE_CFLAGS += -DUSE_CURL=1
ifneq ($(USE_CURL_DLOPEN),1)
CLIENT_LDFLAGS += -lcurl
else
BASE_CFLAGS += -DUSE_CURL_DLOPEN=1
endif
endif
ifeq ($(USE_CODEC_VORBIS),1) ifeq ($(USE_CODEC_VORBIS),1)
BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 BASE_CFLAGS += -DUSE_CODEC_VORBIS=1
@ -404,6 +438,13 @@ ifeq ($(PLATFORM),mingw32)
ifeq ($(USE_OPENAL),1) ifeq ($(USE_OPENAL),1)
BASE_CFLAGS += -DUSE_OPENAL=1 -DUSE_OPENAL_DLOPEN=1 BASE_CFLAGS += -DUSE_OPENAL=1 -DUSE_OPENAL_DLOPEN=1
endif endif
ifeq ($(USE_CURL),1)
BASE_CFLAGS += -DUSE_CURL=1
ifneq ($(USE_CURL_DLOPEN),1)
BASE_CFLAGS += -DCURL_STATICLIB
endif
endif
ifeq ($(USE_CODEC_VORBIS),1) ifeq ($(USE_CODEC_VORBIS),1)
BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 BASE_CFLAGS += -DUSE_CODEC_VORBIS=1
@ -430,6 +471,12 @@ ifeq ($(PLATFORM),mingw32)
LDFLAGS= -mwindows -lshfolder -lwsock32 -lgdi32 -lwinmm -lole32 LDFLAGS= -mwindows -lshfolder -lwsock32 -lgdi32 -lwinmm -lole32
CLIENT_LDFLAGS= CLIENT_LDFLAGS=
ifeq ($(USE_CURL),1)
ifneq ($(USE_CURL_DLOPEN),1)
CLIENT_LDFLAGS += $(LIBSDIR)/win32/libcurl.a
endif
endif
ifeq ($(USE_CODEC_VORBIS),1) ifeq ($(USE_CODEC_VORBIS),1)
CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg
endif endif
@ -847,6 +894,8 @@ Q3OBJ = \
$(B)/client/qal.o \ $(B)/client/qal.o \
$(B)/client/snd_openal.o \ $(B)/client/snd_openal.o \
\ \
$(B)/client/cl_curl.o \
\
$(B)/client/sv_bot.o \ $(B)/client/sv_bot.o \
$(B)/client/sv_ccmds.o \ $(B)/client/sv_ccmds.o \
$(B)/client/sv_client.o \ $(B)/client/sv_client.o \
@ -1067,6 +1116,8 @@ $(B)/client/snd_codec_ogg.o : $(CDIR)/snd_codec_ogg.c; $(DO_CC)
$(B)/client/qal.o : $(CDIR)/qal.c; $(DO_CC) $(B)/client/qal.o : $(CDIR)/qal.c; $(DO_CC)
$(B)/client/snd_openal.o : $(CDIR)/snd_openal.c; $(DO_CC) $(B)/client/snd_openal.o : $(CDIR)/snd_openal.c; $(DO_CC)
$(B)/client/cl_curl.o : $(CDIR)/cl_curl.c; $(DO_CC)
$(B)/client/sv_bot.o : $(SDIR)/sv_bot.c; $(DO_CC) $(B)/client/sv_bot.o : $(SDIR)/sv_bot.c; $(DO_CC)
$(B)/client/sv_client.o : $(SDIR)/sv_client.c; $(DO_CC) $(B)/client/sv_client.o : $(SDIR)/sv_client.c; $(DO_CC)
$(B)/client/sv_ccmds.o : $(SDIR)/sv_ccmds.c; $(DO_CC) $(B)/client/sv_ccmds.o : $(SDIR)/sv_ccmds.c; $(DO_CC)

41
README
View file

@ -23,6 +23,7 @@ for further development. Some of the major features currently implemented are:
* Much improved QVM tools * Much improved QVM tools
* Support for various esoteric operating systems (see * Support for various esoteric operating systems (see
http://icculus.org/quake3/?page=status) http://icculus.org/quake3/?page=status)
* HTTP/FTP download redirection (using cURL)
* Many, many bug fixes * Many, many bug fixes
The map editor and associated compiling tools are not included. We suggest you The map editor and associated compiling tools are not included. We suggest you
@ -140,6 +141,9 @@ New cvars
cl_platformSensitivity - read only, indicates the mouse input cl_platformSensitivity - read only, indicates the mouse input
scaling scaling
r_ext_texture_filter_anisotropic - anisotropic texture filtering r_ext_texture_filter_anisotropic - anisotropic texture filtering
cl_cURLLib - filename of cURL library to load
sv_dlURL - the base of the HTTP or FTP site that
holds custom pk3 files for your server
New commands New commands
video [filename] - start video capture (use with demo command) video [filename] - start video capture (use with demo command)
@ -192,6 +196,43 @@ Creating mods compatible with Q3 1.32b
compiler. See http://www.quakesrc.org/forums/viewtopic.php?t=5665 (if it compiler. See http://www.quakesrc.org/forums/viewtopic.php?t=5665 (if it
still exists when you read this) for more details. still exists when you read this) for more details.
Using HTTP/FTP Download Support (Server)
You can enable redirected downloads on your server even if it's not
an ioquake3 server. You simply need to use the 'sets' command to put
the sv_dlURL cvar into your SERVERINFO string and ensure sv_allowDownloads
is set to 1
sv_dlURL is the base of the URL that contains your custom .pk3 files
the client will append both fs_game and the filename to the end of
this value. For example, if you have sv_dlURL set to
"http://icculus.org/quake3", fs_game is "baseq3", and the client is
missing "test.pk3", it will attempt to download from the URL
"http://icculus.org/quake3/baseq3/test.pk3"
sv_allowDownload's value is now a bitmask made up of the following
flags:
1 - ENABLE
2 - do not use HTTP/FTP downloads
4 - do not use UDP downloads
8 - do not ask the client to disconnect when using HTTP/FTP
Server operators who are concerned about potential "leeching" from their
HTTP servers from other ioquake3 servers can make use of the HTTP_REFERER
that ioquake3 sets which is "ioQ3://{SERVER_IP}:{SERVER_PORT}". For,
example, Apache's mod_rewrite can restrict access based on HTTP_REFERER.
Using HTTP/FTP Download Support (Client)
Simply setting cl_allowDownload to 1 will enable HTTP/FTP downloads
assuming ioquake3 was compiled with USE_CURL=1 (the default).
like sv_allowDownload, cl_allowDownload also uses a bitmask value
supporting the following flags:
1 - ENABLE
2 - do not use HTTP/FTP downloads
4 - do not use UDP downloads
When ioquake3 is built with USE_CURL_DLOPEN=1 (default on some platforms),
it will use the value of the cvar cl_cURLLib as the filename of the cURL
library to dynamically load.
------------------------------------------------------------- Contributing ----- ------------------------------------------------------------- Contributing -----

358
code/client/cl_curl.c Normal file
View file

@ -0,0 +1,358 @@
/*
===========================================================================
Copyright (C) 2006 Tony J. White (tjw@tjw.org)
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#if USE_CURL
#include "client.h"
cvar_t *cl_cURLLib;
#if USE_CURL_DLOPEN
#if USE_SDL_VIDEO
#include "SDL.h"
#include "SDL_loadso.h"
#define OBJTYPE void *
#define OBJLOAD(x) SDL_LoadObject(x)
#define SYMLOAD(x,y) SDL_LoadFunction(x,y)
#define OBJFREE(x) SDL_UnloadObject(x)
#elif defined _WIN32
#include <windows.h>
#define OBJTYPE HMODULE
#define OBJLOAD(x) LoadLibrary(x)
#define SYMLOAD(x,y) GetProcAddress(x,y)
#define OBJFREE(x) FreeLibrary(x)
#elif defined __linux__ || defined __FreeBSD__ || defined MACOS_X || defined __sun
#include <dlfcn.h>
#define OBJTYPE void *
#define OBJLOAD(x) dlopen(x, RTLD_LAZY | RTLD_GLOBAL)
#define SYMLOAD(x,y) dlsym(x,y)
#define OBJFREE(x) dlclose(x)
#else
#error "Your platform has no lib loading code or it is disabled"
#endif
#if defined __linux__ || defined __FreeBSD__ || defined MACOS_X
#include <unistd.h>
#include <sys/types.h>
#endif
char* (*qcurl_version)(void);
CURL* (*qcurl_easy_init)(void);
CURLcode (*qcurl_easy_setopt)(CURL *curl, CURLoption option, ...);
CURLcode (*qcurl_easy_perform)(CURL *curl);
void (*qcurl_easy_cleanup)(CURL *curl);
CURLcode (*qcurl_easy_getinfo)(CURL *curl, CURLINFO info, ...);
CURL* (*qcurl_easy_duphandle)(CURL *curl);
void (*qcurl_easy_reset)(CURL *curl);
const char *(*qcurl_easy_strerror)(CURLcode);
CURLM* (*qcurl_multi_init)(void);
CURLMcode (*qcurl_multi_add_handle)(CURLM *multi_handle,
CURL *curl_handle);
CURLMcode (*qcurl_multi_remove_handle)(CURLM *multi_handle,
CURL *curl_handle);
CURLMcode (*qcurl_multi_fdset)(CURLM *multi_handle,
fd_set *read_fd_set,
fd_set *write_fd_set,
fd_set *exc_fd_set,
int *max_fd);
CURLMcode (*qcurl_multi_perform)(CURLM *multi_handle,
int *running_handles);
CURLMcode (*qcurl_multi_cleanup)(CURLM *multi_handle);
CURLMsg *(*qcurl_multi_info_read)(CURLM *multi_handle,
int *msgs_in_queue);
const char *(*qcurl_multi_strerror)(CURLMcode);
static OBJTYPE cURLLib = NULL;
/*
=================
GPA
=================
*/
static void *GPA(char *str)
{
void *rv;
rv = SYMLOAD(cURLLib, str);
if(!rv)
{
Com_Printf("Can't load symbol %s\n", str);
clc.cURLEnabled = qfalse;
return NULL;
}
else
{
Com_DPrintf("Loaded symbol %s (0x%08X)\n", str, rv);
return rv;
}
}
#endif /* USE_CURL_DLOPEN */
/*
=================
CL_cURL_Init
=================
*/
qboolean CL_cURL_Init()
{
#if USE_CURL_DLOPEN
if(cURLLib)
return qtrue;
Com_Printf("Loading \"%s\"...", cl_cURLLib->string);
if( (cURLLib = OBJLOAD(cl_cURLLib->string)) == 0 )
{
#ifdef _WIN32
return qfalse;
#else
char fn[1024];
getcwd(fn, sizeof(fn));
strncat(fn, "/", sizeof(fn));
strncat(fn, cl_cURLLib->string, sizeof(fn));
if( (cURLLib = OBJLOAD(fn)) == 0 )
{
return qfalse;
}
#endif /* _WIN32 */
}
clc.cURLEnabled = qtrue;
qcurl_version = GPA("curl_version");
qcurl_easy_init = GPA("curl_easy_init");
qcurl_easy_setopt = GPA("curl_easy_setopt");
qcurl_easy_perform = GPA("curl_easy_perform");
qcurl_easy_cleanup = GPA("curl_easy_cleanup");
qcurl_easy_getinfo = GPA("curl_easy_getinfo");
qcurl_easy_duphandle = GPA("curl_easy_duphandle");
qcurl_easy_reset = GPA("curl_easy_reset");
qcurl_easy_strerror = GPA("curl_easy_strerror");
qcurl_multi_init = GPA("curl_multi_init");
qcurl_multi_add_handle = GPA("curl_multi_add_handle");
qcurl_multi_remove_handle = GPA("curl_multi_remove_handle");
qcurl_multi_fdset = GPA("curl_multi_fdset");
qcurl_multi_perform = GPA("curl_multi_perform");
qcurl_multi_cleanup = GPA("curl_multi_cleanup");
qcurl_multi_info_read = GPA("curl_multi_info_read");
qcurl_multi_strerror = GPA("curl_multi_strerror");
if(!clc.cURLEnabled)
{
CL_cURL_Shutdown();
Com_Printf("FAIL One or more symbols not found\n");
return qfalse;
}
Com_Printf("OK\n");
return qtrue;
#else
clc.cURLEnabled = qtrue;
return qtrue;
#endif /* USE_CURL_DLOPEN */
}
/*
=================
CL_cURL_Shutdown
=================
*/
void CL_cURL_Shutdown( void )
{
CL_cURL_Cleanup();
#if USE_CURL_DLOPEN
if(cURLLib)
{
OBJFREE(cURLLib);
cURLLib = NULL;
}
qcurl_easy_init = NULL;
qcurl_easy_setopt = NULL;
qcurl_easy_perform = NULL;
qcurl_easy_cleanup = NULL;
qcurl_easy_getinfo = NULL;
qcurl_easy_duphandle = NULL;
qcurl_easy_reset = NULL;
qcurl_multi_init = NULL;
qcurl_multi_add_handle = NULL;
qcurl_multi_remove_handle = NULL;
qcurl_multi_fdset = NULL;
qcurl_multi_perform = NULL;
qcurl_multi_cleanup = NULL;
qcurl_multi_info_read = NULL;
qcurl_multi_strerror = NULL;
#endif /* USE_CURL_DLOPEN */
}
void CL_cURL_Cleanup(void)
{
if(clc.downloadCURLM) {
if(clc.downloadCURL) {
qcurl_multi_remove_handle(clc.downloadCURLM,
clc.downloadCURL);
qcurl_easy_cleanup(clc.downloadCURL);
}
qcurl_multi_cleanup(clc.downloadCURLM);
clc.downloadCURLM = NULL;
clc.downloadCURL = NULL;
}
else if(clc.downloadCURL) {
qcurl_easy_cleanup(clc.downloadCURL);
clc.downloadCURL = NULL;
}
}
static int CL_cURL_CallbackProgress( void *dummy, double dltotal, double dlnow,
double ultotal, double ulnow )
{
clc.downloadSize = (int)dltotal;
Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
clc.downloadCount = (int)dlnow;
Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
return 0;
}
static int CL_cURL_CallbackWrite(void *buffer, size_t size, size_t nmemb,
void *stream)
{
FS_Write( buffer, size*nmemb, ((fileHandle_t*)stream)[0] );
return size*nmemb;
}
void CL_cURL_BeginDownload( const char *localName, const char *remoteURL )
{
clc.cURLUsed = qtrue;
Com_Printf("URL: %s\n", remoteURL);
Com_DPrintf("***** CL_cURL_BeginDownload *****\n"
"Localname: %s\n"
"RemoteURL: %s\n"
"****************************\n", localName, remoteURL);
CL_cURL_Cleanup();
Q_strncpyz(clc.downloadURL, remoteURL, sizeof(clc.downloadURL));
Q_strncpyz(clc.downloadName, localName, sizeof(clc.downloadName));
Com_sprintf(clc.downloadTempName, sizeof(clc.downloadTempName),
"%s.tmp", localName);
// Set so UI gets access to it
Cvar_Set("cl_downloadName", localName);
Cvar_Set("cl_downloadSize", "0");
Cvar_Set("cl_downloadCount", "0");
Cvar_SetValue("cl_downloadTime", cls.realtime);
clc.downloadBlock = 0; // Starting new file
clc.downloadCount = 0;
clc.downloadCURL = qcurl_easy_init();
if(!clc.downloadCURL) {
Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_easy_init() "
"failed\n");
return;
}
clc.download = FS_SV_FOpenFileWrite(clc.downloadTempName);
if(!clc.download) {
Com_Error(ERR_DROP, "CL_cURL_BeginDownload: failed to open "
"%s for writing\n", clc.downloadTempName);
return;
}
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, clc.download);
if(com_developer->integer)
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_VERBOSE, 1);
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_URL, clc.downloadURL);
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_TRANSFERTEXT, 0);
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_REFERER, va("ioQ3://%s",
NET_AdrToString(clc.serverAddress)));
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_USERAGENT, va("%s %s",
Q3_VERSION, qcurl_version()));
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEFUNCTION,
CL_cURL_CallbackWrite);
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, &clc.download);
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_NOPROGRESS, 0);
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSFUNCTION,
CL_cURL_CallbackProgress);
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSDATA, NULL);
qcurl_easy_setopt(clc.downloadCURL, CURLOPT_FAILONERROR, 1);
clc.downloadCURLM = qcurl_multi_init();
if(!clc.downloadCURLM) {
qcurl_easy_cleanup(clc.downloadCURL);
clc.downloadCURL = NULL;
Com_Error(ERR_DROP, "CL_cURL_BeginDownload: qcurl_multi_init() "
"failed\n");
return;
}
qcurl_multi_add_handle(clc.downloadCURLM, clc.downloadCURL);
if(!(clc.sv_allowDownload & DLF_NO_DISCONNECT) &&
!clc.cURLDisconnected) {
CL_AddReliableCommand("disconnect");
CL_WritePacket();
CL_WritePacket();
CL_WritePacket();
clc.cURLDisconnected = qtrue;
}
}
void CL_cURL_PerformDownload(void)
{
CURLMcode res;
CURLMsg *msg;
int c;
int i = 0;
res = qcurl_multi_perform(clc.downloadCURLM, &c);
while(res == CURLM_CALL_MULTI_PERFORM && i < 100) {
res = qcurl_multi_perform(clc.downloadCURLM, &c);
i++;
}
if(res == CURLM_CALL_MULTI_PERFORM)
return;
msg = qcurl_multi_info_read(clc.downloadCURLM, &c);
if(msg == NULL) {
return;
}
FS_FCloseFile(clc.download);
if(msg->msg == CURLMSG_DONE && msg->data.result == CURLE_OK) {
FS_SV_Rename(clc.downloadTempName, clc.downloadName);
clc.downloadRestart = qtrue;
}
else {
long code;
qcurl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE,
&code);
Com_Error(ERR_DROP, "Download Error: %s Code: %d URL: %s",
qcurl_easy_strerror(msg->data.result),
code, clc.downloadURL);
}
*clc.downloadTempName = *clc.downloadName = 0;
Cvar_Set( "cl_downloadName", "" );
CL_NextDownload();
}
#endif /* USE_CURL */

101
code/client/cl_curl.h Normal file
View file

@ -0,0 +1,101 @@
/*
===========================================================================
Copyright (C) 2006 Tony J. White (tjw@tjw.org)
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifndef __QCURL_H__
#define __QCURL_H__
extern cvar_t *cl_cURLLib;
#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#ifdef WIN32
#define DEFAULT_CURL_LIB "libcurl-3.dll"
#elif defined(MACOS_X)
#define DEFAULT_CURL_LIB "libcurl.dylib"
#else
#define DEFAULT_CURL_LIB "libcurl.so.3"
#endif
#if USE_LOCAL_HEADERS
#include "../libcurl/curl/curl.h"
#else
#include <curl/curl.h>
#endif
#if USE_CURL_DLOPEN
extern char* (*qcurl_version)(void);
extern CURL* (*qcurl_easy_init)(void);
extern CURLcode (*qcurl_easy_setopt)(CURL *curl, CURLoption option, ...);
extern CURLcode (*qcurl_easy_perform)(CURL *curl);
extern void (*qcurl_easy_cleanup)(CURL *curl);
extern CURLcode (*qcurl_easy_getinfo)(CURL *curl, CURLINFO info, ...);
extern void (*qcurl_easy_reset)(CURL *curl);
extern const char *(*qcurl_easy_strerror)(CURLcode);
extern CURLM* (*qcurl_multi_init)(void);
extern CURLMcode (*qcurl_multi_add_handle)(CURLM *multi_handle,
CURL *curl_handle);
extern CURLMcode (*qcurl_multi_remove_handle)(CURLM *multi_handle,
CURL *curl_handle);
extern CURLMcode (*qcurl_multi_fdset)(CURLM *multi_handle,
fd_set *read_fd_set,
fd_set *write_fd_set,
fd_set *exc_fd_set,
int *max_fd);
extern CURLMcode (*qcurl_multi_perform)(CURLM *multi_handle,
int *running_handles);
extern CURLMcode (*qcurl_multi_cleanup)(CURLM *multi_handle);
extern CURLMsg *(*qcurl_multi_info_read)(CURLM *multi_handle,
int *msgs_in_queue);
extern const char *(*qcurl_multi_strerror)(CURLMcode);
#else
#define qcurl_version curl_version
#define qcurl_easy_init curl_easy_init
#define qcurl_easy_setopt curl_easy_setopt
#define qcurl_easy_perform curl_easy_perform
#define qcurl_easy_cleanup curl_easy_cleanup
#define qcurl_easy_getinfo curl_easy_getinfo
#define qcurl_easy_duphandle curl_easy_duphandle
#define qcurl_easy_reset curl_easy_reset
#define qcurl_easy_strerror curl_easy_strerror
#define qcurl_multi_init curl_multi_init
#define qcurl_multi_add_handle curl_multi_add_handle
#define qcurl_multi_remove_handle curl_multi_remove_handle
#define qcurl_multi_fdset curl_multi_fdset
#define qcurl_multi_perform curl_multi_perform
#define qcurl_multi_cleanup curl_multi_cleanup
#define qcurl_multi_info_read curl_multi_info_read
#define qcurl_multi_strerror curl_multi_strerror
#endif
qboolean CL_cURL_Init( void );
void CL_cURL_Shutdown( void );
void CL_cURL_BeginDownload( const char *localName, const char *remoteURL );
void CL_cURL_PerformDownload( void );
void CL_cURL_Cleanup( void );
#endif // __QCURL_H__

View file

@ -608,6 +608,9 @@ CL_ShutdownAll
*/ */
void CL_ShutdownAll(void) { void CL_ShutdownAll(void) {
#if USE_CURL
CL_cURL_Shutdown();
#endif
// clear sounds // clear sounds
S_DisableSounds(); S_DisableSounds();
// shutdown CGame // shutdown CGame
@ -1331,6 +1334,23 @@ Called when all downloading has been completed
*/ */
void CL_DownloadsComplete( void ) { void CL_DownloadsComplete( void ) {
#if USE_CURL
// if we downloaded with cURL
if(clc.cURLUsed) {
clc.cURLUsed = qfalse;
CL_cURL_Shutdown();
if( clc.cURLDisconnected ) {
if(clc.downloadRestart) {
FS_Restart(clc.checksumFeed);
clc.downloadRestart = qfalse;
}
clc.cURLDisconnected = qfalse;
CL_Reconnect_f();
return;
}
}
#endif
// if we downloaded files we need to restart the file system // if we downloaded files we need to restart the file system
if (clc.downloadRestart) { if (clc.downloadRestart) {
clc.downloadRestart = qfalse; clc.downloadRestart = qfalse;
@ -1418,6 +1438,7 @@ A download completed or failed
void CL_NextDownload(void) { void CL_NextDownload(void) {
char *s; char *s;
char *remoteName, *localName; char *remoteName, *localName;
qboolean useCURL = qfalse;
// We are looking to start a download here // We are looking to start a download here
if (*clc.downloadList) { if (*clc.downloadList) {
@ -1441,9 +1462,48 @@ void CL_NextDownload(void) {
*s++ = 0; *s++ = 0;
else else
s = localName + strlen(localName); // point at the nul byte s = localName + strlen(localName); // point at the nul byte
#if USE_CURL
CL_BeginDownload( localName, remoteName ); if(!(cl_allowDownload->integer & DLF_NO_REDIRECT)) {
if(clc.sv_allowDownload & DLF_NO_REDIRECT) {
Com_Printf("WARNING: server does not "
"allow download redirection "
"(sv_allowDownload is %d)\n",
clc.sv_allowDownload);
}
else if(!*clc.sv_dlURL) {
Com_Printf("WARNING: server allows "
"download redirection, but does not "
"have sv_dlURL set\n");
}
else if(!CL_cURL_Init()) {
Com_Printf("WARNING: could not load "
"cURL library\n");
}
else {
CL_cURL_BeginDownload(localName, va("%s/%s",
clc.sv_dlURL, remoteName));
useCURL = qtrue;
}
}
else if(!(clc.sv_allowDownload & DLF_NO_REDIRECT)) {
Com_Printf("WARNING: server allows download "
"redirection, but it disabled by client "
"configuration (cl_allowDownload is %d)\n",
cl_allowDownload->integer);
}
#endif /* USE_CURL */
if(!useCURL) {
if((cl_allowDownload->integer & DLF_NO_UDP)) {
Com_Error(ERR_DROP, "UDP Downloads are "
"disabled on your client. "
"(cl_allowDownload is %d)",
cl_allowDownload->integer);
return;
}
else {
CL_BeginDownload( localName, remoteName );
}
}
clc.downloadRestart = qtrue; clc.downloadRestart = qtrue;
// move over the rest // move over the rest
@ -1466,7 +1526,7 @@ and determine if we need to download them
void CL_InitDownloads(void) { void CL_InitDownloads(void) {
char missingfiles[1024]; char missingfiles[1024];
if ( !cl_allowDownload->integer ) if ( !(cl_allowDownload->integer & DLF_ENABLE) )
{ {
// autodownload is disabled on the client // autodownload is disabled on the client
// but it's possible that some referenced files on the server are missing // but it's possible that some referenced files on the server are missing
@ -2028,6 +2088,25 @@ void CL_Frame ( int msec ) {
return; return;
} }
#if USE_CURL
if(clc.downloadCURLM) {
CL_cURL_PerformDownload();
// we can't process frames normally when in disconnected
// download mode since the ui vm expects cls.state to be
// CA_CONNECTED
if(clc.cURLDisconnected) {
cls.realFrametime = msec;
cls.frametime = msec;
cls.realtime += cls.frametime;
SCR_UpdateScreen();
S_Update();
Con_RunConsole();
cls.framecount++;
return;
}
}
#endif
if ( cls.cddialog ) { if ( cls.cddialog ) {
// bring up the cd error dialog if needed // bring up the cd error dialog if needed
cls.cddialog = qfalse; cls.cddialog = qfalse;
@ -2478,6 +2557,9 @@ void CL_Init( void ) {
cl_showMouseRate = Cvar_Get ("cl_showmouserate", "0", 0); cl_showMouseRate = Cvar_Get ("cl_showmouserate", "0", 0);
cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE); cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE);
#if USE_CURL
cl_cURLLib = Cvar_Get("cl_cURLLib", DEFAULT_CURL_LIB, CVAR_ARCHIVE);
#endif
cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0);
#ifdef MACOS_X #ifdef MACOS_X

View file

@ -412,6 +412,25 @@ void CL_SystemInfoChanged( void ) {
cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" ); cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" );
} }
/*
==================
CL_ParseServerInfo
==================
*/
static void CL_ParseServerInfo(void)
{
const char *serverInfo;
serverInfo = cl.gameState.stringData
+ cl.gameState.stringOffsets[ CS_SERVERINFO ];
clc.sv_allowDownload = atoi(Info_ValueForKey(serverInfo,
"sv_allowDownload"));
Q_strncpyz(clc.sv_dlURL,
Info_ValueForKey(serverInfo, "sv_dlURL"),
sizeof(clc.sv_dlURL));
}
/* /*
================== ==================
CL_ParseGamestate CL_ParseGamestate
@ -479,6 +498,9 @@ void CL_ParseGamestate( msg_t *msg ) {
// read the checksum feed // read the checksum feed
clc.checksumFeed = MSG_ReadLong( msg ); clc.checksumFeed = MSG_ReadLong( msg );
// parse useful values out of CS_SERVERINFO
CL_ParseServerInfo();
// parse serverId and other cvars // parse serverId and other cvars
CL_SystemInfoChanged(); CL_SystemInfoChanged();

View file

@ -30,6 +30,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../cgame/cg_public.h" #include "../cgame/cg_public.h"
#include "../game/bg_public.h" #include "../game/bg_public.h"
#if USE_CURL
#include "cl_curl.h"
#endif /* USE_CURL */
// tjw: file full of random crap that gets used to create cl_guid // tjw: file full of random crap that gets used to create cl_guid
#define QKEY_FILE "qkey" #define QKEY_FILE "qkey"
@ -185,6 +189,16 @@ typedef struct {
fileHandle_t download; fileHandle_t download;
char downloadTempName[MAX_OSPATH]; char downloadTempName[MAX_OSPATH];
char downloadName[MAX_OSPATH]; char downloadName[MAX_OSPATH];
#ifdef USE_CURL
qboolean cURLEnabled;
qboolean cURLUsed;
qboolean cURLDisconnected;
char downloadURL[MAX_OSPATH];
CURL *downloadCURL;
CURLM *downloadCURLM;
#endif /* USE_CURL */
int sv_allowDownload;
char sv_dlURL[MAX_CVAR_VALUE_STRING];
int downloadNumber; int downloadNumber;
int downloadBlock; // block we are waiting for int downloadBlock; // block we are waiting for
int downloadCount; // how many bytes we got int downloadCount; // how many bytes we got
@ -351,6 +365,7 @@ extern cvar_t *cl_aviMotionJpeg;
extern cvar_t *cl_activeAction; extern cvar_t *cl_activeAction;
extern cvar_t *cl_allowDownload; extern cvar_t *cl_allowDownload;
extern cvar_t *cl_downloadMethod;
extern cvar_t *cl_conXOffset; extern cvar_t *cl_conXOffset;
extern cvar_t *cl_inGameVideo; extern cvar_t *cl_inGameVideo;

1563
code/libcurl/curl/curl.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,56 @@
#ifndef __CURL_CURLVER_H
#define __CURL_CURLVER_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id: curlver.h,v 1.21 2006-06-12 07:24:14 bagder Exp $
***************************************************************************/
/* This header file contains nothing but libcurl version info, generated by
a script at release-time. This was made its own header file in 7.11.2 */
/* This is the version number of the libcurl package from which this header
file origins: */
#define LIBCURL_VERSION "7.15.5"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 7
#define LIBCURL_VERSION_MINOR 15
#define LIBCURL_VERSION_PATCH 5
/* This is the numeric version of the libcurl version number, meant for easier
parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
always follow this syntax:
0xXXYYZZ
Where XX, YY and ZZ are the main version, release and patch numbers in
hexadecimal (using 8 bits each). All three numbers are always represented
using two digits. 1.2 would appear as "0x010200" while version 9.11.7
appears as "0x090b07".
This 6-digit (24 bits) hexadecimal number does not show pre-release number,
and it is always a greater number in a more recent release. It makes
comparisons with greater than and less than work.
*/
#define LIBCURL_VERSION_NUM 0x070f05
#endif /* __CURL_CURLVER_H */

81
code/libcurl/curl/easy.h Normal file
View file

@ -0,0 +1,81 @@
#ifndef __CURL_EASY_H
#define __CURL_EASY_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id: easy.h,v 1.13 2004/11/09 14:02:58 giva Exp $
***************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
CURL_EXTERN CURL *curl_easy_init(void);
CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
CURL_EXTERN void curl_easy_cleanup(CURL *curl);
/*
* NAME curl_easy_getinfo()
*
* DESCRIPTION
*
* Request internal information from the curl session with this function. The
* third argument MUST be a pointer to a long, a pointer to a char * or a
* pointer to a double (as the documentation describes elsewhere). The data
* pointed to will be filled in accordingly and can be relied upon only if the
* function returns CURLE_OK. This function is intended to get used *AFTER* a
* performed transfer, all results from this function are undefined until the
* transfer is completed.
*/
CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
/*
* NAME curl_easy_duphandle()
*
* DESCRIPTION
*
* Creates a new curl session handle with the same options set for the handle
* passed in. Duplicating a handle could only be a matter of cloning data and
* options, internal state info and things like persistant connections cannot
* be transfered. It is useful in multithreaded applications when you can run
* curl_easy_duphandle() for each new thread to avoid a series of identical
* curl_easy_setopt() invokes in every thread.
*/
CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl);
/*
* NAME curl_easy_reset()
*
* DESCRIPTION
*
* Re-initializes a CURL handle to the default values. This puts back the
* handle to the same state as it was in when it was just created.
*
* It does keep: live connections, the Session ID cache, the DNS cache and the
* cookies.
*/
CURL_EXTERN void curl_easy_reset(CURL *curl);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,62 @@
#ifndef __CURL_MPRINTF_H
#define __CURL_MPRINTF_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id: mprintf.h,v 1.13 2006-03-28 10:08:54 bagder Exp $
***************************************************************************/
#include <stdarg.h>
#include <stdio.h> /* needed for FILE */
#include "curl.h"
CURL_EXTERN int curl_mprintf(const char *format, ...);
CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...);
CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...);
CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...);
CURL_EXTERN int curl_mvprintf(const char *format, va_list args);
CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args);
CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args);
CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list args);
CURL_EXTERN char *curl_maprintf(const char *format, ...);
CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
#ifdef _MPRINTF_REPLACE
# define printf curl_mprintf
# define fprintf curl_mfprintf
#ifdef CURLDEBUG
/* When built with CURLDEBUG we define away the sprintf() functions since we
don't want internal code to be using them */
# define sprintf sprintf_was_used
# define vsprintf vsprintf_was_used
#else
# define sprintf curl_msprintf
# define vsprintf curl_mvsprintf
#endif
# define snprintf curl_msnprintf
# define vprintf curl_mvprintf
# define vfprintf curl_mvfprintf
# define vsnprintf curl_mvsnprintf
# define aprintf curl_maprintf
# define vaprintf curl_mvaprintf
#endif
#endif /* __CURL_MPRINTF_H */

344
code/libcurl/curl/multi.h Normal file
View file

@ -0,0 +1,344 @@
#ifndef __CURL_MULTI_H
#define __CURL_MULTI_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id: multi.h,v 1.38 2006-08-04 18:53:48 danf Exp $
***************************************************************************/
/*
This is an "external" header file. Don't give away any internals here!
GOALS
o Enable a "pull" interface. The application that uses libcurl decides where
and when to ask libcurl to get/send data.
o Enable multiple simultaneous transfers in the same thread without making it
complicated for the application.
o Enable the application to select() on its own file descriptors and curl's
file descriptors simultaneous easily.
*/
#if defined(_WIN32) && !defined(WIN32)
/* Chris Lewis mentioned that he doesn't get WIN32 defined, only _WIN32 so we
make this adjustment to catch this. */
#define WIN32 1
#endif
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \
!defined(__CYGWIN__) || defined(__MINGW32__)
#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H))
/* The check above prevents the winsock2 inclusion if winsock.h already was
included, since they can't co-exist without problems */
#include <winsock2.h>
#endif
#else
/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
libc5-based Linux systems. Only include it on system that are known to
require it! */
#if defined(_AIX) || defined(NETWARE) || defined(__NetBSD__) || defined(_MINIX)
#include <sys/select.h>
#endif
#ifndef _WIN32_WCE
#include <sys/socket.h>
#endif
#include <sys/time.h>
#include <sys/types.h>
#endif
/*
* This header file should not really need to include "curl.h" since curl.h
* itself includes this file and we expect user applications to do #include
* <curl/curl.h> without the need for especially including multi.h.
*
* For some reason we added this include here at one point, and rather than to
* break existing (wrongly written) libcurl applications, we leave it as-is
* but with this warning attached.
*/
#include "curl.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void CURLM;
#ifndef curl_socket_typedef
/* Public socket typedef */
#ifdef WIN32
typedef SOCKET curl_socket_t;
#define CURL_SOCKET_BAD INVALID_SOCKET
#else
typedef int curl_socket_t;
#define CURL_SOCKET_BAD -1
#endif
#define curl_socket_typedef
#endif /* curl_socket_typedef */
typedef enum {
CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
curl_multi_socket*() soon */
CURLM_OK,
CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */
CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */
CURLM_INTERNAL_ERROR, /* this is a libcurl bug */
CURLM_BAD_SOCKET, /* the passed in socket argument did not match */
CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */
CURLM_LAST
} CURLMcode;
/* just to make code nicer when using curl_multi_socket() you can now check
for CURLM_CALL_MULTI_SOCKET too in the same style it works for
curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
typedef enum {
CURLMSG_NONE, /* first, not used */
CURLMSG_DONE, /* This easy handle has completed. 'result' contains
the CURLcode of the transfer */
CURLMSG_LAST /* last, not used */
} CURLMSG;
struct CURLMsg {
CURLMSG msg; /* what this message means */
CURL *easy_handle; /* the handle it concerns */
union {
void *whatever; /* message-specific data */
CURLcode result; /* return code for transfer */
} data;
};
typedef struct CURLMsg CURLMsg;
/*
* Name: curl_multi_init()
*
* Desc: inititalize multi-style curl usage
*
* Returns: a new CURLM handle to use in all 'curl_multi' functions.
*/
CURL_EXTERN CURLM *curl_multi_init(void);
/*
* Name: curl_multi_add_handle()
*
* Desc: add a standard curl handle to the multi stack
*
* Returns: CURLMcode type, general multi error code.
*/
CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle,
CURL *curl_handle);
/*
* Name: curl_multi_remove_handle()
*
* Desc: removes a curl handle from the multi stack again
*
* Returns: CURLMcode type, general multi error code.
*/
CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
CURL *curl_handle);
/*
* Name: curl_multi_fdset()
*
* Desc: Ask curl for its fd_set sets. The app can use these to select() or
* poll() on. We want curl_multi_perform() called as soon as one of
* them are ready.
*
* Returns: CURLMcode type, general multi error code.
*/
CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
fd_set *read_fd_set,
fd_set *write_fd_set,
fd_set *exc_fd_set,
int *max_fd);
/*
* Name: curl_multi_perform()
*
* Desc: When the app thinks there's data available for curl it calls this
* function to read/write whatever there is right now. This returns
* as soon as the reads and writes are done. This function does not
* require that there actually is data available for reading or that
* data can be written, it can be called just in case. It returns
* the number of handles that still transfer data in the second
* argument's integer-pointer.
*
* Returns: CURLMcode type, general multi error code. *NOTE* that this only
* returns errors etc regarding the whole multi stack. There might
* still have occurred problems on invidual transfers even when this
* returns OK.
*/
CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
int *running_handles);
/*
* Name: curl_multi_cleanup()
*
* Desc: Cleans up and removes a whole multi stack. It does not free or
* touch any individual easy handles in any way. We need to define
* in what state those handles will be if this function is called
* in the middle of a transfer.
*
* Returns: CURLMcode type, general multi error code.
*/
CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
/*
* Name: curl_multi_info_read()
*
* Desc: Ask the multi handle if there's any messages/informationals from
* the individual transfers. Messages include informationals such as
* error code from the transfer or just the fact that a transfer is
* completed. More details on these should be written down as well.
*
* Repeated calls to this function will return a new struct each
* time, until a special "end of msgs" struct is returned as a signal
* that there is no more to get at this point.
*
* The data the returned pointer points to will not survive calling
* curl_multi_cleanup().
*
* The 'CURLMsg' struct is meant to be very simple and only contain
* very basic informations. If more involved information is wanted,
* we will provide the particular "transfer handle" in that struct
* and that should/could/would be used in subsequent
* curl_easy_getinfo() calls (or similar). The point being that we
* must never expose complex structs to applications, as then we'll
* undoubtably get backwards compatibility problems in the future.
*
* Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
* of structs. It also writes the number of messages left in the
* queue (after this read) in the integer the second argument points
* to.
*/
CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
int *msgs_in_queue);
/*
* Name: curl_multi_strerror()
*
* Desc: The curl_multi_strerror function may be used to turn a CURLMcode
* value into the equivalent human readable error string. This is
* useful for printing meaningful error messages.
*
* Returns: A pointer to a zero-terminated error message.
*/
CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
/*
* Name: curl_multi_socket() and
* curl_multi_socket_all()
*
* Desc: An alternative version of curl_multi_perform() that allows the
* application to pass in one of the file descriptors that have been
* detected to have "action" on them and let libcurl perform.
* See man page for details.
*/
#define CURL_POLL_NONE 0
#define CURL_POLL_IN 1
#define CURL_POLL_OUT 2
#define CURL_POLL_INOUT 3
#define CURL_POLL_REMOVE 4
#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD
typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */
curl_socket_t s, /* socket */
int what, /* see above */
void *userp, /* private callback
pointer */
void *socketp); /* private socket
pointer */
CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
int *running_handles);
CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
int *running_handles);
/*
* Name: curl_multi_timeout()
*
* Desc: Returns the maximum number of milliseconds the app is allowed to
* wait before curl_multi_socket() or curl_multi_perform() must be
* called (to allow libcurl's timed events to take place).
*
* Returns: CURLM error code.
*/
CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
long *milliseconds);
#undef CINIT /* re-using the same name as in curl.h */
#ifdef CURL_ISOCPP
#define CINIT(name,type,number) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + number
#else
/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
#define LONG CURLOPTTYPE_LONG
#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
#define OFF_T CURLOPTTYPE_OFF_T
#define CINIT(name,type,number) CURLMOPT_/**/name = type + number
#endif
typedef enum {
/* This is the socket callback function pointer */
CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1),
/* This is the argument passed to the socket callback */
CINIT(SOCKETDATA, OBJECTPOINT, 2),
CURLMOPT_LASTENTRY /* the last unused */
} CURLMoption;
/*
* Name: curl_multi_setopt()
*
* Desc: Sets options for the multi handle.
*
* Returns: CURLM error code.
*/
CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
CURLMoption option, ...);
/*
* Name: curl_multi_assign()
*
* Desc: This function sets an association in the multi handle between the
* given socket and a private pointer of the application. This is
* (only) useful for curl_multi_socket uses.
*
* Returns: CURLM error code.
*/
CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
curl_socket_t sockfd, void *sockp);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif

View file

@ -0,0 +1,34 @@
#ifndef __STDC_HEADERS_H
#define __STDC_HEADERS_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id: stdcheaders.h,v 1.8 2004/01/07 09:19:34 bagder Exp $
***************************************************************************/
#include <sys/types.h>
size_t fread (void *, size_t, size_t, FILE *);
size_t fwrite (const void *, size_t, size_t, FILE *);
int strcasecmp(const char *, const char *);
int strncasecmp(const char *, const char *, size_t);
#endif

View file

@ -0,0 +1 @@
/* not used */

BIN
code/libs/win32/libcurl.a Normal file

Binary file not shown.

View file

@ -1100,4 +1100,10 @@ extern huffman_t clientHuffTables;
#define CL_ENCODE_START 12 #define CL_ENCODE_START 12
#define CL_DECODE_START 4 #define CL_DECODE_START 4
// flags for sv_allowDownload and cl_allowDownload
#define DLF_ENABLE 1
#define DLF_NO_REDIRECT 2
#define DLF_NO_UDP 4
#define DLF_NO_DISCONNECT 8
#endif // _QCOMMON_H_ #endif // _QCOMMON_H_

View file

@ -801,7 +801,9 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
} }
// We open the file here // We open the file here
if ( !sv_allowDownload->integer || idPack || unreferenced || if ( !(sv_allowDownload->integer & DLF_ENABLE) ||
(sv_allowDownload->integer & DLF_NO_UDP) ||
idPack || unreferenced ||
( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) <= 0 ) { ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) <= 0 ) {
// cannot auto-download file // cannot auto-download file
if(unreferenced) if(unreferenced)
@ -818,7 +820,10 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
else { else {
Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName); Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName);
} }
} else if ( !sv_allowDownload->integer ) { }
else if ( !(sv_allowDownload->integer & DLF_ENABLE) ||
(sv_allowDownload->integer & DLF_NO_UDP) ) {
Com_Printf("clientDownload: %d : \"%s\" download disabled", cl - svs.clients, cl->downloadName); Com_Printf("clientDownload: %d : \"%s\" download disabled", cl - svs.clients, cl->downloadName);
if (sv_pure->integer) { if (sv_pure->integer) {
Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n"

View file

@ -606,6 +606,7 @@ void SV_Init (void) {
Cvar_Get ("nextmap", "", CVAR_TEMP ); Cvar_Get ("nextmap", "", CVAR_TEMP );
sv_allowDownload = Cvar_Get ("sv_allowDownload", "0", CVAR_SERVERINFO); sv_allowDownload = Cvar_Get ("sv_allowDownload", "0", CVAR_SERVERINFO);
Cvar_Get ("sv_dlURL", "", CVAR_SERVERINFO | CVAR_ARCHIVE);
sv_master[0] = Cvar_Get ("sv_master1", MASTER_SERVER_NAME, 0 ); sv_master[0] = Cvar_Get ("sv_master1", MASTER_SERVER_NAME, 0 );
sv_master[1] = Cvar_Get ("sv_master2", "", CVAR_ARCHIVE ); sv_master[1] = Cvar_Get ("sv_master2", "", CVAR_ARCHIVE );
sv_master[2] = Cvar_Get ("sv_master3", "", CVAR_ARCHIVE ); sv_master[2] = Cvar_Get ("sv_master3", "", CVAR_ARCHIVE );