diff -Naur --exclude='*svn*' quake3/Makefile quake3-wwwDownload/Makefile --- quake3/Makefile 2006-08-25 21:31:06.000000000 +0200 +++ quake3-wwwDownload/Makefile 2006-08-24 05:23:22.000000000 +0200 @@ -104,10 +104,15 @@ USE_CODEC_VORBIS=0 endif +ifndef USE_CURL +USE_CURL=1 +endif + ifndef USE_LOCAL_HEADERS USE_LOCAL_HEADERS=1 endif + ############################################################################# BD=$(BUILD_DIR)/debug-$(PLATFORM)-$(ARCH) @@ -199,6 +204,10 @@ GL_CFLAGS = -I/usr/X11R6/include endif + ifeq ($(USE_CURL),1) + BASE_CFLAGS += -DUSE_CURL=1 $(shell curl-config --cflags) + endif + OPTIMIZE = -O3 -ffast-math -funroll-loops -fomit-frame-pointer ifeq ($(ARCH),x86_64) @@ -254,6 +263,10 @@ CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg endif + ifeq ($(USE_CURL),1) + CLIENT_LDFLAGS += $(shell curl-config --libs) + endif + ifeq ($(ARCH),i386) # linux32 make ... BASE_CFLAGS += -m32 @@ -368,6 +381,11 @@ #CLIENT_LDFLAGS += -L/usr/X11R6/$(LIB) -lX11 -lXext -lXxf86dga -lXxf86vm endif + ifeq ($(USE_CURL),1) + BASE_CFLAGS += -DUSE_CURL=1 + CLIENT_LDFLAGS += -lcurl + endif + OPTIMIZE += -O3 -ffast-math -falign-loops=16 ifneq ($(HAVE_VM_COMPILED),true) @@ -408,6 +426,10 @@ BASE_CFLAGS += -DUSE_CODEC_VORBIS=1 endif + ifeq ($(USE_CURL),1) + BASE_CFLAGS += -I/usr/local/cross-tools/i386-mingw32msvc/include -DUSE_CURL=1 -DCURL_STATICLIB=1 -DPTW32_STATIC_LIB + endif + GL_CFLAGS = MINGW_CFLAGS = -DDONT_TYPEDEF_INT32 @@ -433,6 +455,10 @@ CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg endif + ifeq ($(USE_CURL),1) + CLIENT_LDFLAGS += -L/usr/local/cross-tools/i386-mingw32msvc/lib -lcurl -lpthreadGC2 + endif + ifeq ($(ARCH),x86) # build 32bit BASE_CFLAGS += -m32 @@ -478,6 +504,10 @@ BASE_CFLAGS += $(shell sdl-config --cflags) -DUSE_SDL_VIDEO=1 -DUSE_SDL_SOUND=1 endif + ifeq ($(USE_CURL),1) + BASE_CFLAGS += $(shell curl-config --cflags) -DUSE_CURL=1 + endif + ifeq ($(ARCH),axp) CC=gcc BASE_CFLAGS += -DNO_VM_COMPILED @@ -522,6 +552,9 @@ CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg endif + ifeq ($(USE_CURL),1) + CLIENT_LDFLAGS += $(shell curl-config --libs) + endif else # ifeq freebsd @@ -610,6 +643,10 @@ GL_CFLAGS = -I/usr/openwin/include endif + ifeq ($(USE_CURL),1) + BASE_CFLAGS += -DUSE_CURL $(shell curl-config --cflags) + endif + OPTIMIZE = -O3 -ffast-math -funroll-loops ifeq ($(ARCH),sparc) @@ -645,6 +682,10 @@ CLIENT_LDFLAGS=-L/usr/openwin/$(LIB) -L/usr/X11/lib -lGLU -lX11 -lXext endif + ifeq ($(USE_CURL),1) + CLIENT_LDFLAGS += $(shell curl-config --libs) + endif + ifeq ($(ARCH),i386) # Solarix x86 make ... BASE_CFLAGS += -m32 diff -Naur --exclude='*svn*' quake3/code/client/cl_main.c quake3-wwwDownload/code/client/cl_main.c --- quake3/code/client/cl_main.c 2006-08-25 21:31:06.000000000 +0200 +++ quake3-wwwDownload/code/client/cl_main.c 2006-08-23 17:26:27.000000000 +0200 @@ -69,6 +69,10 @@ cvar_t *cl_conXOffset; cvar_t *cl_inGameVideo; +#ifdef USE_CURL +cvar_t *cl_wwwDownload; +#endif + cvar_t *cl_serverStatusResendTime; cvar_t *cl_trn; @@ -2457,6 +2460,10 @@ cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE); +#ifdef USE_CURL + cl_wwwDownload = Cvar_Get ("cl_wwwDownload", "0", CVAR_USERINFO | CVAR_ARCHIVE); +#endif + cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); #ifdef MACOS_X // In game video is REALLY slow in Mac OS X right now due to driver slowness @@ -2508,7 +2515,6 @@ Cvar_Get ("password", "", CVAR_USERINFO); Cvar_Get ("cg_predictItems", "1", CVAR_USERINFO | CVAR_ARCHIVE ); - // cgame might not be initialized before menu is used Cvar_Get ("cg_viewsize", "100", CVAR_ARCHIVE ); diff -Naur --exclude='*svn*' quake3/code/client/cl_parse.c quake3-wwwDownload/code/client/cl_parse.c --- quake3/code/client/cl_parse.c 2006-08-25 21:31:06.000000000 +0200 +++ quake3-wwwDownload/code/client/cl_parse.c 2006-08-25 15:59:50.000000000 +0200 @@ -23,6 +23,11 @@ #include "client.h" +#ifdef USE_CURL +#include +#include +#endif + char *svc_strings[256] = { "svc_bad", @@ -492,6 +497,102 @@ //===================================================================== +#ifdef USE_CURL +int downloader_callback_write(void *buffer, size_t size, size_t nmemb, void *stream){ + FS_Write( buffer, size*nmemb, ((fileHandle_t*)stream)[0] ); + return size*nmemb; +} + +int downloader_progress_func( 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; +} + +void *downloader_thread(void *ptr) { + CURL *curl; + CURLcode res; + qboolean failed = qfalse; + + curl = curl_easy_init(); + if(curl) { + clc.download = FS_SV_FOpenFileWrite(clc.downloadTempName); +// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + curl_easy_setopt(curl, CURLOPT_URL, (char *)ptr); + curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 0); + curl_easy_setopt(curl, CURLOPT_REFERER, va("ET://%s", NET_AdrToString(clc.serverAddress))); + curl_easy_setopt(curl, CURLOPT_USERAGENT, va("ID_DOWNLOAD/2.0 %s", curl_version())); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, downloader_callback_write); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &clc.download); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, downloader_progress_func); + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, NULL); + res = curl_easy_perform(curl); + if(res != CURLE_OK) { + Com_Printf("curl_easy_perfom failed: %s\n", curl_easy_strerror(res)); + failed = qtrue; + } + + curl_easy_cleanup(curl); + } + else { + Com_Printf("curl_easy_init failed when trying to start the downloader thread\n"); + failed = qtrue; + } + + if(clc.download) + FS_FCloseFile(clc.download); + + if (failed) { + FS_SV_Remove ( clc.downloadTempName ); + } + else { + FS_SV_Rename ( clc.downloadTempName, clc.downloadName ); + } + + *clc.downloadTempName = *clc.downloadName = 0; + Cvar_Set( "cl_downloadName", "" ); + + // send intentions now + // We need this because without it, we would hold the last nextdl and then start + // loading right away. If we take a while to load, the server is happily trying + // to send us that last block over and over. + // Write it twice to help make sure we acknowledge the download + CL_WritePacket(); + CL_WritePacket(); + + // get another file if needed + CL_NextDownload (); + + return NULL; +} +#endif + +/* +===================== +CL_StartWwwDownload + +A download redirect message has been received from the server +===================== +*/ +void CL_StartWwwDownload ( char *url ) { +#ifdef USE_CURL +#ifdef PTW32_STATIC_LIB + pthread_win32_process_attach_np(); +#endif + if(pthread_create( (pthread_t *)&cls.downloaderThread, NULL, downloader_thread, url )) { + Com_Printf("pthread_create failed when trying to start the downloader thread\n"); + } +#ifdef PTW32_STATIC_LIB + pthread_win32_process_detach_np(); +#endif +#else + Com_Printf("Server sent download redirect, but the client doesn't support CURL\n"); +#endif +} + /* ===================== CL_ParseDownload @@ -605,6 +706,14 @@ seq = MSG_ReadLong( msg ); s = MSG_ReadString( msg ); + // hobbes + // intercept wwwDownload + // don't pass to cgame + if (!strncmp(s, "wwwDownload", 11)) { + CL_StartWwwDownload(&s[12]); + return; + } + // see if we have already executed stored it off if ( clc.serverCommandSequence >= seq ) { return; diff -Naur --exclude='*svn*' quake3/code/client/client.h quake3-wwwDownload/code/client/client.h --- quake3/code/client/client.h 2006-08-25 21:31:06.000000000 +0200 +++ quake3-wwwDownload/code/client/client.h 2006-08-25 15:58:57.000000000 +0200 @@ -304,6 +304,10 @@ qhandle_t charSetShader; qhandle_t whiteShader; qhandle_t consoleShader; + +#ifdef USE_CURL + int downloaderThread; // pthread_t +#endif } clientStatic_t; extern clientStatic_t cls; diff -Naur --exclude='*svn*' quake3/code/qcommon/files.c quake3-wwwDownload/code/qcommon/files.c --- quake3/code/qcommon/files.c 2006-08-25 21:31:05.000000000 +0200 +++ quake3-wwwDownload/code/qcommon/files.c 2006-08-25 15:52:32.000000000 +0200 @@ -782,6 +782,32 @@ } +/* +=========== +FS_SV_Remove + +=========== +*/ +void FS_SV_Remove( const char *filename ) { + char *ospath; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + // don't let sound stutter + S_ClearSoundBuffer(); + + ospath = FS_BuildOSPath( fs_homepath->string, filename, "" ); + ospath[strlen(ospath)-1] = '\0'; + + if ( fs_debug->integer ) { + Com_Printf( "FS_SV_Remove: %s\n", ospath ); + } + + FS_Remove ( ospath ); +} + /* =========== diff -Naur --exclude='*svn*' quake3/code/qcommon/qcommon.h quake3-wwwDownload/code/qcommon/qcommon.h --- quake3/code/qcommon/qcommon.h 2006-08-25 21:31:05.000000000 +0200 +++ quake3-wwwDownload/code/qcommon/qcommon.h 2006-08-25 14:47:59.000000000 +0200 @@ -571,6 +571,7 @@ fileHandle_t FS_SV_FOpenFileWrite( const char *filename ); int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ); void FS_SV_Rename( const char *from, const char *to ); +void FS_SV_Remove( const char *filename ); int FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE ); // if uniqueFILE is true, then a new FILE will be fopened even if the file // is found in an already open pak file. If uniqueFILE is false, you must call diff -Naur --exclude='*svn*' quake3/code/server/server.h quake3-wwwDownload/code/server/server.h --- quake3/code/server/server.h 2006-08-25 21:31:04.000000000 +0200 +++ quake3-wwwDownload/code/server/server.h 2006-08-23 16:25:58.000000000 +0200 @@ -167,6 +167,8 @@ netchan_buffer_t *netchan_start_queue; netchan_buffer_t **netchan_end_queue; + int wwwDownload; // hobbes - client can do redirected downloads and does want to + int oldServerTime; } client_t; @@ -248,6 +250,12 @@ extern cvar_t *sv_lanForceRate; extern cvar_t *sv_strictAuth; +extern cvar_t *sv_wwwDownload; +extern cvar_t *sv_wwwBaseURL; +extern cvar_t *sv_wwwFallbackURL; +extern cvar_t *sv_wwwCheckPath; +extern cvar_t *sv_wwwDlDisconnected; + //=========================================================== // diff -Naur --exclude='*svn*' quake3/code/server/sv_client.c quake3-wwwDownload/code/server/sv_client.c --- quake3/code/server/sv_client.c 2006-08-25 21:31:04.000000000 +0200 +++ quake3-wwwDownload/code/server/sv_client.c 2006-08-24 06:34:19.000000000 +0200 @@ -745,6 +744,19 @@ /* ================== +SV_SendDownloadRedirect + +Send a download redirect to client, containing the URL to download from +================== +*/ +void SV_SendDownloadRedirect( client_t *cl, msg_t *msg ) { + MSG_WriteByte( msg, svc_serverCommand ); + MSG_WriteLong( msg, cl->reliableSequence++ ); + MSG_WriteString( msg, va( "wwwDownload %s/%s", sv_wwwBaseURL->string, cl->downloadName ) ); +} + +/* +================== SV_WriteDownloadToClient Check to see if the client wants a file, open it if needed and start pumping the client @@ -845,12 +857,31 @@ return; } - Com_Printf( "clientDownload: %d : beginning \"%s\"\n", cl - svs.clients, cl->downloadName ); + // hobbes + // hanlde wwwDownload + // send redirect and return + if( sv_wwwDownload && cl->wwwDownload ) { + Com_Printf( "clientDownload: %d : sending redirect for \"%s\"\n", cl - svs.clients, cl->downloadName ); - // Init - cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0; - cl->downloadCount = 0; - cl->downloadEOF = qfalse; + SV_SendDownloadRedirect( cl, msg ); + return; + + } + else { + Com_Printf( "clientDownload: %d : beginning \"%s\"\n", cl - svs.clients, cl->downloadName ); + + // Init + cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0; + cl->downloadCount = 0; + cl->downloadEOF = qfalse; + } + } + + // hobbes + // hanlde wwwDownload + // we don't need all that transfer stuff...the client will handle this + if( sv_wwwDownload && cl->wwwDownload ) { + return; } // Perform any reads that we need to @@ -1219,6 +1250,17 @@ // force the "ip" info key to "localhost" for local clients Info_SetValueForKey( cl->userinfo, "ip", "localhost" ); } + + // hobbes + // set cl->wwwDownload + val = Info_ValueForKey ( cl->userinfo, "cl_wwwDownload" ); + if(strlen(val)) { + i = atoi(val); + cl->wwwDownload = i; + } + else { + cl->wwwDownload = 0; + } } diff -Naur --exclude='*svn*' quake3/code/server/sv_init.c quake3-wwwDownload/code/server/sv_init.c --- quake3/code/server/sv_init.c 2006-08-25 21:31:04.000000000 +0200 +++ quake3-wwwDownload/code/server/sv_init.c 2006-08-25 15:26:24.000000000 +0200 @@ -619,6 +619,12 @@ sv_lanForceRate = Cvar_Get ("sv_lanForceRate", "1", CVAR_ARCHIVE ); sv_strictAuth = Cvar_Get ("sv_strictAuth", "1", CVAR_ARCHIVE ); + sv_wwwDownload = Cvar_Get ("sv_wwwDownload", "0", CVAR_ARCHIVE ); + sv_wwwBaseURL = Cvar_Get ("sv_wwwBaseURL", "", CVAR_ARCHIVE ); + sv_wwwFallbackURL = Cvar_Get ("sv_wwwFallbackURL", "", CVAR_ARCHIVE ); + sv_wwwCheckPath = Cvar_Get ("sv_wwwCheckPath", "", CVAR_ARCHIVE ); + sv_wwwDlDisconnected = Cvar_Get ("sv_wwwDlDisconnected", "0", CVAR_ARCHIVE ); + // initialize bot cvars so they are listed and can be set before loading the botlib SV_BotInitCvars(); diff -Naur --exclude='*svn*' quake3/code/server/sv_main.c quake3-wwwDownload/code/server/sv_main.c --- quake3/code/server/sv_main.c 2006-08-25 21:31:04.000000000 +0200 +++ quake3-wwwDownload/code/server/sv_main.c 2006-08-23 16:21:02.000000000 +0200 @@ -54,6 +54,12 @@ cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491) cvar_t *sv_strictAuth; +cvar_t *sv_wwwDownload; +cvar_t *sv_wwwBaseURL; +cvar_t *sv_wwwFallbackURL; +cvar_t *sv_wwwCheckPath; +cvar_t *sv_wwwDlDisconnected; + /* =============================================================================