* 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

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) {
#if USE_CURL
CL_cURL_Shutdown();
#endif
// clear sounds
S_DisableSounds();
// shutdown CGame
@ -1331,6 +1334,23 @@ Called when all downloading has been completed
*/
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 (clc.downloadRestart) {
clc.downloadRestart = qfalse;
@ -1418,6 +1438,7 @@ A download completed or failed
void CL_NextDownload(void) {
char *s;
char *remoteName, *localName;
qboolean useCURL = qfalse;
// We are looking to start a download here
if (*clc.downloadList) {
@ -1441,9 +1462,48 @@ void CL_NextDownload(void) {
*s++ = 0;
else
s = localName + strlen(localName); // point at the nul byte
CL_BeginDownload( localName, remoteName );
#if USE_CURL
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;
// move over the rest
@ -1466,7 +1526,7 @@ and determine if we need to download them
void CL_InitDownloads(void) {
char missingfiles[1024];
if ( !cl_allowDownload->integer )
if ( !(cl_allowDownload->integer & DLF_ENABLE) )
{
// autodownload is disabled on the client
// but it's possible that some referenced files on the server are missing
@ -2028,6 +2088,25 @@ void CL_Frame ( int msec ) {
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 ) {
// bring up the cd error dialog if needed
cls.cddialog = qfalse;
@ -2478,6 +2557,9 @@ void CL_Init( void ) {
cl_showMouseRate = Cvar_Get ("cl_showmouserate", "0", 0);
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);
#ifdef MACOS_X

View file

@ -412,6 +412,25 @@ void CL_SystemInfoChanged( void ) {
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
@ -479,6 +498,9 @@ void CL_ParseGamestate( msg_t *msg ) {
// read the checksum feed
clc.checksumFeed = MSG_ReadLong( msg );
// parse useful values out of CS_SERVERINFO
CL_ParseServerInfo();
// parse serverId and other cvars
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 "../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
#define QKEY_FILE "qkey"
@ -185,6 +189,16 @@ typedef struct {
fileHandle_t download;
char downloadTempName[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 downloadBlock; // block we are waiting for
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_allowDownload;
extern cvar_t *cl_downloadMethod;
extern cvar_t *cl_conXOffset;
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_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_

View file

@ -801,7 +801,9 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
}
// 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 ) {
// cannot auto-download file
if(unreferenced)
@ -818,7 +820,10 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg )
else {
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);
if (sv_pure->integer) {
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 );
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[1] = Cvar_Get ("sv_master2", "", CVAR_ARCHIVE );
sv_master[2] = Cvar_Get ("sv_master3", "", CVAR_ARCHIVE );