diff --git a/engine/Makefile b/engine/Makefile index 37e34d54..240e609c 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -564,9 +564,21 @@ SERVERONLY_OBJS = \ WINDOWSSERVERONLY_OBJS = \ svmodel.o \ + net_ssl_winsspi.o \ sv_sys_win.o \ sys_win_threads.o +WINDOWS_OBJS = \ + snd_win.o \ + snd_directx.o \ + cd_win.o \ + fs_win32.o \ + in_win.o \ + sys_win.o \ + sys_win_threads.o \ + net_ssl_winsspi.o \ + $(LTO_END) resources.o $(LTO_START) + COMMON_OBJS = \ gl_alias.o \ gl_heightmap.o \ @@ -839,13 +851,13 @@ ifeq ($(FTE_TARGET),vc) GLCL_DIR=glcl_vc$(BITS) GL_LDFLAGS=$(GLLDFLAGS) $(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows GL_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) -DMULTITHREAD $(SPEEXCFLAGS) -DMSVCLIBSPATH="libs/" - GLCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SPEEX_OBJS) gl_vidnt.o snd_win.o snd_directx.o cd_win.o fs_win32.o in_win.o sys_win.o sys_win_threads.o resources.o + GLCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SPEEX_OBJS) gl_vidnt.o $(WINDOWS_OBJS) GL_OBJS= MINGL_DIR=mingl_vc$(BITS) MINGL_EXE_NAME=../fteminglqw$(BITS).exe - D3DCL_OBJS=$(D3DQUAKE_OBJS) $(SPEEX_OBJS) snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(D3DGL_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START) + D3DCL_OBJS=$(D3DQUAKE_OBJS) $(D3DGL_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS) D3D_EXE_NAME=../fted3dqw$(BITS).exe D3DCL_EXE_NAME=../fted3dclqw$(BITS).exe D3D_LDFLAGS=$(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows @@ -854,7 +866,7 @@ ifeq ($(FTE_TARGET),vc) D3DCL_DIR=d3dcl_vc$(BITS) M_EXE_NAME=../fteqw$(BITS).exe - MCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(D3DQUAKE_OBJS) $(GLQUAKE_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o resources.o + MCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(D3DQUAKE_OBJS) $(GLQUAKE_OBJS) gl_vidnt.o $(SPEEX_OBJS) $(WINDOWS_OBJS) M_CFLAGS=$(D3DCFLAGS) $(GLCFLAGS) $(W32_CFLAGS) $(D3DCFLAGS) -DMULTITHREAD $(SPEEXCFLAGS) -DMSVCLIBSPATH="libs/" MB_DIR=m_vc$(BITS) M_LDFLAGS=$(GLLDFLAGS) $(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows @@ -889,32 +901,32 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -v "win(32|64)$$"),) SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) $(BOTLIB_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START) - GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(LTO_END) resources.o $(LTO_START) + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidnt.o $(WINDOWS_OBJS) GL_EXE_NAME=../fteglqw$(BITS).exe GLCL_EXE_NAME=../fteglqwcl$(BITS).exe - GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 + GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows GL_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) $(DX7SDK) -DMULTITHREAD -DLIBVORBISFILE_STATIC $(SPEEXCFLAGS) GLB_DIR=gl_mgw$(BITS) GLCL_DIR=glcl_mgw$(BITS) NPFTE_OBJS=httpclient.o image.o sys_win_threads.o sys_npfte.o sys_axfte.o sys_plugfte.o $(LTO_END) npplug.o ../../ftequake/npapi.def $(LTO_START) NPFTE_DLL_NAME=../npfte$(BITS).dll - NPFTE_LDFLAGS=-Wl,--enable-stdcall-fixup $(IMAGELDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -loleaut32 -luuid -lstdc++ -shared + NPFTE_LDFLAGS=-Wl,--enable-stdcall-fixup $(IMAGELDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -loleaut32 -luuid -lstdc++ -shared -Wl,--subsystem,windows NPFTE_CFLAGS=$(NPFTECFLAGS) $(W32_CFLAGS) -DMULTITHREAD NPFTEB_DIR=npfte_mgw$(BITS) - MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(LTO_END) resources.o $(LTO_START) + MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidnt.o $(WINDOWS_OBJS) M_EXE_NAME=../fteqw$(BITS).exe MCL_EXE_NAME=../fteqwcl$(BITS).exe - M_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 + M_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows M_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) $(D3DCFLAGS) $(DX7SDK) -DMULTITHREAD -DLIBVORBISFILE_STATIC $(SPEEXCFLAGS) MB_DIR=m_mgw$(BITS) MCL_DIR=mcl_mgw$(BITS) - D3DCL_OBJS=$(D3DQUAKE_OBJS) $(SPEEX_OBJS) snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(D3DGL_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START) + D3DCL_OBJS=$(D3DQUAKE_OBJS) $(D3DGL_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS) D3D_EXE_NAME=../fted3dqw$(BITS).exe D3DCL_EXE_NAME=../fted3dclqw$(BITS).exe - D3D_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 + D3D_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows D3D_CFLAGS=$(D3DCFLAGS) $(W32_CFLAGS) $(DX7SDK) -DMULTITHREAD -DLIBVORBISFILE_STATIC $(SPEEXCFLAGS) D3DB_DIR=d3d_mgw$(BITS) D3DCL_DIR=d3dcl_mgw$(BITS) diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index c03f2bdb..cc7dc03b 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -2066,7 +2066,7 @@ void CL_QTVPlay_f (void) if (connrequest) host = connrequest+1; Q_strncpyz(qtvhostname, host, sizeof(qtvhostname)); - newf = FS_OpenTCP(qtvhostname); + newf = FS_OpenTCP(qtvhostname, 27599); if (!newf) { @@ -2148,7 +2148,7 @@ void CL_QTVList_f (void) { char *connrequest; vfsfile_t *newf; - newf = FS_OpenTCP(qtvhostname); + newf = FS_OpenTCP(qtvhostname, 27599); if (!newf) { @@ -2182,7 +2182,7 @@ void CL_QTVDemos_f (void) { char *connrequest; vfsfile_t *newf; - newf = FS_OpenTCP(Cmd_Argv(1)); + newf = FS_OpenTCP(Cmd_Argv(1), 27599); if (!newf) { diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index e6828a1e..d0cc1c53 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -965,13 +965,13 @@ void CLNQ_Connect_f (void) CL_BeginServerConnect(26000); } #endif - + #ifdef IRCCONNECT void CL_IRCConnect_f (void) { CL_Disconnect_f (); - if (FTENET_AddToCollection(cls.sockets, "TCP", Cmd_Argv(2), FTENET_IRCConnect_EstablishConnection, false)) + if (FTENET_AddToCollection(cls.sockets, "TCP", Cmd_Argv(2), NA_IRC, false)) { char *server; server = Cmd_Argv (1); @@ -1307,7 +1307,7 @@ void CL_Disconnect (void) #ifdef TCPCONNECT //disconnects it, without disconnecting the others. - FTENET_AddToCollection(cls.sockets, "TCP", NULL, NULL, false); + FTENET_AddToCollection(cls.sockets, "conn", NULL, NA_INVALID, false); #endif Cvar_ForceSet(&cl_servername, "none"); @@ -2855,11 +2855,17 @@ qboolean CL_AllowArbitaryDownload(char *localfile) { char *ext = COM_FileExtension(localfile); if (!strcmp(ext, "pak") || !strcmp(ext, "pk3") || !strcmp(ext, "pk4")) - allow = true; + return true; else - allow = false; + { + Con_Printf("Ignoring non-package download redirection to \"%s\"\n", localfile); + return false; + } } - return !!allow; + if (allow) + return true; + Con_Printf("Ignoring download redirection to \"%s\". This server may require you to set cl_download_redirection to 2.\n", localfile); + return false; } /* @@ -2952,10 +2958,7 @@ void CL_DownloadSize_f(void) redirection = Cmd_Argv(3); if (!CL_AllowArbitaryDownload(redirection)) - { - Con_Printf("Ignoring redirection of %s to %s\n", rname, redirection); return; - } dl = CL_DownloadFailed(rname, false); Con_DPrintf("Download of \"%s\" redirected to \"%s\".\n", rname, redirection); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 24c607cc..91f83d98 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1650,6 +1650,8 @@ int CL_DownloadRate(void) return cls.downloadedbytes/(Sys_DoubleTime() - cls.downloadstarttime); } +qboolean CL_AllowArbitaryDownload(char *localfile); + void CL_ParseChunkedDownload(void) { qbyte *svname; @@ -1659,7 +1661,7 @@ void CL_ParseChunkedDownload(void) char data[DLBLOCKSIZE]; chunknum = MSG_ReadLong(); - if (chunknum < 0) + if (chunknum == -1) { totalsize = MSG_ReadLong(); svname = MSG_ReadString(); @@ -1680,7 +1682,17 @@ void CL_ParseChunkedDownload(void) if (totalsize < 0) { - if (totalsize == -3) + if (totalsize == -4) + { + if (CL_AllowArbitaryDownload(svname)) + { + Con_Printf("Download of \"%s\" redirected to \"%s\"\n", cls.downloadremotename, svname); + if (CL_CheckOrEnqueDownloadFile(svname, NULL, 0)) + Con_Printf("However, \"%s\" already exists. You may need to delete it.\n", svname); + } + svname = cls.downloadremotename; + } + else if (totalsize == -3) Con_Printf("Server reported an error when downloading file \"%s\"\n", svname); else if (totalsize == -2) Con_Printf("Server permissions deny downloading file \"%s\"\n", svname); @@ -1698,7 +1710,10 @@ void CL_ParseChunkedDownload(void) Host_EndGame("Received second download - \"%s\"\n", svname); if (stricmp(cls.downloadremotename, svname)) + { + //fixme: we should allow extension changes, in the case of ogg/mp3/wav, or tga/png/jpg/pcx, or the addition of .gz or whatever Host_EndGame("Server sent the wrong download - \"%s\" instead of \"%s\"\n", svname, cls.downloadremotename); + } //start the new download @@ -1749,6 +1764,9 @@ void CL_ParseChunkedDownload(void) MSG_ReadData(data, DLBLOCKSIZE); + if (chunknum*DLBLOCKSIZE > downloadsize+DLBLOCKSIZE) + return; + if (!cls.downloadqw) return; diff --git a/engine/client/cl_plugin.inc b/engine/client/cl_plugin.inc index 3dc80dca..987c55c0 100644 --- a/engine/client/cl_plugin.inc +++ b/engine/client/cl_plugin.inc @@ -141,7 +141,7 @@ void Plug_DrawReloadImages(void) } } -void Plug_FreePlugImages(plugin_t *plug) +static void Plug_FreePlugImages(plugin_t *plug) { int i; for (i = 0; i < pluginimagearraylen; i++) @@ -277,8 +277,8 @@ qintptr_t VARGS Plug_CL_GetStats(void *offset, quintptr_t mask, const qintptr_t if (VM_OOB(arg[1], arg[2]*4)) return 0; - if (qrenderer == QR_NONE) - return false; + if (qrenderer == QR_NONE || !cls.state) + return 0; max = pluginstats; if (max > MAX_CL_STATS) @@ -536,7 +536,12 @@ void Plug_Client_Close(plugin_t *plug) } } - +void Plug_Client_Shutdown(void) +{ + BZ_Free(pluginimagearray); + pluginimagearray = NULL; + pluginimagearraylen = 0; +} diff --git a/engine/client/client.h b/engine/client/client.h index 5d65fdc7..495e1f92 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -768,7 +768,9 @@ extern cvar_t ruleset_allow_sensative_texture_replacements; extern cvar_t ruleset_allow_localvolume; extern cvar_t ruleset_allow_shaders; +#ifndef SERVERONLY extern client_state_t cl; +#endif typedef struct { diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 9367b83e..3189ac4e 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -810,7 +810,7 @@ static int numbootdownloads; #include "fs.h" #ifdef AVAIL_ZLIB extern searchpathfuncs_t zipfilefuncs; -static int CL_BootDownload_Extract(const char *fname, int fsize, void *ptr) +static int CL_BootDownload_Extract(const char *fname, int fsize, void *ptr, void *spath) { char buffer[512*1024]; int read; diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index ab9d5c98..68e666d5 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -412,7 +412,7 @@ void M_Media_Draw (void) char compleatenamepath[MAX_OSPATH]; char compleatenamename[MAX_OSPATH]; qboolean compleatenamemultiple; -int Com_CompleatenameCallback(const char *name, int size, void *data) +int Com_CompleatenameCallback(const char *name, int size, void *data, void *spath) { if (*compleatenamename) compleatenamemultiple = true; @@ -431,8 +431,8 @@ void Com_CompleateOSFileName(char *name) ending[-1] = '\0'; //strip a slash *compleatenamename='\0'; - Sys_EnumerateFiles(NULL, va("%s*", name), Com_CompleatenameCallback, NULL); - Sys_EnumerateFiles(NULL, va("%s*.*", name), Com_CompleatenameCallback, NULL); + Sys_EnumerateFiles(NULL, va("%s*", name), Com_CompleatenameCallback, NULL, NULL); + Sys_EnumerateFiles(NULL, va("%s*.*", name), Com_CompleatenameCallback, NULL, NULL); if (*compleatenamename) strcpy(name, compleatenamename); diff --git a/engine/client/m_multi.c b/engine/client/m_multi.c index 859add84..62ef405b 100644 --- a/engine/client/m_multi.c +++ b/engine/client/m_multi.c @@ -188,7 +188,7 @@ typedef struct { int match; } q2skinsearch_t; -int q2skin_enumerate(const char *name, int fsize, void *parm) +int q2skin_enumerate(const char *name, int fsize, void *parm, void *spath) { char blah[MAX_QPATH]; q2skinsearch_t *s = parm; diff --git a/engine/client/m_single.c b/engine/client/m_single.c index 47cde6e3..304f7754 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -494,7 +494,7 @@ static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key) return false; } -static int DemoAddItem(const char *filename, int size, void *parm) +static int DemoAddItem(const char *filename, int size, void *parm, void *spath) { int extnum; demomenu_t *menu = parm; @@ -667,7 +667,7 @@ static void ShowDemoMenu (menu_t *menu, char *path) if (*path) { Q_snprintfz(match, sizeof(match), "%s../", path); - DemoAddItem(match, 0, menu->data); + DemoAddItem(match, 0, menu->data, NULL); } Q_snprintfz(match, sizeof(match), "%s*", path); diff --git a/engine/client/p_script.c b/engine/client/p_script.c index e1720cd6..07ba4dad 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -176,6 +176,12 @@ typedef struct part_type_s { int nummodels; partmodels_t *models; + char soundname[MAX_QPATH]; + float soundvol; + float soundattn; + float sounddelay; + float soundpitch; + vec3_t rgb; //initial colour float alpha; vec3_t rgbchange; //colour delta (per second) @@ -1401,6 +1407,23 @@ static void P_ParticleEffect_f(void) else if (!strcmp(var, "nospreadlast")) ptype->flags |= PT_NOSPREADLAST; + else if (!strcmp(var, "sound")) + { + Q_strncpyz(ptype->soundname, value, sizeof(ptype->soundname)); + ptype->soundvol = atof(Cmd_Argv(2)); + if (!ptype->soundvol) + ptype->soundvol = 1; + ptype->soundattn = atof(Cmd_Argv(3)); + if (!ptype->soundattn) + ptype->soundattn = 1; + ptype->soundpitch = atof(Cmd_Argv(4)); + if (!ptype->soundpitch) + ptype->soundpitch = 100; + ptype->sounddelay = atof(Cmd_Argv(5)); + if (!ptype->sounddelay) + ptype->sounddelay = 0; + } + else if (!strcmp(var, "lightradius")) ptype->dl_radius = atof(value); else if (!strcmp(var, "lightradiusfade")) @@ -1554,13 +1577,16 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen) Q_strncatz(outstr, va("spawnvel %g %g\n", ptype->spawnvel, ptype->spawnvelvert), outstrlen); if (ptype->assoc != P_INVALID) - Q_strncatz(outstr, va("assoc %s\n", part_type[ptype->assoc].name), outstrlen); + Q_strncatz(outstr, va("assoc \"%s\"\n", part_type[ptype->assoc].name), outstrlen); Q_strncatz(outstr, va("tcoords %g %g %g %g %g %i %g\n", ptype->s1, ptype->t1, ptype->s2, ptype->t2, 1.0f, ptype->randsmax, ptype->texsstride), outstrlen); Q_strncatz(outstr, va("rotationstart %g %g\n", ptype->rotationstartmin*180/M_PI, (ptype->rotationstartmin+ptype->rotationstartrand)*180/M_PI), outstrlen); Q_strncatz(outstr, va("rotationspeed %g %g\n", ptype->rotationmin*180/M_PI, (ptype->rotationmin+ptype->rotationrand)*180/M_PI), outstrlen); + if (ptype->soundvol) + Q_strncatz(outstr, va("sound \"%s\" %g %g %g %g\n", ptype->soundname, ptype->soundvol, ptype->soundattn, ptype->soundpitch, ptype->sounddelay), outstrlen); + if (ptype->dl_radius) { Q_strncatz(outstr, va("lightradius %g\n", ptype->dl_radius), outstrlen); @@ -2994,6 +3020,10 @@ static void PScript_EffectSpawned(part_type_t *ptype, vec3_t org, vec3_t dir, in if (ptype->dl_cubemapnum) snprintf(dl->cubemapname, sizeof(dl->cubemapname), "cubemaps/%i", ptype->dl_cubemapnum); } + if (*ptype->soundname) + { + S_StartSound(0, 0, S_PrecacheSound(ptype->soundname), org, ptype->soundvol, ptype->soundattn, ptype->sounddelay, ptype->soundpitch); + } if (ptype->stain_radius) R_AddStain(org, ptype->stain_rgb[0], ptype->stain_rgb[1], ptype->stain_rgb[2], ptype->stain_radius); } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 2ae2aea0..b6d350b2 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -1056,7 +1056,6 @@ void QCBUILTIN PF_R_PolygonEnd(pubprogfuncs_t *prinst, struct globalvars_s *pr_g if (csqc_poly_flags & 4) { mesh_t mesh; - int i; memset(&mesh, 0, sizeof(mesh)); mesh.colors4f_array = cl_strisvertc + csqc_poly_startvert; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 6401632a..ee55a889 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -211,7 +211,7 @@ cvar_t vid_width = CVARF ("vid_width", "0", CVAR_ARCHIVE | CVAR_RENDERERLATCH); cvar_t r_stereo_separation = CVARD("r_stereo_separation", "4", "How far your eyes are apart, in quake units. A non-zero value will enable stereoscoping rendering. You might need some of them retro 3d glasses. Hardware support is recommended, see r_stereo_context."); -cvar_t r_stereo_method = CVARD("r_stereo_method", "0", "Value 0 = Off.\nValue 1 = Attempt hardware acceleration. Requires vid_restart.\nValue 2 = red/cyan.\nValue 3 = red/blue. Value 4=red/green"); +cvar_t r_stereo_method = CVARD("r_stereo_method", "0", "Value 0 = Off.\nValue 1 = Attempt hardware acceleration. Requires vid_restart.\nValue 2 = red/cyan.\nValue 3 = red/blue.\nValue 4=red/green.\nValue 5=eye strain."); extern cvar_t r_dodgytgafiles; extern cvar_t r_dodgypcxfiles; diff --git a/engine/client/snd_mem.c b/engine/client/snd_mem.c index a7d2c48b..2cc4616d 100644 --- a/engine/client/snd_mem.c +++ b/engine/client/snd_mem.c @@ -775,7 +775,7 @@ qboolean S_LoadSound (sfx_t *s) return false; //it failed to load once before, don't bother trying again. // see if still in memory - if (s->decoder.buf) + if (s->decoder.buf || s->decoder.decodedata) return true; if (name[1] == ':' && name[2] == '\\') diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index 24389799..56c6e55a 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -468,78 +468,78 @@ void Sys_SaveClipboard(char *text) { } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath) { - DIR *dir; - char apath[MAX_OSPATH]; - char file[MAX_OSPATH]; - char truepath[MAX_OSPATH]; - char *s; - struct dirent *ent; - struct stat st; + DIR *dir; + char apath[MAX_OSPATH]; + char file[MAX_OSPATH]; + char truepath[MAX_OSPATH]; + char *s; + struct dirent *ent; + struct stat st; -//printf("path = %s\n", gpath); -//printf("match = %s\n", match); + //printf("path = %s\n", gpath); + //printf("match = %s\n", match); - if (!gpath) - gpath = ""; - *apath = '\0'; + if (!gpath) + gpath = ""; + *apath = '\0'; - Q_strncpyz(apath, match, sizeof(apath)); - for (s = apath+strlen(apath)-1; s >= apath; s--) - { - if (*s == '/') - { - s[1] = '\0'; - match += s - apath+1; - break; - } - } - if (s < apath) //didn't find a '/' - *apath = '\0'; - - Q_snprintfz(truepath, sizeof(truepath), "%s/%s", gpath, apath); - - -//printf("truepath = %s\n", truepath); -//printf("gamepath = %s\n", gpath); -//printf("apppath = %s\n", apath); -//printf("match = %s\n", match); - dir = opendir(truepath); - if (!dir) - { - Con_DPrintf("Failed to open dir %s\n", truepath); - return true; - } - do - { - ent = readdir(dir); - if (!ent) - break; - if (*ent->d_name != '.') - { - if (wildcmp(match, ent->d_name)) - { - Q_snprintfz(file, sizeof(file), "%s/%s", truepath, ent->d_name); - - if (stat(file, &st) == 0) - { - Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); - - if (!func(file, st.st_size, parm)) - { - closedir(dir); - return false; - } - } - else - printf("Stat failed for \"%s\"\n", file); - } - } - } while(1); - closedir(dir); - - return true; + Q_strncpyz(apath, match, sizeof(apath)); + for (s = apath+strlen(apath)-1; s >= apath; s--) + { + if (*s == '/') + { + s[1] = '\0'; + match += s - apath+1; + break; + } + } + if (s < apath) //didn't find a '/' + *apath = '\0'; + + Q_snprintfz(truepath, sizeof(truepath), "%s/%s", gpath, apath); + + + //printf("truepath = %s\n", truepath); + //printf("gamepath = %s\n", gpath); + //printf("apppath = %s\n", apath); + //printf("match = %s\n", match); + dir = opendir(truepath); + if (!dir) + { + Con_DPrintf("Failed to open dir %s\n", truepath); + return true; + } + do + { + ent = readdir(dir); + if (!ent) + break; + if (*ent->d_name != '.') + { + if (wildcmp(match, ent->d_name)) + { + Q_snprintfz(file, sizeof(file), "%s/%s", truepath, ent->d_name); + + if (stat(file, &st) == 0) + { + Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); + + if (!func(file, st.st_size, parm, spath)) + { + closedir(dir); + return false; + } + } + else + printf("Stat failed for \"%s\"\n", file); + } + } + } while(1); + closedir(dir); + + return true; } #if 0 diff --git a/engine/client/sys_sdl.c b/engine/client/sys_sdl.c index 7d9be63b..07f12dc0 100644 --- a/engine/client/sys_sdl.c +++ b/engine/client/sys_sdl.c @@ -144,7 +144,7 @@ void Sys_Quit (void) //SDL provides no file enumeration facilities. #if defined(_WIN32) #include -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath) { HANDLE r; WIN32_FIND_DATA fd; @@ -191,7 +191,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const if (wildcmp(match, fd.cFileName)) { Q_snprintfz(file, sizeof(file), "%s%s/", apath2, fd.cFileName); - go = func(file, fd.nFileSizeLow, parm); + go = func(file, fd.nFileSizeLow, parm, spath); } } else @@ -199,7 +199,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const if (wildcmp(match, fd.cFileName)) { Q_snprintfz(file, sizeof(file), "%s%s", apath2, fd.cFileName); - go = func(file, fd.nFileSizeLow, parm); + go = func(file, fd.nFileSizeLow, parm, spath); } } } @@ -210,7 +210,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const } #elif defined(linux) || defined(__unix__) #include -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath) { DIR *dir; char apath[MAX_OSPATH]; @@ -268,7 +268,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const { Q_snprintfz(file, sizeof(file), "%s%s%s", apath, ent->d_name, S_ISDIR(st.st_mode)?"/":""); - if (!func(file, st.st_size, parm)) + if (!func(file, st.st_size, parm, spath)) { closedir(dir); return false; @@ -284,7 +284,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const return true; } #else -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath) { Con_Printf("Warning: Sys_EnumerateFiles not implemented\n"); return false; diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 41d4b571..dedcdb69 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -568,7 +568,8 @@ DWORD CrashExceptionHandler (DWORD exceptionCode, LPEXCEPTION_POINTERS exception BOOL (WINAPI *pIsDebuggerPresent)(void); #ifdef PRINTGLARRAYS - DumpGLState(); + if (qrenderer == QR_OPENGL) + DumpGLState(); #endif hKernel = LoadLibrary ("kernel32"); @@ -750,7 +751,7 @@ qboolean Sys_Rename (char *oldfname, char *newfname) return !rename(oldfname, newfname); } -static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (*func)(const char *, int, void *), void *parm) +static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm, void *spath) { HANDLE r; WIN32_FIND_DATA fd; @@ -771,7 +772,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart char file[MAX_OSPATH]; if (!wild) - return Sys_EnumerateFiles2(match, matchstart, nest+1, func, parm); + return Sys_EnumerateFiles2(match, matchstart, nest+1, func, parm, spath); if (nest-neststart+1> MAX_OSPATH) return 1; @@ -802,7 +803,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart Q_snprintfz(file, sizeof(file), "%s%s/", tmproot, fd.cFileName); newnest = strlen(file); strcpy(file+newnest, match+nest); - go = Sys_EnumerateFiles2(file, matchstart, newnest, func, parm); + go = Sys_EnumerateFiles2(file, matchstart, newnest, func, parm, spath); } } } @@ -835,7 +836,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 2 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, fd.cFileName); - go = func(file, fd.nFileSizeLow, parm); + go = func(file, fd.nFileSizeLow, parm, spath); } } } @@ -846,7 +847,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 1 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, fd.cFileName); - go = func(file, fd.nFileSizeLow, parm); + go = func(file, fd.nFileSizeLow, parm, spath); } } } @@ -856,7 +857,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart return go; } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm, void *spath) { char fullmatch[MAX_OSPATH]; int start; @@ -869,7 +870,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const fullmatch[start++] = '/'; fullmatch[start] = 0; strcat(fullmatch, match); - return Sys_EnumerateFiles2(fullmatch, start, start, func, parm); + return Sys_EnumerateFiles2(fullmatch, start, start, func, parm, spath); } /* @@ -1077,6 +1078,10 @@ void VARGS Sys_Printf (char *fmt, ...) char text[1024]; DWORD dummy; + conchar_t msg[1024], *end, *in; + wchar_t wide[1024], *out; + int wlen; + if (!houtput && !debugout) return; @@ -1084,24 +1089,24 @@ void VARGS Sys_Printf (char *fmt, ...) vsnprintf (text, sizeof(text), fmt, argptr); va_end (argptr); - if (debugout) + end = COM_ParseFunString(CON_WHITEMASK, text, msg, sizeof(msg), false); + out = wide; + in = msg; + wlen = 0; + for (in = msg; in < end; in++) { - //msvc debug output - conchar_t msg[1024], *end, *in; - wchar_t wide[1024], *out; - end = COM_ParseFunString(CON_WHITEMASK, text, msg, sizeof(msg), false); - out = wide; - in = msg; - for (in = msg; in < end; in++) + if (!(*in & CON_HIDDEN)) { - if (!(*in & CON_HIDDEN)) - *out++ = dequake(*in & CON_CHARMASK); + *out++ = dequake(*in & CON_CHARMASK); + wlen++; } - *out = 0; - OutputDebugStringW(wide); } + *out = 0; + + if (debugout) + OutputDebugStringW(wide); if (houtput) - WriteFile (houtput, text, strlen(text), &dummy, NULL); + WriteConsoleW(houtput, wide, wlen, &dummy, NULL); } void Sys_Quit (void) @@ -1435,8 +1440,8 @@ char *Sys_ConsoleInput (void) } } else if (ch >= ' ') { - i = utf8_encode(text+len, ch, sizeof(text)-1-len); - WriteFile(houtput, text+len, i, &dummy, NULL); + wchar_t wch = ch; + WriteConsoleW(houtput, &wch, 1, &dummy, NULL); len += i; } diff --git a/engine/client/view.c b/engine/client/view.c index a1de5dad..aafd7a37 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -1193,6 +1193,8 @@ entity_t *CL_EntityNum(int num) float CalcFov (float fov_x, float width, float height); void SCR_VRectForPlayer(vrect_t *vrect, int pnum) { + float ws; + extern cvar_t r_stereo_method, r_stereo_separation; #if MAX_SPLITS > 4 #pragma warning "Please change this function to cope with the new MAX_SPLITS value" #endif @@ -1250,15 +1252,19 @@ void SCR_VRectForPlayer(vrect_t *vrect, int pnum) if (cl.playerview[pnum].stats[STAT_VIEWZOOM]) r_refdef.fov_x *= cl.playerview[pnum].stats[STAT_VIEWZOOM]/255.0f; - if (vrect->width < (vrect->height*640)/432) + ws = 1; + if (r_stereo_method.ival == 5 && r_stereo_separation.value) + ws = 0.5; + + if (ws*vrect->width < (vrect->height*640)/432) { - r_refdef.fov_y = CalcFov(r_refdef.fov_x, (vrect->width*vid.pixelwidth)/vid.width, (vrect->height*vid.pixelheight)/vid.height); + r_refdef.fov_y = CalcFov(r_refdef.fov_x, (ws*vrect->width*vid.pixelwidth)/vid.width, (vrect->height*vid.pixelheight)/vid.height); // r_refdef.fov_x = CalcFov(r_refdef.fov_y, 432, 640); } else { r_refdef.fov_y = CalcFov(r_refdef.fov_x, 640, 432); - r_refdef.fov_x = CalcFov(r_refdef.fov_y, vrect->height, vrect->width); + r_refdef.fov_x = CalcFov(r_refdef.fov_y, vrect->height, vrect->width*ws); } } diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 1ed2d2f8..4fb087f9 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -103,6 +103,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define AVAIL_D3D #endif +#if defined(_WIN32) && !defined(_SDL) + #define HAVE_SSL +#endif + //#define DYNAMIC_ZLIB //#define DYNAMIC_LIBPNG //#define DYNAMIC_LIBJPEG diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index e324781f..a2b608e3 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -2115,7 +2115,7 @@ static qboolean VARGS Mod_TryAddSkin(const char *skinname, ...) return true; } -int Mod_EnumerateSkins(const char *name, int size, void *param) +int Mod_EnumerateSkins(const char *name, int size, void *param, void *spath) { Mod_TryAddSkin(name); return true; diff --git a/engine/common/common.c b/engine/common/common.c index 6e868f8f..7a28cbd1 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -2469,7 +2469,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t int decodeerror; char *end; uc = utf8_decode(&decodeerror, str, &end); - if (decodeerror) + if (decodeerror && !(utf8 & 2)) { utf8 &= ~1; //malformed encoding we just drop through and stop trying to decode. @@ -2486,7 +2486,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t continue; } } - if (*str == '^') + if (*str == '^' && !(flags & PFS_NOMARKUP)) { if (str[1] >= '0' && str[1] <= '9') { @@ -2664,7 +2664,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t continue; } } - else if (*str == '&' && str[1] == 'c') + else if (*str == '&' && str[1] == 'c' && !(flags & PFS_NOMARKUP)) { // ezQuake color codes @@ -2704,7 +2704,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t } } } - else if (*str == '&' && str[1] == 'r') + else if (*str == '&' && str[1] == 'r' && !(flags & PFS_NOMARKUP)) { ext = (COLOR_WHITE << CON_FGSHIFT) | (ext&~(CON_RICHFOREMASK|CON_RICHFORECOLOUR)); if (!keepmarkup) diff --git a/engine/common/common.h b/engine/common/common.h index 45e4c291..4a938180 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -292,8 +292,9 @@ void COM_ParsePlusSets (void); typedef unsigned int conchar_t; char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, qboolean ignoreflags); -#define PFS_KEEPMARKUP 1 -#define PFS_FORCEUTF8 2 +#define PFS_KEEPMARKUP 1 //leave markup in the final string (but do parse it) +#define PFS_FORCEUTF8 2 //force utf-8 decoding +#define PFS_NOMARKUP 4 //strip markup completely conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, int keepmarkup); //ext is usually CON_WHITEMASK, returns its null terminator unsigned int utf8_decode(int *error, const void *in, char **out); unsigned int utf8_encode(void *out, unsigned int unicode, int maxlen); @@ -406,7 +407,7 @@ qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto); vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto); vfsfile_t *FS_OpenTemp(void); -vfsfile_t *FS_OpenTCP(const char *name); +vfsfile_t *FS_OpenTCP(const char *name, int defaultport); void FS_UnloadPackFiles(void); void FS_ReloadPackFiles(void); char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum); @@ -441,7 +442,7 @@ qbyte *COM_LoadFile (const char *path, int usehunk); qboolean COM_LoadMapPackFile(const char *name, int offset); void COM_FlushTempoaryPacks(void); -void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *), void *parm); +void COM_EnumerateFiles (const char *match, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm); extern struct cvar_s registered; extern qboolean standard_quake; //fixme: remove diff --git a/engine/common/fs.c b/engine/common/fs.c index 8f38cfc2..c9907b3f 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -227,9 +227,19 @@ COM_Dir_f ============ */ -static int COM_Dir_List(const char *name, int size, void *parm) +static int COM_Dir_List(const char *name, int size, void *parm, void *spath) { - Con_Printf("%s (%i)\n", name, size); + char pbuf[MAX_OSPATH] = "??"; + searchpath_t *s; + for (s=com_searchpaths ; s ; s=s->next) + { + if (s->handle == spath) + { + s->funcs->GetDisplayPath(s->handle, pbuf, sizeof(pbuf)); + break; + } + } + Con_Printf("%s (%i) (%s)\n", name, size, pbuf); return 1; } @@ -693,7 +703,7 @@ char *FS_GetPackNames(char *buffer, int buffersize, int referencedonly, qboolean // '*' prefix is meant to mean 'referenced'. //really all that means to the client is that it definitely wants to download it. //if its copyrighted, the client shouldn't try to do so, as it won't be allowed. - if (search->copyprotected) + if (!search->copyprotected) Q_strncatz(buffer, "*", buffersize); } @@ -1214,7 +1224,7 @@ void FS_FreeFile(void *file) -void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *), void *parm) +void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *, void *), void *parm) { searchpath_t *search; for (search = com_searchpaths; search ; search = search->next) @@ -1338,7 +1348,7 @@ typedef struct { const char *puredesc; } wildpaks_t; -static int FS_AddWildDataFiles (const char *descriptor, int size, void *vparam) +static int FS_AddWildDataFiles (const char *descriptor, int size, void *vparam, struct searchpath_s *path) { wildpaks_t *param = vparam; vfsfile_t *vfs; diff --git a/engine/common/fs.h b/engine/common/fs.h index 7ff7cfcf..1cfe2242 100644 --- a/engine/common/fs.h +++ b/engine/common/fs.h @@ -8,7 +8,7 @@ extern hashtable_t filesystemhash; //this table is the one to build your hash re extern int fs_hash_dups; //for tracking efficiency. no functional use. extern int fs_hash_files; //for tracking efficiency. no functional use. - +struct searchpath_s; typedef struct { void (*GetDisplayPath)(void *handle, char *outpath, unsigned int pathsize); void (*ClosePath)(void *handle); @@ -17,7 +17,7 @@ typedef struct { //note that if rawfile and offset are set, many Com_FileOpens will read the raw file //otherwise ReadFile will be called instead. void (*ReadFile)(void *handle, flocation_t *loc, char *buffer); //reads the entire file in one go (size comes from loc, so make sure the loc is valid, this is for performance with compressed archives) - int (*EnumerateFiles)(void *handle, const char *match, int (*func)(const char *, int, void *), void *parm); + int (*EnumerateFiles)(void *handle, const char *match, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm); void *(*OpenNew)(vfsfile_t *file, const char *desc); //returns a handle to a new pak/path diff --git a/engine/common/fs_pak.c b/engine/common/fs_pak.c index a511856e..8a6a30a0 100644 --- a/engine/common/fs_pak.c +++ b/engine/common/fs_pak.c @@ -126,7 +126,7 @@ qboolean FSPAK_FLocate(void *handle, flocation_t *loc, const char *filename, voi } return false; } -int FSPAK_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *), void *parm) +int FSPAK_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *spath), void *parm) { pack_t *pak = handle; int num; @@ -135,7 +135,7 @@ int FSPAK_EnumerateFiles (void *handle, const char *match, int (*func)(const cha { if (wildcmp(match, pak->files[num].name)) { - if (!func(pak->files[num].name, pak->files[num].filelen, parm)) + if (!func(pak->files[num].name, pak->files[num].filelen, parm, handle)) return false; } } diff --git a/engine/common/fs_stdio.c b/engine/common/fs_stdio.c index 9316b698..efb35f65 100644 --- a/engine/common/fs_stdio.c +++ b/engine/common/fs_stdio.c @@ -240,7 +240,7 @@ static void *FSSTDIO_OpenPath(vfsfile_t *mustbenull, const char *desc) } return np; } -static int FSSTDIO_RebuildFSHash(const char *filename, int filesize, void *data) +static int FSSTDIO_RebuildFSHash(const char *filename, int filesize, void *data, void *spath) { stdiopath_t *sp = data; if (filename[strlen(filename)-1] == '/') @@ -248,7 +248,7 @@ static int FSSTDIO_RebuildFSHash(const char *filename, int filesize, void *data) char childpath[256]; Q_snprintfz(childpath, sizeof(childpath), "%s*", filename); - Sys_EnumerateFiles(sp->rootpath, childpath, FSSTDIO_RebuildFSHash, data); + Sys_EnumerateFiles(sp->rootpath, childpath, FSSTDIO_RebuildFSHash, data, spath); return true; } FS_AddFileHash(sp->depth, filename, NULL, sp); @@ -258,7 +258,7 @@ static void FSSTDIO_BuildHash(void *handle, int depth) { stdiopath_t *sp = handle; sp->depth = depth; - Sys_EnumerateFiles(sp->rootpath, "*", FSSTDIO_RebuildFSHash, handle); + Sys_EnumerateFiles(sp->rootpath, "*", FSSTDIO_RebuildFSHash, handle, handle); } static qboolean FSSTDIO_FLocate(void *handle, flocation_t *loc, const char *filename, void *hashedresult) { @@ -326,10 +326,10 @@ static void FSSTDIO_ReadFile(void *handle, flocation_t *loc, char *buffer) fclose(f); } -static int FSSTDIO_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *), void *parm) +static int FSSTDIO_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *spath), void *parm) { stdiopath_t *sp = handle; - return Sys_EnumerateFiles(sp->rootpath, match, func, parm); + return Sys_EnumerateFiles(sp->rootpath, match, func, parm, handle); } searchpathfuncs_t stdiofilefuncs = { diff --git a/engine/common/fs_win32.c b/engine/common/fs_win32.c index 7fa7955b..74de94e1 100644 --- a/engine/common/fs_win32.c +++ b/engine/common/fs_win32.c @@ -243,7 +243,7 @@ static void *VFSW32_OpenPath(vfsfile_t *mustbenull, const char *desc) } return np; } -static int VFSW32_RebuildFSHash(const char *filename, int filesize, void *handle) +static int VFSW32_RebuildFSHash(const char *filename, int filesize, void *handle, void *spath) { vfsw32path_t *wp = handle; if (filename[strlen(filename)-1] == '/') @@ -251,7 +251,7 @@ static int VFSW32_RebuildFSHash(const char *filename, int filesize, void *handle char childpath[256]; Q_snprintfz(childpath, sizeof(childpath), "%s*", filename); - Sys_EnumerateFiles(wp->rootpath, childpath, VFSW32_RebuildFSHash, wp); + Sys_EnumerateFiles(wp->rootpath, childpath, VFSW32_RebuildFSHash, wp, handle); return true; } @@ -262,7 +262,7 @@ static void VFSW32_BuildHash(void *handle, int hashdepth) { vfsw32path_t *wp = handle; wp->hashdepth = hashdepth; - Sys_EnumerateFiles(wp->rootpath, "*", VFSW32_RebuildFSHash, handle); + Sys_EnumerateFiles(wp->rootpath, "*", VFSW32_RebuildFSHash, handle, handle); } static qboolean VFSW32_FLocate(void *handle, flocation_t *loc, const char *filename, void *hashedresult) { @@ -315,10 +315,10 @@ static void VFSW32_ReadFile(void *handle, flocation_t *loc, char *buffer) fread(buffer, 1, loc->len, f); fclose(f); } -static int VFSW32_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *), void *parm) +static int VFSW32_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *spath), void *parm) { vfsw32path_t *wp = handle; - return Sys_EnumerateFiles(wp->rootpath, match, func, parm); + return Sys_EnumerateFiles(wp->rootpath, match, func, parm, handle); } diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 186cf4e0..1481bf79 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -337,7 +337,7 @@ static void FSZIP_ReadFile(void *handle, flocation_t *loc, char *buffer) return; } -static int FSZIP_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *), void *parm) +static int FSZIP_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *spath), void *parm) { zipfile_t *zip = handle; int num; @@ -346,7 +346,7 @@ static int FSZIP_EnumerateFiles (void *handle, const char *match, int (*func)(co { if (wildcmp(match, zip->files[num].name)) { - if (!func(zip->files[num].name, zip->files[num].filelen, parm)) + if (!func(zip->files[num].name, zip->files[num].filelen, parm, handle)) return false; } } diff --git a/engine/common/net.h b/engine/common/net.h index 64e4f789..db61bd0b 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -25,7 +25,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define HAVE_WEBSOCKCL #endif -typedef enum {NA_INVALID, NA_LOOPBACK, NA_IP, NA_IPV6, NA_IPX, NA_BROADCAST_IP, NA_BROADCAST_IP6, NA_BROADCAST_IPX, NA_TCP, NA_TCPV6, NA_IRC, NA_WEBSOCKET} netadrtype_t; +//FIXME: should split this into loopback/dgram/stream/irc +//with the ipv4/v6/x as a separate parameter +typedef enum {NA_INVALID, NA_LOOPBACK, NA_IP, NA_IPV6, NA_IPX, NA_BROADCAST_IP, NA_BROADCAST_IP6, NA_BROADCAST_IPX, NA_TCP, NA_TCPV6, NA_IRC, NA_WEBSOCKET, NA_NATPMP} netadrtype_t; typedef enum {NS_CLIENT, NS_SERVER} netsrc_t; @@ -80,10 +82,12 @@ int TCP_OpenStream (netadr_t remoteaddr); //makes things easier struct ftenet_connections_s; void NET_Init (void); +void SVNET_RegisterCvars(void); void NET_InitClient (void); void NET_InitServer (void); +qboolean NET_WasSpecialPacket(void); void NET_CloseServer (void); -void UDP_CloseSocket (int socket); +void UDP_CloseSocket (int socket); void NET_Shutdown (void); int NET_GetPacket (netsrc_t netsrc, int firstsock); void NET_SendPacket (netsrc_t socket, int length, void *data, netadr_t to); @@ -98,6 +102,7 @@ char *NET_AdrToString (char *s, int len, netadr_t a); char *NET_BaseAdrToString (char *s, int len, netadr_t a); qboolean NET_StringToSockaddr (const char *s, int defaultport, struct sockaddr_qstorage *sadr, int *addrfamily, int *addrsize); qboolean NET_StringToAdr (const char *s, int defaultport, netadr_t *a); +qboolean NET_PortToAdr (int adrfamily, const char *s, netadr_t *a); qboolean NET_IsClientLegal(netadr_t *adr); qboolean NET_IsLoopBackAddress (netadr_t adr); @@ -107,9 +112,7 @@ char *NET_AdrToStringMasked (char *s, int len, netadr_t a, netadr_t amask); void NET_IntegerToMask (netadr_t *a, netadr_t *amask, int bits); qboolean NET_CompareAdrMasked(netadr_t a, netadr_t b, netadr_t mask); - -struct ftenet_generic_connection_s *FTENET_IRCConnect_EstablishConnection(qboolean isserver, const char *address); -qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, struct ftenet_generic_connection_s *(*establish)(qboolean isserver, const char *address), qboolean islisten); +qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, qboolean islisten); //============================================================================ diff --git a/engine/common/net_ssl_winsspi.c b/engine/common/net_ssl_winsspi.c new file mode 100644 index 00000000..9795610b --- /dev/null +++ b/engine/common/net_ssl_winsspi.c @@ -0,0 +1,624 @@ +#include "quakedef.h" +#if defined(_WIN32) && !defined(_SDL) && defined(HAVE_SSL) +#include +#define SECURITY_WIN32 +#include +#include +#include + +//hungarian ensures we hit no macros. +static struct +{ + void *lib; + SECURITY_STATUS (WINAPI *pDecryptMessage) (PCtxtHandle,PSecBufferDesc,ULONG,PULONG); + SECURITY_STATUS (WINAPI *pEncryptMessage) (PCtxtHandle,ULONG,PSecBufferDesc,ULONG); + SECURITY_STATUS (WINAPI *pAcquireCredentialsHandleA) (SEC_CHAR*,SEC_CHAR*,ULONG,PLUID,PVOID,SEC_GET_KEY_FN,PVOID,PCredHandle,PTimeStamp); + SECURITY_STATUS (WINAPI *pInitializeSecurityContextA) (PCredHandle,PCtxtHandle,SEC_CHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp); + SECURITY_STATUS (WINAPI *pCompleteAuthToken) (PCtxtHandle,PSecBufferDesc); + SECURITY_STATUS (WINAPI *pQueryContextAttributesA) (PCtxtHandle,ULONG,PVOID); + SECURITY_STATUS (WINAPI *pFreeCredentialsHandle) (PCredHandle); + SECURITY_STATUS (WINAPI *pDeleteSecurityContext) (PCtxtHandle); +} secur; +static struct +{ + void *lib; + BOOL (WINAPI *pCertGetCertificateChain) (HCERTCHAINENGINE,PCCERT_CONTEXT,LPFILETIME,HCERTSTORE,PCERT_CHAIN_PARA,DWORD,LPVOID,PCCERT_CHAIN_CONTEXT*); + BOOL (WINAPI *pCertVerifyCertificateChainPolicy) (LPCSTR,PCCERT_CHAIN_CONTEXT,PCERT_CHAIN_POLICY_PARA,PCERT_CHAIN_POLICY_STATUS); + void (WINAPI *pCertFreeCertificateChain) (PCCERT_CHAIN_CONTEXT); +} crypt; +static qboolean SSL_Init(void) +{ + dllfunction_t secur_functable[] = + { + {(void**)&secur.pDecryptMessage, "DecryptMessage"}, + {(void**)&secur.pEncryptMessage, "EncryptMessage"}, + {(void**)&secur.pAcquireCredentialsHandleA, "AcquireCredentialsHandleA"}, + {(void**)&secur.pInitializeSecurityContextA, "InitializeSecurityContextA"}, + {(void**)&secur.pCompleteAuthToken, "CompleteAuthToken"}, + {(void**)&secur.pQueryContextAttributesA, "QueryContextAttributesA"}, + {(void**)&secur.pFreeCredentialsHandle, "FreeCredentialsHandle"}, + {(void**)&secur.pDeleteSecurityContext, "DeleteSecurityContext"}, + {NULL, NULL} + }; + + dllfunction_t crypt_functable[] = + { + {(void**)&crypt.pCertGetCertificateChain, "CertGetCertificateChain"}, + {(void**)&crypt.pCertVerifyCertificateChainPolicy, "CertVerifyCertificateChainPolicy"}, + {(void**)&crypt.pCertFreeCertificateChain, "CertFreeCertificateChain"}, + {NULL, NULL} + }; + + if (!secur.lib) + secur.lib = Sys_LoadLibrary("secur32.dll", secur_functable); + if (!crypt.lib) + crypt.lib = Sys_LoadLibrary("crypt32.dll", crypt_functable); + + return !!secur.lib && !!crypt.lib; +} + +#define MessageAttribute (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_MANUAL_CRED_VALIDATION) + +struct sslbuf +{ + char data[8192]; + int avail; + int newd; +}; + +typedef struct { + vfsfile_t funcs; + vfsfile_t *stream; + + wchar_t wpeername[256]; + enum + { + HS_ESTABLISHED, + + HS_STARTCLIENT, + HS_CLIENT, + + HS_STARTSERVER, + HS_SERVER + } handshaking; + + struct sslbuf outraw; + struct sslbuf outcrypt; + struct sslbuf inraw; + struct sslbuf incrypt; + + + CredHandle cred; + SecHandle sechnd; + int headersize, footersize; + char headerdata[1024], footerdata[1024]; +} sslfile_t; + +static int SSPI_CopyIntoBuffer(struct sslbuf *buf, const void *data, unsigned int bytes) +{ + if (bytes > sizeof(buf->data) - buf->avail) + bytes = sizeof(buf->data) - buf->avail; + memcpy(buf->data + buf->avail, data, bytes); + buf->avail += bytes; + + return bytes; +} + +static void SSPI_Error(sslfile_t *f, char *error) +{ + Sys_Printf("%s", error); + if (f->stream) + VFS_CLOSE(f->stream); + + secur.pDeleteSecurityContext(&f->sechnd); + secur.pFreeCredentialsHandle(&f->cred); + f->stream = NULL; +} + +static void SSPI_TryFlushCryptOut(sslfile_t *f) +{ + int sent; + if (f->outcrypt.avail) + sent = VFS_WRITE(f->stream, f->outcrypt.data, f->outcrypt.avail); + else + return; + + if (sent > 0) + { + memmove(f->outcrypt.data, f->outcrypt.data + sent, f->outcrypt.avail - sent); + f->outcrypt.avail -= sent; + } +} + +static int SSPI_CheckNewInCrypt(sslfile_t *f) +{ + int newd; + if (!f->stream) + return -1; + newd = VFS_READ(f->stream, f->incrypt.data+f->incrypt.avail, sizeof(f->incrypt.data) - f->incrypt.avail); + if (newd < 0) + return newd; + else + f->incrypt.avail += newd; + + return 0; +} + +//convert inbound crypt->data +static void SSPI_Decode(sslfile_t *f) +{ + SECURITY_STATUS ss; + SecBufferDesc BuffDesc; + SecBuffer SecBuff[4]; + ULONG ulQop = 0; + SecBuffer *data = NULL; + SecBuffer *extra = NULL; + int i; + + if (!f->incrypt.avail) + return; + + BuffDesc.ulVersion = SECBUFFER_VERSION; + BuffDesc.cBuffers = 4; + BuffDesc.pBuffers = SecBuff; + + SecBuff[0].BufferType = SECBUFFER_DATA; + SecBuff[0].cbBuffer = f->incrypt.avail; + SecBuff[0].pvBuffer = f->incrypt.data; + + SecBuff[1].BufferType = SECBUFFER_EMPTY; //space for header + SecBuff[2].BufferType = SECBUFFER_EMPTY; //space for footer + SecBuff[3].BufferType = SECBUFFER_EMPTY; //space for extra marker + + ss = secur.pDecryptMessage(&f->sechnd, &BuffDesc, 0, &ulQop); + + if (ss < 0) + { + SSPI_Error(f, "DecryptMessage failed"); + return; + } + + for (i = 0; i < BuffDesc.cBuffers; i++) + { + if (SecBuff[i].BufferType == SECBUFFER_DATA && !data) + data = &SecBuff[i]; + if (SecBuff[i].BufferType == SECBUFFER_EXTRA && !extra) + extra = &SecBuff[i]; + } + + //copy the data out to the result, yay. + if (data) + SSPI_CopyIntoBuffer(&f->inraw, data->pvBuffer, data->cbBuffer); + + //retain the extra. if there's no extra then mark it so. + if (extra) + { + memmove(f->incrypt.data, f->incrypt.data + (f->incrypt.avail - extra->cbBuffer), extra->cbBuffer); + f->incrypt.avail = extra->cbBuffer; + } + else + f->incrypt.avail = 0; +} + +//convert outgoing data->crypt +static void SSPI_Encode(sslfile_t *f) +{ + SECURITY_STATUS ss; + SecBufferDesc BuffDesc; + SecBuffer SecBuff[4]; + ULONG ulQop = 0; + + if (f->outcrypt.avail) + { + SSPI_TryFlushCryptOut(f); + if (f->outcrypt.avail) + return; //don't flood too much + } + + + //don't corrupt the handshake data. + if (f->handshaking) + return; + + if (!f->outraw.avail) + return; + + BuffDesc.ulVersion = SECBUFFER_VERSION; + BuffDesc.cBuffers = 4; + BuffDesc.pBuffers = SecBuff; + + SecBuff[0].BufferType = SECBUFFER_STREAM_HEADER; + SecBuff[0].cbBuffer = f->headersize; + SecBuff[0].pvBuffer = f->headerdata; + + SecBuff[1].BufferType = SECBUFFER_DATA; + SecBuff[1].cbBuffer = f->outraw.avail; + SecBuff[1].pvBuffer = f->outraw.data; + + SecBuff[2].BufferType = SECBUFFER_STREAM_TRAILER; + SecBuff[2].cbBuffer = f->footersize; + SecBuff[2].pvBuffer = f->footerdata; + + SecBuff[3].BufferType = SECBUFFER_EMPTY; + + ss = secur.pEncryptMessage(&f->sechnd, ulQop, &BuffDesc, 0); + + if (ss < 0) + { + SSPI_Error(f, "EncryptMessage failed"); + return; + } + + f->outraw.avail = 0; + + //fixme: these should be made non-fatal. + if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[0].pvBuffer, SecBuff[0].cbBuffer) < SecBuff[0].cbBuffer) + { + SSPI_Error(f, "crypt buffer overflowed"); + return; + } + if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[1].pvBuffer, SecBuff[1].cbBuffer) < SecBuff[1].cbBuffer) + { + SSPI_Error(f, "crypt buffer overflowed"); + return; + } + if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[2].pvBuffer, SecBuff[2].cbBuffer) < SecBuff[2].cbBuffer) + { + SSPI_Error(f, "crypt buffer overflowed"); + return; + } + + SSPI_TryFlushCryptOut(f); +} + +static DWORD VerifyServerCertificate(PCCERT_CONTEXT pServerCert, PWSTR pwszServerName, DWORD dwCertFlags) +{ + HTTPSPolicyCallbackData polHttps; + CERT_CHAIN_POLICY_PARA PolicyPara; + CERT_CHAIN_POLICY_STATUS PolicyStatus; + CERT_CHAIN_PARA ChainPara; + PCCERT_CHAIN_CONTEXT pChainContext; + DWORD Status; + LPSTR rgszUsages[] = + { + szOID_PKIX_KP_SERVER_AUTH, + szOID_SERVER_GATED_CRYPTO, + szOID_SGC_NETSCAPE + }; + DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR); + + if(pServerCert == NULL) + return SEC_E_WRONG_PRINCIPAL; + if(!*pwszServerName) + return SEC_E_WRONG_PRINCIPAL; + + // Build certificate chain. + memset(&ChainPara, 0, sizeof(ChainPara)); + ChainPara.cbSize = sizeof(ChainPara); + ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; + ChainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages; + ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages; + + if (!crypt.pCertGetCertificateChain(NULL, pServerCert, NULL, pServerCert->hCertStore, &ChainPara, 0, NULL, &pChainContext)) + { + Status = GetLastError(); + Sys_Printf("Error 0x%x returned by CertGetCertificateChain!\n", Status); + } + else + { + // Validate certificate chain. + memset(&polHttps, 0, sizeof(HTTPSPolicyCallbackData)); + polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData); + polHttps.dwAuthType = AUTHTYPE_SERVER; + polHttps.fdwChecks = dwCertFlags; + polHttps.pwszServerName = pwszServerName; + + memset(&PolicyPara, 0, sizeof(PolicyPara)); + PolicyPara.cbSize = sizeof(PolicyPara); + PolicyPara.pvExtraPolicyPara = &polHttps; + + memset(&PolicyStatus, 0, sizeof(PolicyStatus)); + PolicyStatus.cbSize = sizeof(PolicyStatus); + + if (!crypt.pCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus)) + { + Status = GetLastError(); + Sys_Printf("Error 0x%x returned by CertVerifyCertificateChainPolicy!\n", Status); + } + else + { + if (PolicyStatus.dwError) + { + char *err; + Status = PolicyStatus.dwError; + switch (Status) + { + case CERT_E_EXPIRED: err = "CERT_E_EXPIRED"; break; + case CERT_E_VALIDITYPERIODNESTING: err = "CERT_E_VALIDITYPERIODNESTING"; break; + case CERT_E_ROLE: err = "CERT_E_ROLE"; break; + case CERT_E_PATHLENCONST: err = "CERT_E_PATHLENCONST"; break; + case CERT_E_CRITICAL: err = "CERT_E_CRITICAL"; break; + case CERT_E_PURPOSE: err = "CERT_E_PURPOSE"; break; + case CERT_E_ISSUERCHAINING: err = "CERT_E_ISSUERCHAINING"; break; + case CERT_E_MALFORMED: err = "CERT_E_MALFORMED"; break; + case CERT_E_UNTRUSTEDROOT: err = "CERT_E_UNTRUSTEDROOT"; break; + case CERT_E_CHAINING: err = "CERT_E_CHAINING"; break; + case TRUST_E_FAIL: err = "TRUST_E_FAIL"; break; + case CERT_E_REVOKED: err = "CERT_E_REVOKED"; break; + case CERT_E_UNTRUSTEDTESTROOT: err = "CERT_E_UNTRUSTEDTESTROOT"; break; + case CERT_E_REVOCATION_FAILURE: err = "CERT_E_REVOCATION_FAILURE"; break; + case CERT_E_CN_NO_MATCH: err = "CERT_E_CN_NO_MATCH"; break; + case CERT_E_WRONG_USAGE: err = "CERT_E_WRONG_USAGE"; break; + default: err = "(unknown)"; break; + } + Sys_Printf("Error verifying certificate for %s: %s\n", pwszServerName, err); + } + else + Status = SEC_E_OK; + } + crypt.pCertFreeCertificateChain(pChainContext); + } + + return Status; +} + +static void SSPI_Handshake (sslfile_t *f) +{ + SECURITY_STATUS ss; + TimeStamp Lifetime; + SecBufferDesc OutBuffDesc; + SecBuffer OutSecBuff; + SecBufferDesc InBuffDesc; + SecBuffer InSecBuff[2]; + ULONG ContextAttributes; + SCHANNEL_CRED SchannelCred; + + if (f->outcrypt.avail) + { + //don't let things build up too much + SSPI_TryFlushCryptOut(f); + if (f->outcrypt.avail) + return; + } + + OutBuffDesc.ulVersion = SECBUFFER_VERSION; + OutBuffDesc.cBuffers = 1; + OutBuffDesc.pBuffers = &OutSecBuff; + + OutSecBuff.cbBuffer = sizeof(f->outcrypt.data) - f->outcrypt.avail; + OutSecBuff.BufferType = SECBUFFER_TOKEN; + OutSecBuff.pvBuffer = f->outcrypt.data + f->outcrypt.avail; + + if (f->handshaking == HS_STARTCLIENT) + { + //no input data yet. + f->handshaking = HS_CLIENT; + + memset(&SchannelCred, 0, sizeof(SchannelCred)); + SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; + SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1 | SP_PROT_SSL3; + SchannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS; /*don't use windows login info or anything*/ + + ss = secur.pAcquireCredentialsHandleA (NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &SchannelCred, NULL, NULL, &f->cred, &Lifetime); + if (ss < 0) + { + SSPI_Error(f, "AcquireCredentialsHandle failed\n"); + return; + } + + ss = secur.pInitializeSecurityContextA (&f->cred, NULL, NULL, MessageAttribute, 0, SECURITY_NATIVE_DREP, NULL, 0, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime); + } + else + { + //only if we actually have data. + if (!f->incrypt.avail) + return; + + InBuffDesc.ulVersion = SECBUFFER_VERSION; + InBuffDesc.cBuffers = 2; + InBuffDesc.pBuffers = InSecBuff; + + InSecBuff[0].BufferType = SECBUFFER_TOKEN; + InSecBuff[0].cbBuffer = f->incrypt.avail; + InSecBuff[0].pvBuffer = f->incrypt.data; + + InSecBuff[1].BufferType = SECBUFFER_EMPTY; + InSecBuff[1].pvBuffer = NULL; + InSecBuff[1].cbBuffer = 0; + + ss = secur.pInitializeSecurityContextA (&f->cred, &f->sechnd, NULL, MessageAttribute, 0, SECURITY_NATIVE_DREP, &InBuffDesc, 0, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime); + + if (ss == SEC_E_INCOMPLETE_MESSAGE) + return; + + //any extra data should still remain for the next time around. this might be more handshake data or payload data. + if (InSecBuff[1].BufferType == SECBUFFER_EXTRA) + { + memmove(f->incrypt.data, f->incrypt.data + (f->incrypt.avail - InSecBuff[1].cbBuffer), InSecBuff[1].cbBuffer); + f->incrypt.avail = InSecBuff[1].cbBuffer; + } + else f->incrypt.avail = 0; + } + + if (ss == SEC_I_INCOMPLETE_CREDENTIALS) + { + SSPI_Error(f, "server requires credentials\n"); + return; + } + + if (ss < 0) + { + SSPI_Error(f, "InitializeSecurityContext failed\n"); + return; + } + + if ((SEC_I_COMPLETE_NEEDED == ss) || (SEC_I_COMPLETE_AND_CONTINUE == ss)) + { + ss = secur.pCompleteAuthToken (&f->sechnd, &OutBuffDesc); + if (ss < 0) + { + SSPI_Error(f, "CompleteAuthToken failed\n"); + return; + } + } + + if (SSPI_CopyIntoBuffer(&f->outcrypt, OutSecBuff.pvBuffer, OutSecBuff.cbBuffer) < OutSecBuff.cbBuffer) + { + SSPI_Error(f, "crypt overflow\n"); + return; + } + + //send early, send often. + SSPI_TryFlushCryptOut(f); + + //its all okay and established if we get this far. + if (ss == SEC_E_OK) + { + SecPkgContext_StreamSizes strsizes; + CERT_CONTEXT *remotecert; + + secur.pQueryContextAttributesA(&f->sechnd, SECPKG_ATTR_STREAM_SIZES, &strsizes); + f->headersize = strsizes.cbHeader; + f->footersize = strsizes.cbTrailer; + f->handshaking = HS_ESTABLISHED; + + if (*f->wpeername) + { + ss = secur.pQueryContextAttributesA(&f->sechnd, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &remotecert); + if (ss != SEC_E_OK) + { + SSPI_Error(f, "unable to read server's certificate\n"); + return; + } + if (VerifyServerCertificate(remotecert, f->wpeername, 0)) + SSPI_Error(f, "Error validating certificante"); + } + else + Sys_Printf("SSL/TLS Server name not specified, skipping verification\n"); + + + SSPI_Encode(f); + } +} + +static int SSPI_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread) +{ + sslfile_t *f = (sslfile_t *)file; + int err = SSPI_CheckNewInCrypt(f); + + if (f->handshaking) + { + SSPI_Handshake(f); + return err; + } + + SSPI_Encode(f); + + SSPI_Decode(f); + + bytestoread = min(bytestoread, f->inraw.avail); + if (bytestoread) + { + memcpy(buffer, f->inraw.data, bytestoread); + f->inraw.avail -= bytestoread; + memmove(f->inraw.data, f->inraw.data + bytestoread, f->inraw.avail); + } + else + { + if (err) + return err; + } + return bytestoread; +} +static int SSPI_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestowrite) +{ + sslfile_t *f = (sslfile_t *)file; + + bytestowrite = SSPI_CopyIntoBuffer(&f->outraw, buffer, bytestowrite); + + if (f->handshaking) + { + SSPI_CheckNewInCrypt(f); //make sure its ticking over + SSPI_Handshake(f); + } + else + { + SSPI_Encode(f); + } + + return bytestowrite; +} +static qboolean SSPI_Seek (struct vfsfile_s *file, unsigned long pos) +{ + SSPI_Error((sslfile_t*)file, "unable to seek on streams"); + return false; +} +static unsigned long SSPI_Tell (struct vfsfile_s *file) +{ + SSPI_Error((sslfile_t*)file, "unable to seek on streams"); + return 0; +} +static unsigned long SSPI_GetLen (struct vfsfile_s *file) +{ + return 0; +} +static void SSPI_Close (struct vfsfile_s *file) +{ + SSPI_Error((sslfile_t*)file, ""); + Z_Free(file); +} + +#include +vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server) +{ + sslfile_t *newf; + int i = 0; + int err; + unsigned int c; + + if (!source || !SSL_Init()) + { + VFS_CLOSE(source); + return NULL; + } + if (!hostname) + hostname = ""; + + if (server) //unsupported + { + VFS_CLOSE(source); + return NULL; + } + + newf = Z_Malloc(sizeof(*newf)); + while(*hostname) + { + c = utf8_decode(&err, hostname, (void*)&hostname); + if (c > WCHAR_MAX) + err = true; //no 16bit surrogates. they're evil. + else if (i == sizeof(newf->wpeername)/sizeof(newf->wpeername[0]) - 1) + err = true; //no space to store it + else + newf->wpeername[i++] = c; + if (err) + { + Z_Free(newf); + VFS_CLOSE(source); + return NULL; + } + } + newf->wpeername[i] = 0; + newf->handshaking = server?HS_STARTSERVER:HS_STARTCLIENT; + newf->stream = source; + newf->funcs.Close = SSPI_Close; + newf->funcs.Flush = NULL; + newf->funcs.GetLen = SSPI_GetLen; + newf->funcs.ReadBytes = SSPI_ReadBytes; + newf->funcs.Seek = SSPI_Seek; + newf->funcs.Tell = SSPI_Tell; + newf->funcs.WriteBytes = SSPI_WriteBytes; + newf->funcs.seekingisabadplan = true; + + return &newf->funcs; +} +#endif diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 854dd7e1..ae7fa998 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -63,22 +63,17 @@ void (*pfreeaddrinfo) (struct addrinfo*); #endif #endif -void NET_GetLocalAddress (int socket, netadr_t *out); -int TCP_OpenListenSocket (int port); -#ifdef HAVE_IPV4 -extern cvar_t sv_port_ipv4; +#if defined(HAVE_IPV4) && !defined(CLIENTONLY) +#define HAVE_NATPMP #endif + +void NET_GetLocalAddress (int socket, netadr_t *out); +//int TCP_OpenListenSocket (const char *localip, int port); #ifdef IPPROTO_IPV6 int UDP6_OpenSocket (int port, qboolean bcast); -extern cvar_t sv_port_ipv6; #endif #ifdef USEIPX void IPX_CloseSocket (int socket); -extern cvar_t sv_port_ipx; -#endif -#ifdef TCPCONNECT -extern cvar_t sv_port_tcp; -extern cvar_t sv_port_tcp6; #endif cvar_t net_hybriddualstack = CVAR("net_hybriddualstack", "1"); cvar_t net_fakeloss = CVARFD("net_fakeloss", "0", CVAR_CHEAT, "Simulates packetloss in both receiving and sending, on a scale from 0 to 1."); @@ -87,6 +82,28 @@ extern cvar_t sv_public, sv_listen_qw, sv_listen_nq, sv_listen_dp, sv_listen_q3; static qboolean allowconnects = false; + +#define FTENET_ADDRTYPES 2 +typedef struct ftenet_generic_connection_s { + char name[MAX_QPATH]; + + int (*GetLocalAddress)(struct ftenet_generic_connection_s *con, netadr_t *local, int adridx); + qboolean (*ChangeLocalAddress)(struct ftenet_generic_connection_s *con, const char *newaddress); + qboolean (*GetPacket)(struct ftenet_generic_connection_s *con); + qboolean (*SendPacket)(struct ftenet_generic_connection_s *con, int length, void *data, netadr_t to); + void (*Close)(struct ftenet_generic_connection_s *con); +#ifdef HAVE_PACKET + int (*SetReceiveFDSet) (struct ftenet_generic_connection_s *con, fd_set *fdset); /*set for connections which have multiple sockets (ie: listening tcp connections)*/ +#endif + + netadrtype_t addrtype[FTENET_ADDRTYPES]; + qboolean islisten; + int thesocket; +} ftenet_generic_connection_t; + + + + #define MAX_LOOPBACK 8 typedef struct { @@ -96,6 +113,7 @@ typedef struct typedef struct { + qboolean inited; loopmsg_t msgs[MAX_LOOPBACK]; int get, send; } loopback_t; @@ -222,7 +240,42 @@ void SockadrToNetadr (struct sockaddr_qstorage *s, netadr_t *a) qboolean NET_CompareAdr (netadr_t a, netadr_t b) { if (a.type != b.type) + { + int i; + if (a.type == NA_IP && b.type == NA_IPV6) + { + for (i = 0; i < 10; i++) + if (b.address.ip6[i] != 0) + return false; //only matches if they're 0s, otherwise its not an ipv4 address there + for (; i < 12; i++) + if (b.address.ip6[i] != 0xff && b.address.ip6[i] != 0x00) //0x00 is depricated + return false; //only matches if they're 0s or ffs, otherwise its not an ipv4 address there + for (i = 0; i < 4; i++) + { + if (a.address.ip[i] != b.address.ip6[12+i]) + return false; //mask doesn't match + } + return true; //its an ipv4 address in there, the mask matched the whole way through + } + if (a.type == NA_IPV6 && b.type == NA_IP) + { + for (i = 0; i < 10; i++) + if (a.address.ip6[i] != 0) + return false; //only matches if they're 0s, otherwise its not an ipv4 address there + + for (; i < 12; i++) + if (a.address.ip6[i] != 0xff && a.address.ip6[i] != 0x00) //0x00 is depricated + return false; //only matches if they're 0s or ffs, otherwise its not an ipv4 address there + + for (i = 0; i < 4; i++) + { + if (a.address.ip6[12+i] != b.address.ip[i]) + return false; //mask doesn't match + } + return true; //its an ipv4 address in there, the mask matched the whole way through + } return false; + } if (a.type == NA_LOOPBACK) return true; @@ -943,6 +996,17 @@ qboolean NET_StringToAdr (const char *s, int defaultport, netadr_t *a) return true; } #endif +#ifdef HAVE_NATPMP + if (!strncmp (s, "natpmp://", 9)) + { + NET_PortToAdr(NA_NATPMP, s+9, a); + if (a->type == NA_IP) + a->type = NA_NATPMP; + if (a->type != NA_NATPMP) + return false; + return true; + } +#endif if (!NET_StringToSockaddr (s, defaultport, &sadr, NULL, NULL)) { @@ -1424,11 +1488,15 @@ qboolean NET_IsLoopBackAddress (netadr_t adr) ///////////////////////////////////////////// //loopback stuff -qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *from, sizebuf_t *message) +#if !defined(CLIENTONLY) && !defined(SERVERONLY) + +qboolean NET_GetLoopPacket (int sock, netadr_t *from, sizebuf_t *message) { int i; loopback_t *loop; + sock &= 1; + loop = &loopbacks[sock]; if (loop->send - loop->get > MAX_LOOPBACK) @@ -1459,11 +1527,13 @@ qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *from, sizebuf_t *message) } -void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to) +void NET_SendLoopPacket (int sock, int length, void *data, netadr_t to) { int i; loopback_t *loop; + sock &= 1; + loop = &loopbacks[sock^1]; if (length > sizeof(loop->msgs[i].data)) @@ -1478,28 +1548,74 @@ void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to) memcpy (loop->msgs[i].data, data, length); loop->msgs[i].datalen = length; } + +int FTENET_Loop_GetLocalAddress(ftenet_generic_connection_t *con, netadr_t *out, int adrnum) +{ + if (adrnum==0) + { + out->type = NA_LOOPBACK; + out->port = con->thesocket+1; + } + return 1; +} + +qboolean FTENET_Loop_GetPacket(ftenet_generic_connection_t *con) +{ + return NET_GetLoopPacket(con->thesocket, &net_from, &net_message); +} + +qboolean FTENET_Loop_SendPacket(ftenet_generic_connection_t *con, int length, void *data, netadr_t to) +{ + if (to.type == NA_LOOPBACK) + { + NET_SendLoopPacket(con->thesocket, length, data, to); + return true; + } + + return false; +} + +void FTENET_Loop_Close(ftenet_generic_connection_t *con) +{ + int sock = con->thesocket; + sock &= 1; + loopbacks[sock].inited = false; + Z_Free(con); +} + +static ftenet_generic_connection_t *FTENET_Loop_EstablishConnection(qboolean isserver, const char *address) +{ + ftenet_generic_connection_t *newcon; + int sock; + for (sock = 0; sock < 2; sock++) + if (!loopbacks[sock].inited) + break; + if (sock == 2) + return NULL; + newcon = Z_Malloc(sizeof(*newcon)); + if (newcon) + { + loopbacks[sock].inited = true; + + newcon->GetLocalAddress = FTENET_Loop_GetLocalAddress; + newcon->GetPacket = FTENET_Loop_GetPacket; + newcon->SendPacket = FTENET_Loop_SendPacket; + newcon->Close = FTENET_Loop_Close; + + newcon->islisten = isserver; + newcon->addrtype[0] = NA_LOOPBACK; + newcon->addrtype[1] = NA_INVALID; + + newcon->thesocket = sock; + } + return newcon; +} +#endif //============================================================================= -#define FTENET_ADDRTYPES 2 -typedef struct ftenet_generic_connection_s { - const char *name; - - int (*GetLocalAddress)(struct ftenet_generic_connection_s *con, netadr_t *local, int adridx); - qboolean (*ChangeLocalAddress)(struct ftenet_generic_connection_s *con, const char *newaddress); - qboolean (*GetPacket)(struct ftenet_generic_connection_s *con); - qboolean (*SendPacket)(struct ftenet_generic_connection_s *con, int length, void *data, netadr_t to); - void (*Close)(struct ftenet_generic_connection_s *con); -#ifdef HAVE_PACKET - int (*SetReceiveFDSet) (struct ftenet_generic_connection_s *con, fd_set *fdset); /*set for connections which have multiple sockets (ie: listening tcp connections)*/ -#endif - - netadrtype_t addrtype[FTENET_ADDRTYPES]; - qboolean islisten; - int thesocket; -} ftenet_generic_connection_t; - #define MAX_CONNECTIONS 8 -typedef struct ftenet_connections_s { +typedef struct ftenet_connections_s +{ qboolean islisten; ftenet_generic_connection_t *conn[MAX_CONNECTIONS]; } ftenet_connections_t; @@ -1511,14 +1627,300 @@ ftenet_connections_t *FTENET_CreateCollection(qboolean listen) col->islisten = listen; return col; } +static ftenet_generic_connection_t *FTENET_Loop_EstablishConnection(qboolean isserver, const char *address); +static ftenet_generic_connection_t *FTENET_UDP4_EstablishConnection(qboolean isserver, const char *address); +static ftenet_generic_connection_t *FTENET_UDP6_EstablishConnection(qboolean isserver, const char *address); +static ftenet_generic_connection_t *FTENET_TCP4Connect_EstablishConnection(qboolean isserver, const char *address); +static ftenet_generic_connection_t *FTENET_TCP6Connect_EstablishConnection(qboolean isserver, const char *address); +static ftenet_generic_connection_t *FTENET_IPX_EstablishConnection(qboolean isserver, const char *address); +static ftenet_generic_connection_t *FTENET_WebSocket_EstablishConnection(qboolean isserver, const char *address); +static ftenet_generic_connection_t *FTENET_IRCConnect_EstablishConnection(qboolean isserver, const char *address); +static ftenet_generic_connection_t *FTENET_NATPMP_EstablishConnection(qboolean isserver, const char *address); -qboolean FTENET_AddToCollection(ftenet_connections_t *col, const char *name, const char *address, ftenet_generic_connection_t *(*establish)(qboolean isserver, const char *address), qboolean islisten) +#ifdef HAVE_NATPMP +typedef struct +{ + ftenet_generic_connection_t pub; + ftenet_connections_t *col; + netadr_t reqpmpaddr; + netadr_t pmpaddr; + netadr_t natadr; + unsigned int refreshtime; +} pmpcon_t; + +int FTENET_NATPMP_GetLocalAddress(struct ftenet_generic_connection_s *con, netadr_t *local, int adridx); +static qboolean NET_Was_NATPMP(ftenet_connections_t *collection) +{ + pmpcon_t *pmp; + struct + { + qbyte ver; qbyte op; short resultcode; + int age; + union + { + struct + { + short privport; short pubport; + int mapping_expectancy; + }; + qbyte ipv4[4]; + }; + } *pmpreqrep; + int i; + + for (i = 0; i < MAX_CONNECTIONS; i++) + { + if (!collection->conn[i]) + continue; + if (collection->conn[i]->GetLocalAddress == FTENET_NATPMP_GetLocalAddress) + { + pmp = (pmpcon_t*)collection->conn[i]; + if (NET_CompareAdr(pmp->pmpaddr, net_from)) + { + pmpreqrep = (void*)net_message.data; + + if (pmpreqrep->ver != 0) + return false; + if (net_message.cursize == 12 && pmpreqrep->op == 128) + { + char adrbuf[256]; + pmp->natadr.type = NA_IP; + pmp->natadr.port = 0; + memcpy(pmp->natadr.address.ip, pmpreqrep->ipv4, sizeof(pmp->natadr.address.ip)); + NET_AdrToString(adrbuf, sizeof(adrbuf), pmp->natadr); +// Con_Printf("Public ip is %s\n", adrbuf); + return true; + } + if (net_message.cursize == 16 && pmpreqrep->op == 129) + { + switch(BigShort(pmpreqrep->resultcode)) + { + case 0: + break; + case 1: + Con_Printf("NAT-PMP: unsupported version\n"); + return true; + case 2: + Con_Printf("NAT-PMP: refused - please reconfigure router\n"); + return true; + case 3: + Con_Printf("NAT-PMP: network failure\n"); + return true; + case 4: + Con_Printf("NAT-PMP: out of resources\n"); + return true; + case 5: + Con_Printf("NAT-PMP: unsupported opcode\n"); + return true; + default: + return false; + } + +// Con_Printf("Local port %u publically available on port %u\n", (unsigned short)BigShort(pmpreqrep->privport), (unsigned short)BigShort(pmpreqrep->pubport)); + pmp->natadr.port = pmpreqrep->pubport; + return true; + } + return false; + } + } + } + return false; +} + +static void FTENET_NATPMP_Refresh(pmpcon_t *pmp, short oldport, ftenet_connections_t *collection) +{ + int i; + int adrno, adrcount=1; + netadr_t adr; + struct + { + qbyte ver; qbyte op; short reserved1; + short privport; short pubport; + int mapping_expectancy; + } pmpreqmsg; + + pmpreqmsg.ver = 0; + pmpreqmsg.op = 1; + pmpreqmsg.reserved1 = BigShort(0); + pmpreqmsg.privport = BigShort(0); + pmpreqmsg.pubport = BigShort(0); + pmpreqmsg.mapping_expectancy = BigLong(60*5); + + if (!collection) + return; + + for (i = 0; i < MAX_CONNECTIONS; i++) + { + if (!collection->conn[i]) + continue; + if (collection->conn[i]->GetLocalAddress && collection->conn[i]->GetLocalAddress != FTENET_NATPMP_GetLocalAddress) + { + for (adrno = 0, adrcount=1; (adrcount = collection->conn[i]->GetLocalAddress(collection->conn[i], &adr, adrno)) && adrno < adrcount; adrno++) + { +// Con_Printf("net address (%s): %s\n", collection->conn[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), adr)); + + //unipv6ify it if its a hybrid socket. + if (adr.type == NA_IPV6 && + !*(int*)&adr.address.ip6[0] && + !*(int*)&adr.address.ip6[4] && + !*(short*)&adr.address.ip6[8] && + *(short*)&adr.address.ip6[10]==(short)0xffff && + !*(int*)&adr.address.ip6[12]) + { + *(int*)adr.address.ip = *(int*)&adr.address.ip6[12]; + adr.type = NA_IP; + } + + if (adr.type == NA_IP) + { + if (adr.address.ip[0] == 127) //yes. loopback has a lot of ip addresses. wasteful but whatever. + continue; + + //assume a netmask of 255.255.255.0 + adr.address.ip[3] = 1; + } +// else if (adr.type == NA_IPV6) +// { +// } + else + continue; + + pmpreqmsg.privport = adr.port; + pmpreqmsg.pubport = oldport?oldport:adr.port; + + if (*(int*)pmp->reqpmpaddr.address.ip == INADDR_ANY) + { + pmp->pmpaddr = adr; + pmp->pmpaddr.port = pmp->reqpmpaddr.port; + } + else + pmp->pmpaddr = pmp->reqpmpaddr; + + //get the public ip. + pmpreqmsg.op = 0; + NET_SendPacket(NS_SERVER, 2, &pmpreqmsg, pmp->pmpaddr); + + //open the firewall/nat. + pmpreqmsg.op = 1; + NET_SendPacket(NS_SERVER, sizeof(pmpreqmsg), &pmpreqmsg, pmp->pmpaddr); + } + } + } +} +#define PMP_POLL_TIME (1000*30)//every 30 seconds +int FTENET_NATPMP_GetLocalAddress(struct ftenet_generic_connection_s *con, netadr_t *local, int adridx) +{ + pmpcon_t *pmp = (pmpcon_t*)con; + local->type = NA_INVALID; + + if (adridx == 0) + *local = pmp->natadr; + return (pmp->natadr.type != NA_INVALID) && (pmp->natadr.port != 0); +} +qboolean FTENET_NATPMP_GetPacket(struct ftenet_generic_connection_s *con) +{ + pmpcon_t *pmp = (pmpcon_t*)con; + unsigned int now = Sys_Milliseconds(); + if (now - pmp->refreshtime > PMP_POLL_TIME) //weird logic to cope with wrapping + { + pmp->refreshtime = now; + FTENET_NATPMP_Refresh(pmp, pmp->natadr.port, pmp->col); + } + return false; +} +qboolean FTENET_NATPMP_SendPacket(struct ftenet_generic_connection_s *con, int length, void *data, netadr_t to) +{ + return false; +} +qboolean FTENET_NATPMP_Close(struct ftenet_generic_connection_s *con) +{ + //FIXME: we should send a packet to close the port + Z_Free(con); + return true; +} +ftenet_generic_connection_t *FTENET_NATPMP_EstablishConnection(qboolean isserver, const char *address) +{ + pmpcon_t *pmp; + netadr_t pmpadr; + + NET_PortToAdr(NA_IP, address, &pmpadr); + if (pmpadr.type == NA_NATPMP) + pmpadr.type = NA_IP; + if (pmpadr.type != NA_IP) + return NULL; + + pmp = Z_Malloc(sizeof(*pmp)); + pmp->col = svs.sockets; + Q_strncpyz(pmp->pub.name, "natpmp", sizeof(pmp->pub.name)); + pmp->reqpmpaddr = pmpadr; + pmp->pub.GetLocalAddress = FTENET_NATPMP_GetLocalAddress; + pmp->pub.GetPacket = FTENET_NATPMP_GetPacket; + //qboolean (*ChangeLocalAddress)(struct ftenet_generic_connection_s *con, const char *newaddress); + pmp->pub.SendPacket = FTENET_NATPMP_SendPacket; + pmp->pub.Close = FTENET_NATPMP_Close; + pmp->pub.thesocket = INVALID_SOCKET; + + pmp->refreshtime = Sys_Milliseconds() + PMP_POLL_TIME*64; + + return &pmp->pub; +} +#endif + +qboolean FTENET_AddToCollection(ftenet_connections_t *col, const char *name, const char *address, netadrtype_t addrtype, qboolean islisten) { int count = 0; int i; + netadr_t adr; + ftenet_generic_connection_t *(*establish)(qboolean isserver, const char *address) = NULL; + if (!col) return false; + if (!address || !*address) + adr.type = NA_INVALID; + else if (islisten) + NET_PortToAdr(addrtype, address, &adr); + else + NET_StringToAdr(address, 0, &adr); + + switch(adr.type) + { + default: establish = NULL; break; +#ifdef HAVE_NATPMP + case NA_NATPMP: establish = FTENET_NATPMP_EstablishConnection; break; +#endif +#if !defined(CLIENTONLY) && !defined(SERVERONLY) + case NA_LOOPBACK: establish = FTENET_Loop_EstablishConnection; break; +#endif +#ifdef HAVE_IPV4 + case NA_IP: establish = FTENET_UDP4_EstablishConnection; break; +#endif +#ifdef IPPROTO_IPV6 + case NA_IPV6: establish = FTENET_UDP6_EstablishConnection; break; +#endif +#ifdef USEIPX + case NA_IPX: establish = FTENET_IPX_EstablishConnection; break; +#endif + case NA_WEBSOCKET: +#ifdef HAVE_WEBSOCKCL + if (!islisten) + establish = FTENET_WebSocket_EstablishConnection; +#endif +#ifdef TCPCONNECT + establish = FTENET_TCP4Connect_EstablishConnection; +#endif + break; +#ifdef IRCCONNECT + case NA_IRC: establish = FTENET_IRCConnect_EstablishConnection; break; +#endif +#ifdef TCPCONNECT + case NA_TCP: establish = FTENET_TCP4Connect_EstablishConnection; break; +#endif +#if defined(TCPCONNECT) && defined(IPPROTO_IPV6) + case NA_TCPV6: establish = FTENET_TCP6Connect_EstablishConnection; break; +#endif + } + if (name) { for (i = 0; i < MAX_CONNECTIONS; i++) @@ -1539,7 +1941,7 @@ qboolean FTENET_AddToCollection(ftenet_connections_t *col, const char *name, con } } - if (address && *address) + if (address && *address && establish) { for (i = 0; i < MAX_CONNECTIONS; i++) { @@ -1549,7 +1951,8 @@ qboolean FTENET_AddToCollection(ftenet_connections_t *col, const char *name, con col->conn[i] = establish(islisten, com_token); if (!col->conn[i]) break; - col->conn[i]->name = name; + if (name) + Q_strncpyz(col->conn[i]->name, name, sizeof(col->conn[i]->name)); count++; if (address && *address) @@ -1585,56 +1988,6 @@ void FTENET_Generic_Close(ftenet_generic_connection_t *con) Z_Free(con); } -#if !defined(CLIENTONLY) && !defined(SERVERONLY) - -int FTENET_Loop_GetLocalAddress(ftenet_generic_connection_t *con, netadr_t *out, int adrnum) -{ - if (adrnum==0) - { - out->type = NA_LOOPBACK; - out->port = con->islisten+1; - } - return 1; -} - -qboolean FTENET_Loop_GetPacket(ftenet_generic_connection_t *con) -{ - return NET_GetLoopPacket(con->islisten, &net_from, &net_message); -} - -qboolean FTENET_Loop_SendPacket(ftenet_generic_connection_t *con, int length, void *data, netadr_t to) -{ - if (to.type == NA_LOOPBACK) - { - NET_SendLoopPacket(con->islisten, length, data, to); - return true; - } - - return false; -} - -ftenet_generic_connection_t *FTENET_Loop_EstablishConnection(qboolean isserver, const char *address) -{ - ftenet_generic_connection_t *newcon; - newcon = Z_Malloc(sizeof(*newcon)); - if (newcon) - { - newcon->name = "Loopback"; - newcon->GetLocalAddress = FTENET_Loop_GetLocalAddress; - newcon->GetPacket = FTENET_Loop_GetPacket; - newcon->SendPacket = FTENET_Loop_SendPacket; - newcon->Close = FTENET_Generic_Close; - - newcon->islisten = isserver; - newcon->addrtype[0] = NA_LOOPBACK; - newcon->addrtype[1] = NA_INVALID; - - newcon->thesocket = INVALID_SOCKET; - } - return newcon; -} -#endif - int FTENET_Generic_GetLocalAddress(ftenet_generic_connection_t *con, netadr_t *out, int count) { #ifndef HAVE_PACKET @@ -1946,28 +2299,9 @@ qboolean NET_PortToAdr (int adrfamily, const char *s, netadr_t *a) { memset(a, 0, sizeof(*a)); a->port = htons((unsigned short)port); - switch(adrfamily) - { -#ifdef HAVE_IPV4 - case AF_INET: - a->type = NA_IP; - return true; -#endif -#ifdef IPPROTO_IPV6 - case AF_INET6: - a->type = NA_IPV6; - return true; -#endif -#ifdef USEIPX - case AF_IPX: - a->type = NA_IPX; - return true; -#endif - default: - a->type = NA_INVALID; - return false; - } - return false; + a->type = adrfamily; + + return a->type != NA_INVALID; } a->type = NA_INVALID; return false; @@ -2087,7 +2421,6 @@ ftenet_generic_connection_t *FTENET_Generic_EstablishConnection(int adrfamily, i newcon = Z_Malloc(sizeof(*newcon)); if (newcon) { - newcon->name = "Generic"; newcon->GetLocalAddress = FTENET_Generic_GetLocalAddress; newcon->GetPacket = FTENET_Generic_GetPacket; newcon->SendPacket = FTENET_Generic_SendPacket; @@ -2120,19 +2453,19 @@ ftenet_generic_connection_t *FTENET_Generic_EstablishConnection(int adrfamily, i #ifdef IPPROTO_IPV6 ftenet_generic_connection_t *FTENET_UDP6_EstablishConnection(qboolean isserver, const char *address) { - return FTENET_Generic_EstablishConnection(AF_INET6, IPPROTO_UDP, isserver, address); + return FTENET_Generic_EstablishConnection(NA_IPV6, IPPROTO_UDP, isserver, address); } #endif #ifdef HAVE_IPV4 ftenet_generic_connection_t *FTENET_UDP4_EstablishConnection(qboolean isserver, const char *address) { - return FTENET_Generic_EstablishConnection(AF_INET, IPPROTO_UDP, isserver, address); + return FTENET_Generic_EstablishConnection(NA_IP, IPPROTO_UDP, isserver, address); } #endif #ifdef USEIPX ftenet_generic_connection_t *FTENET_IPX_EstablishConnection(qboolean isserver, const char *address) { - return FTENET_Generic_EstablishConnection(AF_IPX, NSPROTO_IPX, isserver, address); + return FTENET_Generic_EstablishConnection(NA_IPX, NSPROTO_IPX, isserver, address); } #endif @@ -2935,7 +3268,6 @@ ftenet_generic_connection_t *FTENET_TCPConnect_EstablishConnection(int affamily, newcon = Z_Malloc(sizeof(*newcon)); if (newcon) { - newcon->generic.name = "TCPConnect"; if (isserver) newcon->generic.GetLocalAddress = FTENET_Generic_GetLocalAddress; newcon->generic.GetPacket = FTENET_TCPConnect_GetPacket; @@ -2985,13 +3317,13 @@ ftenet_generic_connection_t *FTENET_TCPConnect_EstablishConnection(int affamily, #ifdef IPPROTO_IPV6 ftenet_generic_connection_t *FTENET_TCP6Connect_EstablishConnection(qboolean isserver, const char *address) { - return FTENET_TCPConnect_EstablishConnection(AF_INET6, isserver, address); + return FTENET_TCPConnect_EstablishConnection(NA_TCPV6, isserver, address); } #endif ftenet_generic_connection_t *FTENET_TCP4Connect_EstablishConnection(qboolean isserver, const char *address) { - return FTENET_TCPConnect_EstablishConnection(AF_INET, isserver, address); + return FTENET_TCPConnect_EstablishConnection(NA_TCP, isserver, address); } #endif @@ -3548,7 +3880,6 @@ struct ftenet_generic_connection_s *FTENET_IRCConnect_EstablishConnection(qboole newcon = Z_Malloc(sizeof(*newcon)); if (newcon) { - newcon->generic.name = "IRCConnect"; newcon->generic.GetPacket = FTENET_IRCConnect_GetPacket; newcon->generic.SendPacket = FTENET_IRCConnect_SendPacket; newcon->generic.Close = FTENET_IRCConnect_Close; @@ -3768,7 +4099,7 @@ static ftenet_generic_connection_t *FTENET_WebSocket_EstablishConnection(qboolea struct PP_Var str = ppb_var_interface->VarFromUtf8(adr.address.websocketurl, strlen(adr.address.websocketurl)); ppb_websocket_interface->Connect(newsocket, str, NULL, 0, ccb); ppb_var_interface->Release(str); - newcon->generic.name = "WebSocket"; + Q_strncpyz(newcon->generic.name, "WebSocket", sizeof(newcon->generic.name)); newcon->generic.GetPacket = FTENET_WebSocket_GetPacket; newcon->generic.SendPacket = FTENET_WebSocket_SendPacket; newcon->generic.Close = FTENET_WebSocket_Close; @@ -3911,30 +4242,13 @@ qboolean NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char switch(adr.type) { -#ifdef HAVE_WEBSOCKCL case NA_WEBSOCKET: - if (!FTENET_AddToCollection(collection, routename, host, FTENET_WebSocket_EstablishConnection, islisten)) - return false; - break; -#endif -#ifdef TCPCONNECT case NA_TCP: - if (!FTENET_AddToCollection(collection, routename, host, FTENET_TCP4Connect_EstablishConnection, islisten)) - return false; - break; -#ifdef IPPROTO_IPV6 case NA_TCPV6: - if (!FTENET_AddToCollection(collection, routename, host, FTENET_TCP6Connect_EstablishConnection, islisten)) - return false; - break; -#endif -#endif -#ifdef IRCCONNECT case NA_IRC: - if (!FTENET_AddToCollection(collection, routename, host, FTENET_IRCConnect_EstablishConnection, islisten)) + if (!FTENET_AddToCollection(collection, routename, host, adr.type, islisten)) return false; break; -#endif default: //not recognised, or not needed break; @@ -3956,15 +4270,16 @@ void NET_PrintAddresses(ftenet_connections_t *collection) { if (!collection->conn[i]) continue; + adrno = 0; if (collection->conn[i]->GetLocalAddress) { - for (adrno = 0, adrcount=1; (adrcount = collection->conn[i]->GetLocalAddress(collection->conn[i], &adr, adrno)) && adrno < adrcount; adrno++) + for (adrcount=1; (adrcount = collection->conn[i]->GetLocalAddress(collection->conn[i], &adr, adrno)) && adrno < adrcount; adrno++) { - Con_Printf("net address: %s\n", NET_AdrToString(adrbuf, sizeof(adrbuf), adr)); + Con_Printf("net address (%s): %s\n", collection->conn[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), adr)); } } - else - Con_Printf("%s\n", collection->conn[i]->name); + if (!adrno) + Con_Printf("net address (%s): no addresses\n", collection->conn[i]->name); } } @@ -3980,12 +4295,15 @@ int TCP_OpenStream (netadr_t remoteaddr) int temp; struct sockaddr_qstorage qs; // struct sockaddr_qstorage loc; + int recvbufsize = (1<<19);//512kb temp = NetadrToSockadr(&remoteaddr, &qs); if ((newsocket = socket (((struct sockaddr_in*)&qs)->sin_family, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return INVALID_SOCKET; + setsockopt(newsocket, SOL_SOCKET, SO_RCVBUF, (void*)&recvbufsize, sizeof(recvbufsize)); + // memset(&loc, 0, sizeof(loc)); // ((struct sockaddr*)&loc)->sa_family = ((struct sockaddr*)&loc)->sa_family; // bind(newsocket, (struct sockaddr *)&loc, ((struct sockaddr_in*)&qs)->sin_family == AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6)); @@ -4016,32 +4334,46 @@ int TCP_OpenStream (netadr_t remoteaddr) #endif } -int TCP_OpenListenSocket (int port) +/*int TCP_OpenListenSocket (const char *localip, int port) { #ifndef HAVE_TCP return INVALID_SOCKET; #else int newsocket; - struct sockaddr_in address; + struct sockaddr_qstorage address; + int pf; unsigned long _true = true; int i; int maxport = port + 100; - if ((newsocket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) + if (localip && *localip) + { + if (!NET_StringToSockaddr(localip, port, &address, &pf, &adrsize)) + return INVALID_SOCKET; + } + else + { + adrsize = sizeof(struct sockaddr_in); + pf = ((struct sockaddr_in*)&address)->sin_family = AF_INET; + ((struct sockaddr_in*)&address)->sin_port = htons(port); + + //ZOID -- check for interface binding option + if ((i = COM_CheckParm("-ip")) != 0 && i < com_argc) + { + ((struct sockaddr_in*)&address)->sin_addr.s_addr = inet_addr(com_argv[i+1]); + Con_TPrintf(TL_NETBINDINTERFACE, + inet_ntoa(address.sin_addr)); + } + else + ((struct sockaddr_in*)&address)->sin_addr.s_addr = INADDR_ANY; + } + + if ((newsocket = socket (pf, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return INVALID_SOCKET; if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) Sys_Error ("TCP_OpenListenSocket: ioctl FIONBIO: %s", strerror(qerrno)); - address.sin_family = AF_INET; -//ZOID -- check for interface binding option - if ((i = COM_CheckParm("-ip")) != 0 && i < com_argc) { - address.sin_addr.s_addr = inet_addr(com_argv[i+1]); - Con_TPrintf(TL_NETBINDINTERFACE, - inet_ntoa(address.sin_addr)); - } else - address.sin_addr.s_addr = INADDR_ANY; - for(;;) { if (port == PORT_ANY) @@ -4079,7 +4411,7 @@ int maxport = port + 100; return newsocket; #endif } - +*/ #if defined(SV_MASTER) || defined(CL_MASTER) int UDP_OpenSocket (int port, qboolean bcast) @@ -4378,68 +4710,131 @@ void NET_GetLocalAddress (int socket, netadr_t *out) #ifndef CLIENTONLY void SVNET_AddPort_f(void) { - netadr_t adr; char *s = Cmd_Argv(1); + char *conname = Cmd_Argv(2); + + if (!*s && !*conname) + { + Con_Printf("Active Server ports:\n"); + NET_PrintAddresses(svs.sockets); + Con_Printf("end of list\n"); + return; + } + if (!*conname) + conname = NULL; //just in case if (!svs.sockets) { svs.sockets = FTENET_CreateCollection(true); #ifndef SERVERONLY - FTENET_AddToCollection(svs.sockets, "SVLoopback", "27500", FTENET_Loop_EstablishConnection, true); + FTENET_AddToCollection(svs.sockets, "SVLoopback", "27500", NA_LOOPBACK, true); #endif } -#ifdef HAVE_IPV4 - NET_PortToAdr(AF_INET, s, &adr); -#else - adr.type = NA_INVALID; -#endif + FTENET_AddToCollection(svs.sockets, conname, *s?s:NULL, *s?NA_IP:NA_INVALID, true); +} - switch(adr.type) +typedef struct +{ + unsigned short msgtype; + unsigned short msglen; + unsigned int magiccookie; + unsigned int transactid[3]; +} stunhdr_t; +typedef struct +{ + unsigned short attrtype; + unsigned short attrlen; +} stunattr_t; +static qboolean NET_WasStun(void) +{ + if ((net_from.type == NA_IP || net_from.type == NA_IPV6) && net_message.cursize >= 20) { -#ifdef HAVE_IPV4 - case NA_IP: - FTENET_AddToCollection(svs.sockets, NULL, s, FTENET_UDP4_EstablishConnection, true); - break; -#endif -#ifdef IPPROTO_IPV6 - case NA_IPV6: - FTENET_AddToCollection(svs.sockets, NULL, s, FTENET_UDP6_EstablishConnection, true); - break; -#endif - case NA_IPX: -#ifdef USEIPX - FTENET_AddToCollection(svs.sockets, NULL, s, FTENET_IPX_EstablishConnection, true); -#endif - break; -#ifdef IRCCONNECT - case NA_IRC: - FTENET_AddToCollection(svs.sockets, NULL, s, FTENET_IRCConnect_EstablishConnection, true); - break; -#endif -#ifdef IRCCONNECT - case NA_TCP: - FTENET_AddToCollection(svs.sockets, NULL, s, FTENET_TCP4Connect_EstablishConnection, true); - break; -#ifdef IPPROTO_IPV6 - case NA_TCPV6: - FTENET_AddToCollection(svs.sockets, NULL, s, FTENET_TCP6Connect_EstablishConnection, true); - break; -#endif -#endif - // warning: enumeration value ‘NA_*’ not handled in switch - case NA_WEBSOCKET: - case NA_INVALID: - case NA_LOOPBACK: - case NA_BROADCAST_IP: - case NA_BROADCAST_IP6: - case NA_BROADCAST_IPX: - break; + stunhdr_t *stun = (stunhdr_t*)net_message.data; + int stunlen = BigShort(stun->msglen); + if (stun->msgtype == BigShort(0x0101) && net_message.cursize == stunlen + sizeof(*stun)) + { + stunattr_t *attr = (stunattr_t*)(stun+1); + int alen; + while(stunlen) + { + stunlen -= sizeof(*attr); + alen = BigShort(attr->attrlen); + if (alen > stunlen) + return false; + if (attr->attrtype == BigShort(1) && alen == 8 && ((qbyte*)attr)[5] == 1) //ipv4 MAPPED-ADDRESS + { + netadr_t adr; + char str[256]; + adr.type = NA_IP; + adr.port = (((short*)attr)[3]); + memcpy(adr.address.ip, &((qbyte*)attr)[8], 4); + NET_AdrToString(str, sizeof(str), adr); + Con_Printf("Public address %s\n", str); + } + else if (attr->attrtype == BigShort(1) && alen == 20 && ((qbyte*)attr)[5] == 2) //ipv6 MAPPED-ADDRESS + { + netadr_t adr; + char str[256]; + adr.type = NA_IPV6; + adr.port = (((short*)attr)[3]); + memcpy(adr.address.ip6, &((qbyte*)attr)[8], 16); + NET_AdrToString(str, sizeof(str), adr); + Con_Printf("Public address %s\n", str); + } + attr = (stunattr_t*)((char*)(attr+1) + alen); + } + return true; + } } + return false; +} +void SVNET_Stun_f(void) +{ + char *stunserver = Cmd_Argv(1); + netadr_t stunserverip; + struct { + stunhdr_t hdr; + } stunmsg; + + //"stun.l.google.com:19302" + + if (!NET_StringToAdr(stunserver, 3478, &stunserverip) || stunserverip.type != NA_IP) + { + Con_Printf("Specified stun server was not resolved or was not udp v4\n"); + return; + } + + stunmsg.hdr.magiccookie = BigLong(0x2112a442); + Sys_RandomBytes((qbyte*)&stunmsg.hdr.transactid[0], sizeof(stunmsg.hdr.transactid)); // 'and SHOULD be cryptographically random' + stunmsg.hdr.msgtype = BigShort(0x0001); //binding request + stunmsg.hdr.msglen = BigShort(0); + NET_SendPacket(NS_SERVER, sizeof(stunmsg), &stunmsg, stunserverip); } #endif +#ifndef SERVERONLY +void NET_ClientPort_f(void) +{ + Con_Printf("Active Client ports:\n"); + NET_PrintAddresses(cls.sockets); + Con_Printf("end of list\n"); +} +#endif + +qboolean NET_WasSpecialPacket(void) +{ +#ifndef CLIENTONLY + if (NET_WasStun()) + return true; +#endif +#ifdef HAVE_NATPMP + if (NET_Was_NATPMP(svs.sockets)) + return true; +#endif + return false; +} /* ==================== NET_Init @@ -4448,7 +4843,6 @@ NET_Init void NET_Init (void) { #ifdef _WIN32 - WORD wVersionRequested; int r; #ifdef IPPROTO_IPV6 HMODULE ws2_32dll; @@ -4468,8 +4862,6 @@ void NET_Init (void) pgetaddrinfo = NULL; #endif - wVersionRequested = MAKEWORD(1, 1); - r = WSAStartup (MAKEWORD(1, 1), &winsockdata); if (r) @@ -4481,6 +4873,10 @@ void NET_Init (void) #ifndef CLIENTONLY Cmd_AddCommand("sv_addport", SVNET_AddPort_f); + Cmd_AddCommand("sv_stun", SVNET_Stun_f); +#endif +#ifndef SERVERONLY + Cmd_AddCommand("cl_addport", NET_ClientPort_f); #endif } #ifndef SERVERONLY @@ -4490,11 +4886,6 @@ void NET_InitClient(void) int p; port = STRINGIFY(PORT_QWCLIENT); - p = COM_CheckParm ("-port"); - if (p && p < com_argc) - { - port = com_argv[p+1]; - } p = COM_CheckParm ("-clport"); if (p && p < com_argc) { @@ -4503,16 +4894,16 @@ void NET_InitClient(void) cls.sockets = FTENET_CreateCollection(false); #ifndef CLIENTONLY - FTENET_AddToCollection(cls.sockets, "CLLoopback", port, FTENET_Loop_EstablishConnection, false); + FTENET_AddToCollection(cls.sockets, "CLLoopback", port, NA_LOOPBACK, true); #endif #ifdef HAVE_IPV4 - FTENET_AddToCollection(cls.sockets, "CLUDP4", port, FTENET_UDP4_EstablishConnection, true); + FTENET_AddToCollection(cls.sockets, "CLUDP4", port, NA_IP, true); #endif #ifdef IPPROTO_IPV6 - FTENET_AddToCollection(cls.sockets, "CLUDP6", port, FTENET_UDP6_EstablishConnection, true); + FTENET_AddToCollection(cls.sockets, "CLUDP6", port, NA_IPV6, true); #endif #ifdef USEIPX - FTENET_AddToCollection(cls.sockets, "CLIPX", port, FTENET_IPX_EstablishConnection, true); + FTENET_AddToCollection(cls.sockets, "CLIPX", port, NA_IPX, true); #endif // @@ -4524,43 +4915,109 @@ void NET_InitClient(void) Con_TPrintf(TL_CLIENTPORTINITED); } #endif -#ifndef CLIENTONLY - - #ifndef CLIENTONLY #ifdef HAVE_IPV4 void SV_Tcpport_Callback(struct cvar_s *var, char *oldvalue) { - FTENET_AddToCollection(svs.sockets, "SVTCP4", var->string, FTENET_TCP4Connect_EstablishConnection, true); + FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_TCP, true); } +cvar_t sv_port_tcp = CVARC("sv_port_tcp", "", SV_Tcpport_Callback); #endif #ifdef IPPROTO_IPV6 void SV_Tcpport6_Callback(struct cvar_s *var, char *oldvalue) { - FTENET_AddToCollection(svs.sockets, "SVTCP6", var->string, FTENET_TCP6Connect_EstablishConnection, true); + FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_TCPV6, true); } +cvar_t sv_port_tcp6 = CVARC("sv_port_tcp6", "", SV_Tcpport6_Callback); #endif - #ifdef HAVE_IPV4 void SV_Port_Callback(struct cvar_s *var, char *oldvalue) { - FTENET_AddToCollection(svs.sockets, "SVUDP4", var->string, FTENET_UDP4_EstablishConnection, true); + FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IP, true); } +cvar_t sv_port_ipv4 = CVARC("sv_port", "27500", SV_Port_Callback); #endif #ifdef IPPROTO_IPV6 void SV_PortIPv6_Callback(struct cvar_s *var, char *oldvalue) { - FTENET_AddToCollection(svs.sockets, "SVUDP6", var->string, FTENET_UDP6_EstablishConnection, true); + FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IPV6, true); } +cvar_t sv_port_ipv6 = CVARC("sv_port_ipv6", "", SV_PortIPv6_Callback); #endif #ifdef USEIPX void SV_PortIPX_Callback(struct cvar_s *var, char *oldvalue) { - FTENET_AddToCollection(svs.sockets, "SVIPX", var->string, FTENET_IPX_EstablishConnection, true); + FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IPX, true); } +cvar_t sv_port_ipx = CVARC("sv_port_ipx", "", SV_PortIPX_Callback); #endif +#ifdef HAVE_NATPMP +void SV_Port_NatPMP_Callback(struct cvar_s *var, char *oldvalue) +{ + FTENET_AddToCollection(svs.sockets, var->name, va("natpmp://%s", var->string), NA_NATPMP, true); +} +#ifdef SERVERONLY +#define NATPMP_DEFAULT_PORT "" //don't fuck with dedicated servers +#else +#define NATPMP_DEFAULT_PORT "5351" //home users, yay, lucky people. #endif +cvar_t sv_port_natpmp = CVARCD("sv_port_natpmp", NATPMP_DEFAULT_PORT, SV_Port_NatPMP_Callback, "If set (typically to 5351), automatically configures your router's port forwarding. You can instead specify the full ip address of your router (192.168.1.1:5351 for example). Your router must have NAT-PMP supported and enabled."); +#endif + +void SVNET_RegisterCvars(void) +{ + int p; + +#if defined(TCPCONNECT) && defined(HAVE_IPV4) + Cvar_Register (&sv_port_tcp, "networking"); + sv_port_tcp.restriction = RESTRICT_MAX; +#endif +#if defined(TCPCONNECT) && defined(IPPROTO_IPV6) + Cvar_Register (&sv_port_tcp6, "networking"); + sv_port_tcp6.restriction = RESTRICT_MAX; +#endif +#ifdef IPPROTO_IPV6 + Cvar_Register (&sv_port_ipv6, "networking"); + sv_port_ipv6.restriction = RESTRICT_MAX; +#endif +#ifdef USEIPX + Cvar_Register (&sv_port_ipx, "networking"); + sv_port_ipx.restriction = RESTRICT_MAX; +#endif +#ifdef HAVE_IPV4 + Cvar_Register (&sv_port_ipv4, "networking"); + sv_port_ipv4.restriction = RESTRICT_MAX; +#endif +#ifdef HAVE_NATPMP + Cvar_Register (&sv_port_natpmp, "networking"); + sv_port_natpmp.restriction = RESTRICT_MAX; +#endif + + // parse params for cvars + p = COM_CheckParm ("-port"); + if (!p) + p = COM_CheckParm ("-svport"); + if (p && p < com_argc) + { + extern cvar_t sv_port_ipv4, sv_port_ipv6, sv_port_ipx; + int port = atoi(com_argv[p+1]); + if (!port) + port = PORT_QWSERVER; +#ifdef HAVE_IPV4 + if (*sv_port_ipv4.string) + Cvar_SetValue(&sv_port_ipv4, port); +#endif +#ifdef IPPROTO_IPV6 + if (*sv_port_ipv6.string) + Cvar_SetValue(&sv_port_ipv6, port); +#endif +#ifdef USEIPX + if (*sv_port_ipx.string) + Cvar_SetValue(&sv_port_ipx, port); +#endif + } +} void NET_CloseServer(void) { @@ -4580,9 +5037,9 @@ void NET_InitServer(void) if (!svs.sockets) { svs.sockets = FTENET_CreateCollection(true); - #ifndef SERVERONLY - FTENET_AddToCollection(svs.sockets, "SVLoopback", port, FTENET_Loop_EstablishConnection, true); - #endif +#ifndef SERVERONLY + FTENET_AddToCollection(svs.sockets, "SVLoopback", port, NA_LOOPBACK, true); +#endif } allowconnects = true; @@ -4601,6 +5058,9 @@ void NET_InitServer(void) #ifdef IPPROTO_IPV6 Cvar_ForceCallback(&sv_port_tcp6); #endif +#endif +#ifdef HAVE_NATPMP + Cvar_ForceCallback(&sv_port_natpmp); #endif } else @@ -4609,7 +5069,7 @@ void NET_InitServer(void) #ifndef SERVERONLY svs.sockets = FTENET_CreateCollection(true); - FTENET_AddToCollection(svs.sockets, "SVLoopback", port, FTENET_Loop_EstablishConnection, true); + FTENET_AddToCollection(svs.sockets, "SVLoopback", port, NA_LOOPBACK, true); #endif } @@ -4681,12 +5141,24 @@ int VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread) len = recv(tf->sock, tf->readbuffer + tf->readbuffered, trying, 0); if (len == -1) { - if (errno != EWOULDBLOCK) - printf("socket error\n"); + int e = qerrno; + if (e != EWOULDBLOCK) + { + switch(e) + { + case ECONNABORTED: + Sys_Printf("conenction aborted\n", e); + break; + default: + Sys_Printf("socket error %i\n", e); + } + VFSTCP_Error(tf); + } //fixme: figure out wouldblock or error } else if (len == 0 && trying != 0) { + //peer disconnected VFSTCP_Error(tf); } else @@ -4726,7 +5198,9 @@ int VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestore len = send(tf->sock, buffer, bytestoread, 0); if (len == -1 || len == 0) { - VFSTCP_Error(tf); +// don't destroy it on write errors, because that prevents us from reading anything that was sent to us afterwards. +// instead let the read handling kill it if there's nothing new to be read + VFSTCP_ReadBytes(file, NULL, 0); return 0; } return len; @@ -4751,12 +5225,12 @@ void VFSTCP_Close (struct vfsfile_s *file) Z_Free(file); } -vfsfile_t *FS_OpenTCP(const char *name) +vfsfile_t *FS_OpenTCP(const char *name, int defaultport) { tcpfile_t *newf; int sock; netadr_t adr = {0}; - if (NET_StringToAdr(name, 0, &adr)) + if (NET_StringToAdr(name, defaultport, &adr)) { sock = TCP_OpenStream(adr); if (sock == INVALID_SOCKET) @@ -5000,7 +5474,7 @@ unsigned long VFSTCP_GetLen (struct vfsfile_s *file) } /*nacl websockets implementation...*/ -vfsfile_t *FS_OpenTCP(const char *name) +vfsfile_t *FS_OpenTCP(const char *name, int defaultport) { tcpfile_t *newf; @@ -5010,7 +5484,7 @@ vfsfile_t *FS_OpenTCP(const char *name) { return NULL; } - if (!NET_StringToAdr(name, &adr)) + if (!NET_StringToAdr(name, defaultport, &adr)) return NULL; //couldn't resolve the name newf = Z_Malloc(sizeof(*newf)); if (newf) @@ -5035,7 +5509,7 @@ vfsfile_t *FS_OpenTCP(const char *name) return NULL; } #else -vfsfile_t *FS_OpenTCP(const char *name) +vfsfile_t *FS_OpenTCP(const char *name, int defaultport) { return NULL; } diff --git a/engine/common/plugin.c b/engine/common/plugin.c index ed1ff95e..aa57e16a 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -344,7 +344,7 @@ plugin_t *Plug_Load(char *file) return newplug; } -static int Plug_Emumerated (const char *name, int size, void *param) +static int Plug_Emumerated (const char *name, int size, void *param, struct searchpath_s *spath) { char vmname[MAX_QPATH]; Q_strncpyz(vmname, name, sizeof(vmname)); @@ -745,14 +745,14 @@ typedef enum{ STREAM_NONE, STREAM_SOCKET, STREAM_TLS, - STREAM_OSFILE, - STREAM_FILE + STREAM_VFS } plugstream_e; typedef struct { plugin_t *plugin; plugstream_e type; int socket; + vfsfile_t *vfs; struct { char filename[MAX_QPATH]; qbyte *buffer; @@ -770,7 +770,7 @@ int pluginstreamarraylen; static int Plug_NewStreamHandle(plugstream_e type) { int i; - for (i = 1; i < pluginstreamarraylen; i++) + for (i = 0; i < pluginstreamarraylen; i++) { if (!pluginstreamarray[i].plugin) break; @@ -906,50 +906,49 @@ qintptr_t VARGS Plug_Net_TCPConnect(void *offset, quintptr_t mask, const qintptr unsigned short remoteport = VM_LONG(arg[1]); int handle; - struct sockaddr_qstorage to, from; - int sock; - int _true = 1; - - netadr_t a; - - if (!NET_StringToAdr(remoteip, remoteport, &a)) + vfsfile_t *stream = FS_OpenTCP(remoteip, remoteport); + if (!stream) return -1; - NetadrToSockadr(&a, &to); - - if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) - { - return -2; - } - - memset(&from, 0, sizeof(from)); - ((struct sockaddr*)&from)->sa_family = ((struct sockaddr*)&to)->sa_family; - if (bind(sock, (struct sockaddr *)&from, sizeof(from)) == -1) - { - return -2; - } - - //not yet blocking. So no frequent attempts please... - //non blocking prevents connect from returning worthwhile sensible value. - if (connect(sock, (struct sockaddr *)&to, sizeof(to)) == -1) - { - closesocket(sock); - return -2; - } - - if (ioctlsocket (sock, FIONBIO, (u_long *)&_true) == -1) //now make it non blocking. - { - return -1; - } - - handle = Plug_NewStreamHandle(STREAM_SOCKET); - pluginstreamarray[handle].socket = sock; - + handle = Plug_NewStreamHandle(STREAM_VFS); + pluginstreamarray[handle].vfs = stream; return handle; + } + +void Plug_Net_Close_Internal(int handle); +vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server); +#ifdef HAVE_SSL +qintptr_t VARGS Plug_Net_SetTLSClient(void *offset, quintptr_t mask, const qintptr_t *arg) +{ + pluginstream_t *stream; + int handle = VM_LONG(arg[0]); + qboolean anon = false; + if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug) + { + Con_Printf("Plug_Net_SetTLSClient: socket does not belong to you (or is invalid)\n"); + return -2; + } + stream = &pluginstreamarray[handle]; + if (stream->type != STREAM_VFS) + { //not a socket - invalid + Con_Printf("Plug_Net_SetTLSClient: Not a socket handle\n"); + return -2; + } + + stream->vfs = FS_OpenSSL(VM_POINTER(arg[1]), stream->vfs, false); + if (!stream->vfs) + { + Plug_Net_Close_Internal(handle); + return -1; + } + return 0; +} +#endif + #ifdef GNUTLS -qintptr_t VARGS Plug_Net_SetTLSClient(void *offset, unsigned int mask, const qintptr_t *arg) +qintptr_t VARGS Plug_Net_SetTLSClient(void *offset, quintptr_t mask, const qintptr_t *arg) { static gnutls_anon_client_credentials anoncred; static gnutls_certificate_credentials xcred; @@ -1058,47 +1057,32 @@ qintptr_t VARGS Plug_FS_Open(void *offset, quintptr_t mask, const qintptr_t *arg int handle; int *ret; - char *data; + //char *data; + char *mode; + vfsfile_t *f; if (VM_OOB(arg[1], sizeof(int))) return -2; ret = VM_POINTER(arg[1]); - if (arg[2] == 1) + switch(arg[2]) { - FS_LoadFile(VM_POINTER(arg[0]), (void**)&data); - if (!data) - return -1; - - handle = Plug_NewStreamHandle(STREAM_FILE); - pluginstreamarray[handle].file.buffer = data; - pluginstreamarray[handle].file.curpos = 0; - pluginstreamarray[handle].file.curlen = com_filesize; - pluginstreamarray[handle].file.buflen = com_filesize; - - *ret = handle; - - return com_filesize; - } - else if (arg[2] == 2) - { - data = BZ_Malloc(8192); - if (!data) - return -1; - - handle = Plug_NewStreamHandle(STREAM_FILE); - Q_strncpyz(pluginstreamarray[handle].file.filename, VM_POINTER(arg[0]), MAX_QPATH); - pluginstreamarray[handle].file.buffer = data; - pluginstreamarray[handle].file.curpos = 0; - pluginstreamarray[handle].file.curlen = 0; - pluginstreamarray[handle].file.buflen = 8192; - - *ret = handle; - - return com_filesize; - } - else + case 1: + mode = "rb"; + break; + case 2: + mode = "wb"; + break; + default: return -2; + } + f = FS_OpenVFS(VM_POINTER(arg[0]), mode, FS_GAME); + if (!f) + return -1; + handle = Plug_NewStreamHandle(STREAM_VFS); + pluginstreamarray[handle].vfs = f; + *ret = handle; + return VFS_GETLEN(pluginstreamarray[handle].vfs); } qintptr_t VARGS Plug_memset(void *offset, quintptr_t mask, const qintptr_t *arg) @@ -1171,6 +1155,34 @@ qintptr_t VARGS Plug_atan2(void *offset, quintptr_t mask, const qintptr_t *arg) return ret; } +void Plug_Net_Close_Internal(int handle) +{ + switch(pluginstreamarray[handle].type) + { + case STREAM_NONE: + break; + case STREAM_VFS: + if (pluginstreamarray[handle].vfs) + VFS_CLOSE(pluginstreamarray[handle].vfs); + pluginstreamarray[handle].vfs = NULL; + break; + case STREAM_SOCKET: +#ifndef NACL + closesocket(pluginstreamarray[handle].socket); +#endif + break; + case STREAM_TLS: +#ifdef GNUTLS + gnutls_bye (pluginstreamarray[handle].session, GNUTLS_SHUT_RDWR); + pluginstreamarray[handle].type = STREAM_SOCKET; + Plug_Net_Close_Internal(handle); + return; +#endif + break; + } + + pluginstreamarray[handle].plugin = NULL; +} qintptr_t VARGS Plug_Net_Recv(void *offset, quintptr_t mask, const qintptr_t *arg) { int read; @@ -1217,16 +1229,8 @@ qintptr_t VARGS Plug_Net_Recv(void *offset, quintptr_t mask, const qintptr_t *ar return -2; //closed by remote connection. return read; #endif - case STREAM_FILE: - if (pluginstreamarray[handle].file.curlen - pluginstreamarray[handle].file.curpos < destlen) - { - destlen = pluginstreamarray[handle].file.curlen - pluginstreamarray[handle].file.curpos; - if (destlen < 0) - return -2; - } - memcpy(dest, pluginstreamarray[handle].file.buffer + pluginstreamarray[handle].file.curpos, destlen); - pluginstreamarray[handle].file.curpos += destlen; - return destlen; + case STREAM_VFS: + return VFS_READ(pluginstreamarray[handle].vfs, dest, destlen); default: return -2; } @@ -1273,18 +1277,8 @@ qintptr_t VARGS Plug_Net_Send(void *offset, quintptr_t mask, const qintptr_t *ar return -2; //closed by remote connection. return written; #endif - case STREAM_FILE: - if (pluginstreamarray[handle].file.buflen < pluginstreamarray[handle].file.curpos + srclen) - { - pluginstreamarray[handle].file.buflen = pluginstreamarray[handle].file.curpos + srclen+8192; - pluginstreamarray[handle].file.buffer = - BZ_Realloc(pluginstreamarray[handle].file.buffer, pluginstreamarray[handle].file.buflen); - } - memcpy(pluginstreamarray[handle].file.buffer + pluginstreamarray[handle].file.curpos, src, srclen); - pluginstreamarray[handle].file.curpos += srclen; - if (pluginstreamarray[handle].file.curpos > pluginstreamarray[handle].file.curlen) - pluginstreamarray[handle].file.curlen = pluginstreamarray[handle].file.curpos; - return -2; + case STREAM_VFS: + return VFS_WRITE(pluginstreamarray[handle].vfs, src, srclen); default: return -2; @@ -1331,41 +1325,6 @@ qintptr_t VARGS Plug_Net_SendTo(void *offset, quintptr_t mask, const qintptr_t * return -2; } } - -void Plug_Net_Close_Internal(int handle) -{ - switch(pluginstreamarray[handle].type) - { - case STREAM_FILE: - if (*pluginstreamarray[handle].file.filename) - { - COM_WriteFile(pluginstreamarray[handle].file.filename, pluginstreamarray[handle].file.buffer, pluginstreamarray[handle].file.curlen); - BZ_Free(pluginstreamarray[handle].file.buffer); - } - else - FS_FreeFile(pluginstreamarray[handle].file.buffer); - break; - case STREAM_NONE: - break; - case STREAM_OSFILE: - break; - case STREAM_SOCKET: -#ifndef NACL - closesocket(pluginstreamarray[handle].socket); -#endif - break; - case STREAM_TLS: -#ifdef GNUTLS - gnutls_bye (pluginstreamarray[handle].session, GNUTLS_SHUT_RDWR); - pluginstreamarray[handle].type = STREAM_SOCKET; - Plug_Net_Close_Internal(handle); - return; -#endif - break; - } - - pluginstreamarray[handle].plugin = NULL; -} qintptr_t VARGS Plug_Net_Close(void *offset, quintptr_t mask, const qintptr_t *arg) { int handle = VM_LONG(arg[0]); @@ -1484,6 +1443,9 @@ void Plug_Init(void) #ifdef GNUTLS if (Init_GNUTLS()) Plug_RegisterBuiltin("Net_SetTLSClient", Plug_Net_SetTLSClient, 0); +#endif +#ifdef HAVE_SSL + Plug_RegisterBuiltin("Net_SetTLSClient", Plug_Net_SetTLSClient, 0); #endif Plug_RegisterBuiltin("Net_Recv", Plug_Net_Recv, 0); Plug_RegisterBuiltin("Net_Send", Plug_Net_Send, 0); @@ -1775,6 +1737,7 @@ qboolean Plug_CenterPrintMessage(char *buffer, int clientnum) void Plug_Close(plugin_t *plug) { + int i; if (plug->blockcloses) { Con_Printf("Plugin %s provides driver features, and cannot safely be unloaded\n", plug->name); @@ -1804,6 +1767,14 @@ void Plug_Close(plugin_t *plug) VM_Call(plug->vm, plug->shutdown); VM_Destroy(plug->vm); + for (i = 0; i < pluginstreamarraylen; i++) + { + if (pluginstreamarray[i].plugin == plug) + { + Plug_Net_Close_Internal(i); + } + } + Plug_FreeConCommands(plug); Plug_Client_Close(plug); @@ -1883,6 +1854,10 @@ void Plug_Shutdown(void) Plug_Close(plugs); } + BZ_Free(pluginstreamarray); + pluginstreamarray = NULL; + pluginstreamarraylen = 0; + numplugbuiltins = 0; BZ_Free(plugbuiltins); plugbuiltins = NULL; @@ -1894,6 +1869,10 @@ void Plug_Shutdown(void) plugincommandarraylen = 0; BZ_Free(plugincommandarray); plugincommandarray = NULL; + +#ifndef SERVERONLY + Plug_Client_Shutdown(); +#endif } #endif diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 3c16ef19..ee5bac81 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -1426,7 +1426,7 @@ void search_close_progs(pubprogfuncs_t *prinst, qboolean complain) prvm_nextsearchhandle = 0; //might as well. } -int search_enumerate(const char *name, int fsize, void *parm) +int search_enumerate(const char *name, int fsize, void *parm, struct searchpath_s *spath) { prvmsearch_t *s = parm; diff --git a/engine/common/protocol.h b/engine/common/protocol.h index b1bc04eb..dbc96323 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -146,140 +146,141 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // server to client // -#define svc_bad 0 -#define svc_nop 1 -#define svc_disconnect 2 -#define svcqw_updatestatbyte 3 // [qbyte] [qbyte] -#define svcnq_updatestatlong 3 // [qbyte] [long] -#define svc_version 4 // [long] server version -#define svc_setview 5 // [short] entity number -#define svc_sound 6 // -#define svc_time 7 // [float] server time -#define svc_print 8 // [qbyte] id [string] null terminated string -#define svc_stufftext 9 // [string] stuffed into client's console buffer - // the string should be \n terminated -#define svc_setangle 10 // [angle3] set the view angle to this absolute value +#define svc_bad 0 +#define svc_nop 1 +#define svc_disconnect 2 +#define svcqw_updatestatbyte 3 // [qbyte] [qbyte] +#define svcnq_updatestatlong 3 // [qbyte] [long] +#define svc_version 4 // [long] server version +#define svc_setview 5 // [short] entity number +#define svc_sound 6 // +#define svc_time 7 // [float] server time +#define svc_print 8 // [qbyte] id [string] null terminated string +#define svc_stufftext 9 // [string] stuffed into client's console buffer + // the string should be \n terminated +#define svc_setangle 10 // [angle3] set the view angle to this absolute value -#define svc_serverdata 11 // [long] protocol ... -#define svc_lightstyle 12 // [qbyte] [string] -#define svc_updatename 13 // [qbyte] [string] -#define svc_updatefrags 14 // [qbyte] [short] -#define svc_clientdata 15 // -#define svc_stopsound 16 // -#define svc_updatecolors 17 // [qbyte] [qbyte] [qbyte] -#define svc_particle 18 // [vec3] -#define svc_damage 19 +#define svc_serverdata 11 // [long] protocol ... +#define svc_lightstyle 12 // [qbyte] [string] +#define svc_updatename 13 // [qbyte] [string] +#define svc_updatefrags 14 // [qbyte] [short] +#define svc_clientdata 15 // +#define svc_stopsound 16 // +#define svc_updatecolors 17 // [qbyte] [qbyte] [qbyte] +#define svc_particle 18 // [vec3] +#define svc_damage 19 -#define svc_spawnstatic 20 -#define svcfte_spawnstatic2 21 -#define svc_spawnbaseline 22 +#define svc_spawnstatic 20 +#define svcfte_spawnstatic2 21 +#define svc_spawnbaseline 22 -#define svc_temp_entity 23 // variable -#define svc_setpause 24 // [qbyte] on / off -#define svc_signonnum 25 // [qbyte] used for the signon sequence +#define svc_temp_entity 23 // variable +#define svc_setpause 24 // [qbyte] on / off +#define svc_signonnum 25 // [qbyte] used for the signon sequence -#define svc_centerprint 26 // [string] to put in center of the screen +#define svc_centerprint 26 // [string] to put in center of the screen -#define svc_killedmonster 27 -#define svc_foundsecret 28 +#define svc_killedmonster 27 +#define svc_foundsecret 28 -#define svc_spawnstaticsound 29 // [coord3] [qbyte] samp [qbyte] vol [qbyte] aten +#define svc_spawnstaticsound 29 // [coord3] [qbyte] samp [qbyte] vol [qbyte] aten -#define svc_intermission 30 // [vec3_t] origin [vec3_t] angle -#define svc_finale 31 // [string] text +#define svc_intermission 30 // [vec3_t] origin [vec3_t] angle +#define svc_finale 31 // [string] text -#define svc_cdtrack 32 // [qbyte] track -#define svc_sellscreen 33 +#define svc_cdtrack 32 // [qbyte] track +#define svc_sellscreen 33 -#define svc_cutscene 34 //hmm... nq only... added after qw tree splitt? +#define svc_cutscene 34 //hmm... nq only... added after qw tree splitt? //QW svcs -#define svc_smallkick 34 // set client punchangle to 2 -#define svc_bigkick 35 // set client punchangle to 4 +#define svc_smallkick 34 // set client punchangle to 2 +#define svc_bigkick 35 // set client punchangle to 4 -#define svc_updateping 36 // [qbyte] [short] -#define svc_updateentertime 37 // [qbyte] [float] +#define svc_updateping 36 // [qbyte] [short] +#define svc_updateentertime 37 // [qbyte] [float] -#define svcqw_updatestatlong 38 // [qbyte] [long] +#define svcqw_updatestatlong 38 // [qbyte] [long] -#define svc_muzzleflash 39 // [short] entity +#define svc_muzzleflash 39 // [short] entity -#define svc_updateuserinfo 40 // [qbyte] slot [long] uid - // [string] userinfo +#define svc_updateuserinfo 40 // [qbyte] slot [long] uid [string] userinfo -#define svc_download 41 // [short] size [size bytes] -#define svc_playerinfo 42 // variable -#define svc_nails 43 // [qbyte] num [48 bits] xyzpy 12 12 12 4 8 -#define svc_chokecount 44 // [qbyte] packets choked -#define svc_modellist 45 // [strings] -#define svc_soundlist 46 // [strings] -#define svc_packetentities 47 // [...] -#define svc_deltapacketentities 48 // [...] -#define svc_maxspeed 49 // maxspeed change, for prediction -#define svc_entgravity 50 // gravity change, for prediction -#define svc_setinfo 51 // setinfo on a client -#define svc_serverinfo 52 // serverinfo -#define svc_updatepl 53 // [qbyte] [qbyte] +#define svc_download 41 // [short] size [size bytes] +#define svc_playerinfo 42 // variable +#define svc_nails 43 // [qbyte] num [48 bits] xyzpy 12 12 12 4 8 +#define svc_chokecount 44 // [qbyte] packets choked +#define svc_modellist 45 // [strings] +#define svc_soundlist 46 // [strings] +#define svc_packetentities 47 // [...] +#define svc_deltapacketentities 48 // [...] +#define svc_maxspeed 49 // maxspeed change, for prediction +#define svc_entgravity 50 // gravity change, for prediction +#define svc_setinfo 51 // setinfo on a client +#define svc_serverinfo 52 // serverinfo +#define svc_updatepl 53 // [qbyte] [qbyte] //mvdsv extended svcs (for mvd playback) -#define svc_nails2 54 //qwe - [qbyte] num [52 bits] nxyzpy 8 12 12 12 4 8 +#define svc_nails2 54 //qwe - [qbyte] num [52 bits] nxyzpy 8 12 12 12 4 8 //FTE extended svcs #ifdef PEXT_SOUNDDBL -#define svcfte_soundextended 55 -#define svcfte_soundlistshort 56 +#define svcfte_soundextended 55 +#define svcfte_soundlistshort 56 #endif #ifdef PEXT_LIGHTSTYLECOL -#define svcfte_lightstylecol 57 +#define svcfte_lightstylecol 57 #endif -//#define svcfte_svcremoved 58 +//#define svcfte_svcremoved 58 //#define svcfte_svcremoved 59 #ifdef PEXT_MODELDBL -#define svcfte_modellistshort 60 // [strings] +#define svcfte_modellistshort 60 // [strings] #endif //#define svc_ftesetclientpersist 61 //ushort DATA -#define svc_setportalstate 62 +#define svc_setportalstate 62 -#define svcfte_particle2 63 -#define svcfte_particle3 64 -#define svcfte_particle4 65 -#define svcfte_spawnbaseline2 66 +#define svcfte_particle2 63 +#define svcfte_particle3 64 +#define svcfte_particle4 65 +#define svcfte_spawnbaseline2 66 -#define svcfte_customtempent 67 +#define svcfte_customtempent 67 -#define svcfte_choosesplitclient 68 -#define svcfte_showpic 69 -#define svcfte_hidepic 70 -#define svcfte_movepic 71 -#define svcfte_updatepic 72 +#define svcfte_choosesplitclient 68 +#define svcfte_showpic 69 +#define svcfte_hidepic 70 +#define svcfte_movepic 71 +#define svcfte_updatepic 72 -#define svcfte_effect 74 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate -#define svcfte_effect2 75 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate +//73 + +#define svcfte_effect 74 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate +#define svcfte_effect2 75 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate #ifdef PEXT_CSQC -#define svcfte_csqcentities 76 //entity lump for csqc +#define svcfte_csqcentities 76 //entity lump for csqc #endif -#define svcfte_precache 77 +#define svcfte_precache 77 -#define svcfte_updatestatstring 78 -#define svcfte_updatestatfloat 79 +#define svcfte_updatestatstring 78 +#define svcfte_updatestatfloat 79 -#define svcfte_trailparticles 80 // [short] entnum [short] effectnum [vector] start [vector] end -#define svcfte_pointparticles 81 // [short] effectnum [vector] start [vector] velocity [short] count -#define svcfte_pointparticles1 82 // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1 +#define svcfte_trailparticles 80 // [short] entnum [short] effectnum [vector] start [vector] end +#define svcfte_pointparticles 81 // [short] effectnum [vector] start [vector] velocity [short] count +#define svcfte_pointparticles1 82 // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1 -#define svcfte_cgamepacket 83 -#define svcfte_voicechat 84 +#define svcfte_cgamepacket 83 +#define svcfte_voicechat 84 #define svcfte_setangledelta 85 // [angle3] add this to the current viewangles -#define svcfte_updateentities 86 +#define svcfte_updateentities 86 //fitz svcs @@ -291,18 +292,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define svcfitz_spawnstaticsound2 44 //DP extended svcs -#define svcdp_downloaddata 50 -#define svcdp_updatestatbyte 51 -#define svcnq_effect 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate -#define svcnq_effect2 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate -#define svcdp_precache 54 // [short] precacheindex [string] filename, precacheindex is + 0 for modelindex and +32768 for soundindex -#define svcdp_spawnbaseline2 55 -#define svcdp_entities 57 -#define svcdp_csqcentities 58 -#define svcdp_spawnstaticsound2 59 // [coord3] [short] samp [byte] vol [byte] aten -#define svcdp_trailparticles 60 // [short] entnum [short] effectnum [vector] start [vector] end -#define svcdp_pointparticles 61 // [short] effectnum [vector] start [vector] velocity [short] count -#define svcdp_pointparticles1 62 // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1 +#define svcdp_downloaddata 50 +#define svcdp_updatestatbyte 51 +#define svcnq_effect 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate +#define svcnq_effect2 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate +#define svcdp_precache 54 // [short] precacheindex [string] filename, precacheindex is + 0 for modelindex and +32768 for soundindex +#define svcdp_spawnbaseline2 55 +#define svcdp_entities 57 +#define svcdp_csqcentities 58 +#define svcdp_spawnstaticsound2 59 // [coord3] [short] samp [byte] vol [byte] aten +#define svcdp_trailparticles 60 // [short] entnum [short] effectnum [vector] start [vector] end +#define svcdp_pointparticles 61 // [short] effectnum [vector] start [vector] velocity [short] count +#define svcdp_pointparticles1 62 // [short] effectnum [vector] start, same as svc_pointparticles except velocity is zero and count is 1 diff --git a/engine/common/q3common.c b/engine/common/q3common.c index 1a1180e5..bf24277d 100644 --- a/engine/common/q3common.c +++ b/engine/common/q3common.c @@ -186,7 +186,7 @@ typedef struct { int bufferleft; int skip; } vmsearch_t; -static int VMEnum(const char *match, int size, void *args) +static int VMEnum(const char *match, int size, void *args, void *spath) { char *check; int newlen; @@ -210,13 +210,13 @@ static int VMEnum(const char *match, int size, void *args) return true; } -static int IfFound(const char *match, int size, void *args) +static int IfFound(const char *match, int size, void *args, void *spath) { *(qboolean*)args = true; return true; } -static int VMEnumMods(const char *match, int size, void *args) +static int VMEnumMods(const char *match, int size, void *args, void *spath) { char *check; char desc[1024]; @@ -238,7 +238,7 @@ static int VMEnumMods(const char *match, int size, void *args) return true; //we don't want baseq3 foundone = false; - Sys_EnumerateFiles(va("%s%s/", ((vmsearch_t *)args)->dir, match), "*.pk3", IfFound, &foundone); + Sys_EnumerateFiles(va("%s%s/", ((vmsearch_t *)args)->dir, match), "*.pk3", IfFound, &foundone, spath); if (foundone == false) return true; //we only count directories with a pk3 file @@ -286,9 +286,9 @@ int VM_GetFileList(char *path, char *ext, char *output, int buffersize) if (!strcmp(path, "$modlist")) { vms.skip=0; - Sys_EnumerateFiles((vms.dir=com_quakedir), "*", VMEnumMods, &vms); + Sys_EnumerateFiles((vms.dir=com_quakedir), "*", VMEnumMods, &vms, NULL); if (*com_homedir) - Sys_EnumerateFiles((vms.dir=com_homedir), "*", VMEnumMods, &vms); + Sys_EnumerateFiles((vms.dir=com_homedir), "*", VMEnumMods, &vms, NULL); } else if (*(char *)ext == '.' || *(char *)ext == '/') COM_EnumerateFiles(va("%s/*%s", path, ext), VMEnum, &vms); diff --git a/engine/common/sys.h b/engine/common/sys.h index 457bb1ee..79b6a0db 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -83,7 +83,7 @@ void Sys_ServerActivity(void); void Sys_SendKeyEvents (void); // Perform Key_Event () callbacks until the input que is empty -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm); +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm, void *spath); void Sys_Vibrate(int count); diff --git a/engine/dotnet2005/droid.vcproj b/engine/dotnet2005/droid.vcproj index 78b4a96f..4ff978b7 100644 --- a/engine/dotnet2005/droid.vcproj +++ b/engine/dotnet2005/droid.vcproj @@ -72,6 +72,10 @@ RelativePath="..\droid\src\com\fteqw\FTEDroidEngine.java" > + + diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index d6803575..f2cd1f6c 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -2,6 +2,7 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftequake", "ftequake.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}" ProjectSection(ProjectDependencies) = postProject + {9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA} {0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080} EndProjectSection EndProject @@ -30,6 +31,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avplug", "..\..\plugins\avp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "droid", "droid.vcproj", "{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{8CED01C6-2C61-4EC5-90B6-574D9756D773}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jabbercl", "..\..\plugins\jabber\jabbercl.vcproj", "{9767E236-8454-44E9-8999-CD5BDAFBE9BA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution D3DDebug|Win32 = D3DDebug|Win32 @@ -437,10 +442,52 @@ Global {4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.Release|Win32.ActiveCfg = Release|Win32 {4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.Release|Win32.Build.0 = Release|Win32 {4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.Release|x64.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DDebug|Win32.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DDebug|Win32.Build.0 = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DDebug|x64.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DRelease|Win32.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DRelease|Win32.Build.0 = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.D3DRelease|x64.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug Dedicated Server|Win32.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug Dedicated Server|Win32.Build.0 = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug Dedicated Server|x64.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug|Win32.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug|Win32.Build.0 = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Debug|x64.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|Win32.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|Win32.Build.0 = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLDebug|x64.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|Win32.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|Win32.Build.0 = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.GLRelease|x64.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MDebug|Win32.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MDebug|Win32.Build.0 = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MDebug|x64.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLDebug|Win32.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLDebug|Win32.Build.0 = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLDebug|x64.ActiveCfg = Debug|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLRelease|Win32.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLRelease|Win32.Build.0 = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MinGLRelease|x64.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MRelease|Win32.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MRelease|Win32.Build.0 = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.MRelease|x64.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release Dedicated Server|Win32.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release Dedicated Server|Win32.Build.0 = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release Dedicated Server|x64.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release|Win32.ActiveCfg = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release|Win32.Build.0 = Release|Win32 + {9767E236-8454-44E9-8999-CD5BDAFBE9BA}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {4877586B-E85B-4DF8-BCCE-59D31514D240} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} + {32B12987-DF8C-4E40-B07C-B18586A4CA65} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} + {873CCE24-3549-49D4-A4B4-653F91B1532A} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} + {9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {8CED01C6-2C61-4EC5-90B6-574D9756D773} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution AMDCaProjectFile = C:\Games\Quake\wip\engine\dotnet2005\CodeAnalyst\ftequake.caw EndGlobalSection diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 65ad61eb..29cfb461 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -2096,7 +2096,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -2300,7 +2280,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -2508,7 +2468,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -2712,7 +2652,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -2916,7 +2836,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -3120,7 +3020,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -3324,7 +3204,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -3528,7 +3388,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -3732,7 +3572,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -3936,7 +3756,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -4140,7 +3940,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -4344,7 +4124,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -4548,7 +4308,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -4752,7 +4492,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -4960,7 +4680,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -5860,7 +5060,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -6065,7 +5245,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> @@ -17440,7 +16600,6 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" /> + + @@ -31020,206 +30176,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - lm = lm; lms->x = (i & (LMCHUNKS-1))*SECTTEXSIZE; lms->y = (i / LMCHUNKS)*SECTTEXSIZE; @@ -257,7 +257,7 @@ static void Terr_InitLightmap(hmsection_t *s) s->lmx = lms->x; s->lmy = lms->y; - free(lms); + Z_Free(lms); } #endif @@ -344,7 +344,7 @@ static qboolean Terr_IsSectionFName(heightmap_t *hm, char *fname, int *sx, int * } static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, dsection_t *ds, unsigned int dslen) { - int i; + int i, j; #ifndef SERVERONLY dsmesh_t *dm; unsigned char *lm; @@ -365,13 +365,12 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, in if (!s) { - s = malloc(sizeof(*s)); + s = Z_Malloc(sizeof(*s)); if (!s) { FS_FreeFile(ds); return NULL; } - memset(s, 0, sizeof(*s)); InsertLinkBefore(&s->recycle, &hm->recycle); s->sx = sx; @@ -468,12 +467,11 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, in s->numents = ds->ents_num; s->maxents = s->numents; if (s->maxents) - s->ents = malloc(sizeof(*s->ents) * s->maxents); + s->ents = Z_Malloc(sizeof(*s->ents) * s->maxents); else s->ents = NULL; if (!s->ents) s->numents = s->maxents = 0; - memset(s->ents, 0, sizeof(*s->ents) * s->maxents); for (i = 0, dm = (dsmesh_t*)ptr; i < s->numents; i++, dm = (dsmesh_t*)((qbyte*)dm + dm->size)) { s->ents[i].model = Mod_ForName((char*)(dm + 1), false); @@ -499,7 +497,7 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, in } else { - s->flags |= TSF_RELIGHT; +// s->flags |= TSF_RELIGHT; #ifndef SERVERONLY if (s->lightmap >= 0) @@ -508,7 +506,13 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, in lm += (s->lmy * HMLMSTRIDE + s->lmx) * lightmap_bytes; for (i = 0; i < SECTTEXSIZE; i++) { - memset(lm, 0, sizeof(byte_vec4_t)*SECTTEXSIZE); + for (j = 0; j < SECTTEXSIZE; j++) + { + lm[j*4+0] = 0; + lm[j*4+0] = 0; + lm[j*4+0] = 0; + lm[j*4+3] = 255; + } lm += (HMLMSTRIDE)*lightmap_bytes; } lightmap[s->lightmap]->modified = true; @@ -644,12 +648,9 @@ qboolean Terr_DownloadedSection(char *fname) hmcluster_t *cluster = hm->cluster[cx + cy*MAXSECTIONS]; if (!cluster) { - cluster = malloc(sizeof(*cluster)); + cluster = Z_Malloc(sizeof(*cluster)); if (cluster) - { - memset(cluster, 0, sizeof(*cluster)); hm->cluster[cx + cy*MAXSECTIONS] = cluster; - } } if (cluster) cluster->section[sx + sy*MAXSECTIONS] = Terr_ReadSection(hm, cluster->section[sx + sy*MAXSECTIONS], x, y, fileptr, len); @@ -663,7 +664,7 @@ qboolean Terr_DownloadedSection(char *fname) } #endif -static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy) +static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, qboolean force) { hmsection_t *sect; void *diskimage; @@ -685,9 +686,7 @@ static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, in /*queue the file for download if we don't have it yet*/ if (len < 0) { -#ifndef CLIENTONLY - if (!sv.state) //server ignores any load errors, and will load a dummy section. -#endif + if (!force) { #ifndef SERVERONLY if (!cl.downloadlist) @@ -805,7 +804,10 @@ static qboolean Terr_SaveSection(heightmap_t *hm, hmsection_t *s, int sx, int sy } /*convienience function*/ -static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, qboolean doload) +#define TGS_NOLOAD 0 +#define TGS_LOAD 1 +#define TGS_FORCELOAD 2 +static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, unsigned int flags) { hmcluster_t *cluster; hmsection_t *section; @@ -816,12 +818,11 @@ static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, qboolean dolo cluster = hm->cluster[cx + cy*MAXSECTIONS]; if (!cluster) { - if (doload) + if (flags & (TGS_LOAD|TGS_FORCELOAD)) { - cluster = malloc(sizeof(*cluster)); + cluster = Z_Malloc(sizeof(*cluster)); if (!cluster) return NULL; - memset(cluster, 0, sizeof(*cluster)); hm->cluster[cx + cy*MAXSECTIONS] = cluster; } else @@ -830,13 +831,27 @@ static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, qboolean dolo section = cluster->section[sx + sy*MAXSECTIONS]; if (!section) { - if (doload) + if (flags & (TGS_LOAD|TGS_FORCELOAD)) { // while (hm->activesections > TERRAINACTIVESECTIONS) // Terr_Collect(hm); - section = cluster->section[sx + sy*MAXSECTIONS] = Terr_LoadSection(hm, section, x, y); + section = cluster->section[sx + sy*MAXSECTIONS] = Terr_LoadSection(hm, section, x, y, !!(flags & TGS_FORCELOAD)); } } +#ifndef SERVERONLY + //when using networked terrain, the client will never load a section from disk, but only loading it from the server + if (section && (section->flags & TSF_NOTIFY) && mod_terrain_networked.ival && !sv.state) + { + //try to download it now... + if (!cl.downloadlist) + { + CL_CheckOrEnqueDownloadFile(Terr_DiskSectionName(hm, x, y), Terr_TempDiskSectionName(hm, x, y), DLLF_OVERWRITE|DLLF_TEMPORARY); + + section->flags &= ~TSF_NOTIFY; + } + } +#endif + return section; } @@ -850,7 +865,7 @@ int Heightmap_Save(heightmap_t *hm) { for (y = hm->firstsegy; y < hm->maxsegy; y++) { - s = Terr_GetSection(hm, x, y, false); + s = Terr_GetSection(hm, x, y, TGS_NOLOAD); if (!s) continue; if (s->flags & TSF_EDITED) @@ -868,16 +883,6 @@ int Heightmap_Save(heightmap_t *hm) } #ifndef CLIENTONLY -static int dehex(int i) -{ - if (i >= '0' && i <= '9') - return (i-'0'); - else if (i >= 'A' && i <= 'F') - return (i-'A'+10); - else - return (i-'a'+10); -} - //on servers, we can get requests to download current map sections. if so, give them it. qboolean Terrain_LocateSection(char *name, flocation_t *loc) { @@ -896,22 +901,11 @@ qboolean Terrain_LocateSection(char *name, flocation_t *loc) if (!Terr_IsSectionFName(hm, name, &x, &y)) return false; - x = dehex(name[nlen-17+ 6])<<8; - x|= dehex(name[nlen-17+ 7])<<4; - x|= dehex(name[nlen-17+ 8])<<0; - - y = dehex(name[nlen-17+10])<<8; - y|= dehex(name[nlen-17+11])<<4; - y|= dehex(name[nlen-17+12])<<0; - - x += CHUNKBIAS; - y += CHUNKBIAS; - //verify that its valid if (strcmp(name, Terr_DiskSectionName(hm, x, y))) return false; - s = Terr_GetSection(hm, x, y, false); + s = Terr_GetSection(hm, x, y, TGS_NOLOAD); if (!s || !(s->flags & TSF_EDITED)) return false; //its not been edited, might as well just use the regular file @@ -931,7 +925,7 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa { struct lmsect_s *lms; - lms = malloc(sizeof(*lms)); + lms = BZ_Malloc(sizeof(*lms)); lms->lm = s->lightmap; lms->x = s->lmx; lms->y = s->lmy; @@ -950,18 +944,56 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa } #endif - free(s->ents); - free(s->mesh.xyz_array); - free(s->mesh.indexes); + Z_Free(s->ents); + Z_Free(s->mesh.xyz_array); + Z_Free(s->mesh.indexes); #endif - free(s); + Z_Free(s); hm->activesections--; } +static void Terr_DoEditNotify(heightmap_t *hm) +{ + int i; + char *cmd; + hmsection_t *s; + link_t *ln = &hm->recycle; + + if (!sv.state) + return; + + for (i = 0; i < sv.allocated_client_slots; i++) + { + if (svs.clients[i].state > cs_zombie && svs.clients[i].netchan.remote_address.type != NA_LOOPBACK) + { + if (svs.clients[i].backbuf.cursize) + return; + } + } + + for (ln = &hm->recycle; ln->next != &hm->recycle; ln = &s->recycle) + { + s = (hmsection_t*)ln->next; + if (s->flags & TSF_NOTIFY) + { + s->flags &= ~TSF_NOTIFY; + cmd = va("mod_terrain_reload %s %i %i\n", hm->path, s->sx - CHUNKBIAS, s->sy - CHUNKBIAS); + for (i = 0; i < sv.allocated_client_slots; i++) + { + if (svs.clients[i].state > cs_zombie && svs.clients[i].netchan.remote_address.type != NA_LOOPBACK) + { + SV_StuffcmdToClient(&svs.clients[i], cmd); + } + } + return; + } + } +} + //garbage collect the oldest section, to make space for another -static void Terr_Collect(heightmap_t *hm) +static qboolean Terr_Collect(heightmap_t *hm) { hmcluster_t *c; hmsection_t *s; @@ -986,9 +1018,10 @@ static void Terr_Collect(heightmap_t *hm) c->section[sx+sy*MAXSECTIONS] = NULL; Terr_DestroySection(hm, s, true); - return; + return true; } } + return false; } /*purge all sections @@ -1034,7 +1067,7 @@ void Terr_PurgeTerrainModel(model_t *mod, qboolean lightmapsonly, qboolean light if (!lightmapsonly) { hm->cluster[cx + cy*MAXSECTIONS] = NULL; - free(c); + BZ_Free(c); } } #ifndef SERVERONLY @@ -1045,7 +1078,7 @@ void Terr_PurgeTerrainModel(model_t *mod, qboolean lightmapsonly, qboolean light struct lmsect_s *lms; lms = hm->unusedlmsects; hm->unusedlmsects = lms->next; - free(lms); + BZ_Free(lms); } } #endif @@ -1528,11 +1561,11 @@ void Terr_DrawInBounds(struct tdibctx *ctx, int x, int y, int w, int h) if (R_CullBox(mins, maxs)) return; - s = Terr_GetSection(hm, x, y, true); + s = Terr_GetSection(hm, x, y, TGS_LOAD); if (!s) return; if (s->lightmap < 0) - Terr_LoadSection(hm, s, x, y); + Terr_LoadSection(hm, s, x, y, false); if (s->flags & TSF_RELIGHT) { @@ -1644,8 +1677,15 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e) struct tdibctx tdibctx; if (!r_refdef.recurse) + { + Terr_DoEditNotify(hm); +// while (hm->activesections > 0) +// if (!Terr_Collect(hm)) +// break; while (hm->activesections > TERRAINACTIVESECTIONS) - Terr_Collect(hm); + if (!Terr_Collect(hm)) + break; + } if (hm->relight) ted_dorelight(hm); @@ -1729,7 +1769,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e) mins[1] = (y+0 - CHUNKBIAS)*hm->sectionsize; maxs[1] = (y+1 - CHUNKBIAS)*hm->sectionsize; - s = Terr_GetSection(hm, x, y, true); + s = Terr_GetSection(hm, x, y, TGS_LOAD); if (!s) continue; if (s->lightmap < 0) @@ -1829,7 +1869,7 @@ void Terrain_ClipDecal(fragmentdecal_t *dec, float *center, float radius, model_ { for (x = min[0]; x < max[0]; x++) { - s = Terr_GetSection(hm, x, y, true); + s = Terr_GetSection(hm, x, y, TGS_LOAD); if (!s) continue; @@ -1912,7 +1952,7 @@ unsigned int Heightmap_PointContentsHM(heightmap_t *hm, float clipmipsz, vec3_t return hm->exteriorcontents; if (sx >= hm->maxsegx || sy >= hm->maxsegy) return hm->exteriorcontents; - s = Terr_GetSection(hm, sx, sy, true); + s = Terr_GetSection(hm, sx, sy, TGS_LOAD); if (!s) { return FTECONTENTS_SOLID; @@ -2002,7 +2042,7 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm) return; if (sx >= hm->maxsegx || sy >= hm->maxsegy) return; - s = Terr_GetSection(hm, sx, sy, true); + s = Terr_GetSection(hm, sx, sy, TGS_LOAD); if (!s) return; @@ -2152,7 +2192,7 @@ static void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty) else if (sy < tr->hm->firstsegy || sy >= tr->hm->maxsegy) s = NULL; else - s = Terr_GetSection(tr->hm, sx, sy, true); + s = Terr_GetSection(tr->hm, sx, sy, TGS_LOAD); if (!s) { @@ -2501,7 +2541,7 @@ static unsigned char *ted_getlightmap(hmsection_t *s, int idx) int x = idx % SECTTEXSIZE, y = idx / SECTTEXSIZE; if (s->lightmap < 0) { - Terr_LoadSection(s->hmmod, s, x, y); + Terr_LoadSection(s->hmmod, s, x, y, true); if (s->lightmap < 0) Terr_InitLightmap(s); } @@ -2832,7 +2872,7 @@ static void ted_itterate(heightmap_t *hm, int distribution, float *pos, float ra { for (sx = min[0]; sx < max[0]; sx++) { - s = Terr_GetSection(hm, sx, sy, true); + s = Terr_GetSection(hm, sx, sy, TGS_FORCELOAD); if (!s) continue; @@ -2907,7 +2947,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g x = bound(hm->firstsegx*4, x, hm->maxsegy*4-1); y = bound(hm->firstsegy*4, y, hm->maxsegy*4-1); - s = Terr_GetSection(hm, x/4, y/4, true); + s = Terr_GetSection(hm, x/4, y/4, TGS_FORCELOAD); if (!s) return; ted_sethole(&quant, s, (x&3) + (y&3)*4, x/4, y/4, 0); @@ -2953,7 +2993,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g x = bound(hm->firstsegx, x, hm->maxsegy-1); y = bound(hm->firstsegy, y, hm->maxsegy-1); - s = Terr_GetSection(hm, x, y, true); + s = Terr_GetSection(hm, x, y, TGS_LOAD); if (!s) return; s->flags |= TSF_HASWATER|TSF_EDITED; @@ -2995,7 +3035,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g x = bound(hm->firstsegx, x, hm->maxsegy-1); y = bound(hm->firstsegy, y, hm->maxsegy-1); - s = Terr_GetSection(hm, x, y, true); + s = Terr_GetSection(hm, x, y, TGS_LOAD); if (!s) return; x = bound(0, quant, 3); @@ -3012,7 +3052,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g x = bound(hm->firstsegx, x, hm->maxsegy-1); y = bound(hm->firstsegy, y, hm->maxsegy-1); - s = Terr_GetSection(hm, x, y, true); + s = Terr_GetSection(hm, x, y, TGS_FORCELOAD); if (!s) return; s->flags |= TSF_EDITED; @@ -3070,7 +3110,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g x = bound(hm->firstsegx, x, hm->maxsegy-1); y = bound(hm->firstsegy, y, hm->maxsegy-1); - s = Terr_GetSection(hm, x, y, true); + s = Terr_GetSection(hm, x, y, TGS_FORCELOAD); if (!s) return; @@ -3106,7 +3146,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g x = bound(hm->firstsegx, x, hm->maxsegy-1); y = bound(hm->firstsegy, y, hm->maxsegy-1); - s = Terr_GetSection(hm, x, y, true); + s = Terr_GetSection(hm, x, y, TGS_FORCELOAD); if (!s) return; @@ -3354,8 +3394,70 @@ void *Mod_LoadTerrainInfo(model_t *mod, char *loadname) return hm; } +void Mod_Terrain_Create_f(void) +{ + char *mname; + char *mdata; + mname = va("maps/%s.hmp", Cmd_Argv(1)); + mdata = va( + "terrain\n" + "{\n" + "classname worldspawn\n" + "_segmentsize 1024\n" + "_minxsegment -2048\n" + "_minysegment -2048\n" + "_maxxsegment 2048\n" + "_maxysegment 2048\n" + "_segmentsize 1024\n" +// "_tiles 64 64 8 8\n" + "}\n" + "{\n" + "classname info_player_start\n" + "origin \"0 0 1024\"\n" + "}\n" + , mname); + COM_WriteFile(mname, mdata, strlen(mdata)); +} +void Mod_Terrain_Reload_f(void) +{ + model_t *mod; + heightmap_t *hm; + if (Cmd_Argc() >= 2) + mod = Mod_FindName(va("maps/%s.hmp", Cmd_Argv(1))); +#ifndef SERVERONLY + else if (cls.state) + mod = cl.worldmodel; +#endif + else + mod = NULL; + if (!mod || mod->type == mod_dummy) + return; + hm = mod->terrain; + if (!hm) + return; + + if (Cmd_Argc() >= 4) + { + hmsection_t *s; + int sx = atoi(Cmd_Argv(2)) + CHUNKBIAS; + int sy = atoi(Cmd_Argv(3)) + CHUNKBIAS; + if (hm) + { + s = Terr_GetSection(hm, sx, sy, TGS_NOLOAD); + if (s) + { + s->flags |= TSF_NOTIFY; + } + } + } + else + Terr_PurgeTerrainModel(mod, false, true); +} + void Terr_Init(void) { Cvar_Register(&mod_terrain_networked, "Terrain"); + Cmd_AddCommand("mod_terrain_create", Mod_Terrain_Create_f); + Cmd_AddCommand("mod_terrain_reload", Mod_Terrain_Reload_f); } #endif diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 5312b360..d0652eea 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -4686,7 +4686,7 @@ typedef struct { short xpos; short ypos; } doomimage_t; -static int FindDoomSprites(const char *name, int size, void *param) +static int FindDoomSprites(const char *name, int size, void *param, void *spath) { if (*(int *)param + strlen(name)+1 > 16000) Sys_Error("Too many doom sprites\n"); diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index b0695af0..ecaed0bf 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -401,6 +401,16 @@ void R_SetupGL (float stereooffset) w = x2 - x; h = y - y2; + fov_x = r_refdef.fov_x;//+sin(cl.time)*5; + fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5; + + if (stereooffset && r_stereo_method.ival == 5) + { + w /= 2; + if (stereooffset > 0) + x += vid.pixelwidth/2; + } + r_refdef.pxrect.x = x; r_refdef.pxrect.y = y; r_refdef.pxrect.width = w; @@ -408,9 +418,6 @@ void R_SetupGL (float stereooffset) qglViewport (x, y2, w, h); - fov_x = r_refdef.fov_x;//+sin(cl.time)*5; - fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5; - if (r_waterwarp.value<0 && (r_viewcontents & FTECONTENTS_FLUID)) { fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); @@ -556,7 +563,8 @@ void R_RenderScene (void) else qglColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE); break; - + case 5: //eyestrain + break; } if (i) qglClear (GL_DEPTH_BUFFER_BIT); @@ -595,12 +603,20 @@ void R_RenderScene (void) case 1: qglDrawBuffer(GL_BACK); break; - case 2: case 3: - case 4: + qglColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); + qglClear(GL_COLOR_BUFFER_BIT); qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); break; - + case 4: + qglColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE); + qglClear(GL_COLOR_BUFFER_BIT); + qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + case 2: + qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + break; + case 5: + break; } } /*generates a new modelview matrix, as well as vpn vectors*/ diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index a4d2bfb2..12ee42c9 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -2977,7 +2977,7 @@ void Shader_Free (shader_t *shader) -int Shader_InitCallback (const char *name, int size, void *param) +int Shader_InitCallback (const char *name, int size, void *param, void *spath) { strcpy(shaderbuf+shaderbuflen, name); Shader_MakeCache(shaderbuf+shaderbuflen); diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 68de1992..a214863b 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -54,13 +54,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "uniform sampler2D s_t2; //diffuse/reflection\n" "#ifdef DEPTH\n" "uniform sampler2D s_t3; //refraction depth\n" -"#ifdef RIPPLEMAP\n" -"uniform sampler2D s_t4; //ripplemap\n" -"#endif\n" +"#define s_ripplemap s_t4\n" "#else\n" -"#ifdef RIPPLEMAP\n" -"uniform sampler2D s_t3; //ripplemap\n" +"#define s_ripplemap s_t3\n" "#endif\n" +"#ifdef RIPPLEMAP\n" +"uniform sampler2D s_ripplemap; //ripplemap\n" "#endif\n" "uniform float e_time;\n" @@ -84,7 +83,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "n -= 1.0 - 4.0/256.0;\n" "#ifdef RIPPLEMAP\n" -"n += texture2D(s_t4, stc).rgb*3.0;\n" +"n += texture2D(s_ripplemap, stc).rgb*3.0;\n" "#endif\n" //the fresnel term decides how transparent the water should be @@ -543,7 +542,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "vec4 col, sp;\n" "#ifdef OFFSETMAPPING\n" -"vec2 tcoffsetmap = offsetmap(s_t4, tcbase, eyevector);\n" +"vec2 tcoffsetmap = offsetmap(s_t4, tc, eyevector);\n" "#define tc tcoffsetmap\n" "#endif\n" diff --git a/engine/http/ftpserver.c b/engine/http/ftpserver.c index 9447f146..ebc5b7ce 100644 --- a/engine/http/ftpserver.c +++ b/engine/http/ftpserver.c @@ -128,7 +128,7 @@ void FTP_ServerShutdown(void) } //we ought to filter this to remove duplicates. -static int SendFileNameTo(const char *rawname, int size, void *param) +static int SendFileNameTo(const char *rawname, int size, void *param, struct searchpath_s *spath) { int socket = *(int*)param; // int i; diff --git a/engine/http/iweb.h b/engine/http/iweb.h index 2ebfaa65..e25bcc61 100644 --- a/engine/http/iweb.h +++ b/engine/http/iweb.h @@ -68,9 +68,9 @@ iwboolean IWebAllowUpLoad(char *fname, char *uname); vfsfile_t *IWebGenerateFile(char *name, char *content, int contentlength); - char *COM_ParseOut (const char *data, char *out, int outlen); -void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *), void *parm); +//struct searchpath_s; +//void COM_EnumerateFiles (const char *match, int (*func)(const char *, int, void *, struct searchpath_s *), void *parm); char *Q_strcpyline(char *out, const char *in, int maxlen); diff --git a/engine/nacl/fs_ppapi.c b/engine/nacl/fs_ppapi.c index f6653664..d4f3587f 100644 --- a/engine/nacl/fs_ppapi.c +++ b/engine/nacl/fs_ppapi.c @@ -345,7 +345,7 @@ static void FSPPAPI_ClosePath(void *handle) Z_Free(handle); } -int Sys_EnumerateFiles (const char *rootpath, const char *match, int (*func)(const char *, int, void *), void *parm) +int Sys_EnumerateFiles (const char *rootpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath) { int rootlen = strlen(rootpath); char *sub; @@ -362,33 +362,33 @@ int Sys_EnumerateFiles (const char *rootpath, const char *match, int (*func)(con sub++; if (wildcmp(match, sub)) { - if (!func(sub, f->length, parm)) + if (!func(sub, f->length, parm, spath)) return false; } } return true; } -static int FSPPAPI_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *), void *parm) +static int FSPPAPI_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath) { - return Sys_EnumerateFiles((char*)handle, match, func, parm); + return Sys_EnumerateFiles((char*)handle, match, func, parm, spath); } -static int FSPPAPI_RebuildFSHash(const char *filename, int filesize, void *data) +static int FSPPAPI_RebuildFSHash(const char *filename, int filesize, void *data, void *handle) { if (filename[strlen(filename)-1] == '/') { //this is actually a directory char childpath[256]; Q_snprintfz(childpath, sizeof(childpath), "%s*", filename); - Sys_EnumerateFiles((char*)data, childpath, FSPPAPI_RebuildFSHash, data); + Sys_EnumerateFiles((char*)data, childpath, FSPPAPI_RebuildFSHash, data, handle); return true; } - FS_AddFileHash(0, filename, NULL, data); + FS_AddFileHash(0, filename, NULL, handle); return true; } static void FSPPAPI_BuildHash(void *handle, int depth) { - Sys_EnumerateFiles(handle, "*", FSPPAPI_RebuildFSHash, handle); + Sys_EnumerateFiles(handle, "*", FSPPAPI_RebuildFSHash, handle, handle); } /* diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index e389bef2..e3f5308e 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -3847,8 +3847,8 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *func) //warning, the func could //note that we don't allow passing 0.0f for null. //WARNING: field 0 is actually a valid field, and is commonly modelindex. } - else if (p->type == ev_field && e->type->type == ev_field && (p->aux_type->type == ev_variant || e->type->aux_type->type == ev_variant)) - { //allow passing variant fields etc + else if ((p->type == ev_field || p->type == ev_pointer) && e->type->type == p->type && (p->aux_type->type == ev_variant || e->type->aux_type->type == ev_variant || p->aux_type->type == ev_void || e->type->aux_type->type == ev_void)) + { //allow passing variant fields etc (also allow .void or *void as universal/variant field/pointer types) } else if ((p->type == ev_vector) && e->type->type == ev_integer && e->constant && !((int*)qcc_pr_globals)[e->ofs]) { diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index aedb06d6..f8aaf2db 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -1,4 +1,4 @@ -#include "qwsvdef.h" +#include "quakedef.h" #ifndef CLIENTONLY /*Testing this code should typically be done with the three following mods: diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 93d10515..0fa9976d 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "qwsvdef.h" +#include "quakedef.h" #ifdef SQL #include "sv_sql.h" @@ -105,6 +105,21 @@ void PF_InitTempStrings(pubprogfuncs_t *prinst); void PR_DumpPlatform_f(void); +typedef struct qcstate_s +{ + float resumetime; + qboolean waiting; + struct qcthread_s *thread; + int self; + int selfid; + int other; + int otherid; + float returnval; + + struct qcstate_s *next; +} qcstate_t; +qcstate_t *qcthreads; + typedef struct { //for func finding and swapping. char *name; @@ -163,9 +178,22 @@ progstype_t progstype; void PR_RegisterFields(void); void PR_ResetBuiltins(progstype_t type); -char *QC_ProgsNameForEnt(edict_t *ent) +static qcstate_t *PR_CreateThread(pubprogfuncs_t *prinst, float retval, float resumetime, qboolean wait) { - return "?"; + qcstate_t *state; + + state = prinst->parms->memalloc(sizeof(qcstate_t)); + state->next = qcthreads; + qcthreads = state; + state->resumetime = resumetime; + state->self = NUM_FOR_EDICT(prinst, PROG_TO_EDICT(prinst, pr_global_struct->self)); + state->selfid = PROG_TO_EDICT(prinst, state->self)->xv->uniquespawnid; + state->other = NUM_FOR_EDICT(prinst, PROG_TO_EDICT(prinst, pr_global_struct->other)); + state->otherid = PROG_TO_EDICT(prinst, state->other)->xv->uniquespawnid; + state->thread = prinst->Fork(prinst); + state->waiting = wait; + state->returnval = retval; + return state; } void PDECL ED_Spawned (struct edict_s *ent, int loading) @@ -5550,35 +5578,83 @@ void QCBUILTIN PF_sqldisconnect (pubprogfuncs_t *prinst, struct globalvars_s *pr } } +static qboolean PR_SQLResultAvailable(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof) +{ + edict_t *ent; + pubprogfuncs_t *prinst = svprogfuncs; + struct globalvars_s *pr_globals = PR_globals(prinst, PR_CURRENT); + + if (req->user.qccallback) + { + G_FLOAT(OFS_PARM0) = req->srvid; + G_FLOAT(OFS_PARM1) = req->num; + G_FLOAT(OFS_PARM2) = numrows; + G_FLOAT(OFS_PARM3) = numcols; + G_FLOAT(OFS_PARM4) = eof; + G_FLOAT(OFS_PARM5) = firstrow; + + // recall self and other references + ent = PROG_TO_EDICT(prinst, req->user.selfent); + if (ent->isfree || ent->xv->uniquespawnid != req->user.selfid) + pr_global_struct->self = pr_global_struct->world; + else + pr_global_struct->self = req->user.selfent; + ent = PROG_TO_EDICT(prinst, req->user.otherent); + if (ent->isfree || ent->xv->uniquespawnid != req->user.otherid) + pr_global_struct->other = pr_global_struct->world; + else + pr_global_struct->other = req->user.otherent; + + PR_ExecuteProgram(svprogfuncs, req->user.qccallback); + } + if (eof && req->user.thread) + { + qcstate_t *thread = req->user.thread; + req->user.thread = NULL; + if (thread) + thread->waiting = false; + } + + return req->user.persistant; +} + void QCBUILTIN PF_sqlopenquery (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { sqlserver_t *server; int callfunc = G_INT(OFS_PARM1); int querytype = G_FLOAT(OFS_PARM2); char *querystr = PF_VarString(prinst, 3, pr_globals); - int qself, qother; - float qselfid, qotherid; if (SQL_Available()) { server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); if (server) { - // save self and other references - if (PROG_TO_EDICT(prinst, pr_global_struct->self)->isfree) - qself = pr_global_struct->world; - else - qself = pr_global_struct->self; - qselfid = PROG_TO_EDICT(prinst, qself)->xv->uniquespawnid; - if (PROG_TO_EDICT(prinst, pr_global_struct->other)->isfree) - qother = pr_global_struct->world; - else - qother = pr_global_struct->other; - qotherid = PROG_TO_EDICT(prinst, qother)->xv->uniquespawnid; + queryrequest_t *qreq; Con_DPrintf("SQL Query: %s\n", querystr); - G_FLOAT(OFS_RETURN) = SQL_NewQuery(server, callfunc, querytype, qself, qselfid, qother, qotherid, querystr); + G_FLOAT(OFS_RETURN) = SQL_NewQuery(server, PR_SQLResultAvailable, querystr, &qreq); + + if (qreq) + { + //so our C callback knows what to do + qreq->user.persistant = querytype > 0; + qreq->user.qccallback = callfunc; + + // save self and other references + qreq->user.selfent = PROG_TO_EDICT(prinst, pr_global_struct->self)->isfree?pr_global_struct->world:pr_global_struct->self; + qreq->user.selfid = PROG_TO_EDICT(prinst, qreq->user.selfent)->xv->uniquespawnid; + qreq->user.otherent = PROG_TO_EDICT(prinst, pr_global_struct->other)->isfree?pr_global_struct->world:pr_global_struct->other; + qreq->user.otherid = PROG_TO_EDICT(prinst, qreq->user.otherent)->xv->uniquespawnid; + + if (querytype & 2) + { + qreq->user.thread = PR_CreateThread(prinst, G_FLOAT(OFS_RETURN), 0, true); + + svprogfuncs->AbortStack(prinst); + } + } return; } } @@ -5589,20 +5665,21 @@ void QCBUILTIN PF_sqlopenquery (pubprogfuncs_t *prinst, struct globalvars_s *pr_ void QCBUILTIN PF_sqlclosequery (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { sqlserver_t *server; - queryresult_t *qres; + queryrequest_t *qreq; if (SQL_Available()) { server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); if (server) { - qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1)); - if (qres) + qreq = SQL_GetQueryRequest(server, G_FLOAT(OFS_PARM1)); + if (qreq) { - // TODO: partial resultset logic not implemented yet - SQL_CloseResult(server, qres); + SQL_CloseRequest(server, qreq, false); return; } + else + Con_Printf("Invalid sql request\n"); } } // else nothing to close @@ -5619,7 +5696,7 @@ void QCBUILTIN PF_sqlreadfield (pubprogfuncs_t *prinst, struct globalvars_s *pr_ server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); if (server) { - qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1)); + qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2)); if (qres) { data = SQL_ReadField(server, qres, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), true); @@ -5629,6 +5706,10 @@ void QCBUILTIN PF_sqlreadfield (pubprogfuncs_t *prinst, struct globalvars_s *pr_ return; } } + else + { + Con_Printf("Invalid sql request/row\n"); + } } } // else we failed to get anything @@ -5638,6 +5719,7 @@ void QCBUILTIN PF_sqlreadfield (pubprogfuncs_t *prinst, struct globalvars_s *pr_ void QCBUILTIN PF_sqlreadfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { sqlserver_t *server; + queryrequest_t *qreq; queryresult_t *qres; char *data; @@ -5646,16 +5728,51 @@ void QCBUILTIN PF_sqlreadfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_ server = SQL_GetServer(G_FLOAT(OFS_PARM0), false); if (server) { - qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1)); - if (qres) + if (G_FLOAT(OFS_PARM2) < 0) { - data = SQL_ReadField(server, qres, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), true); - if (data) + qreq = SQL_GetQueryRequest(server, G_FLOAT(OFS_PARM1)); + if (qreq->results) { - G_FLOAT(OFS_RETURN) = Q_atof(data); + if (G_FLOAT(OFS_PARM2) == -2) + G_FLOAT(OFS_RETURN) = qreq->results->columns; + else if (G_FLOAT(OFS_PARM2) == -3) + G_FLOAT(OFS_RETURN) = qreq->results->rows + qreq->results->firstrow; + else + { + Con_Printf("Invalid sql row\n"); + G_FLOAT(OFS_RETURN) = 0; + } return; } } + else + { + qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2)); + if (qres) + { + if (G_FLOAT(OFS_PARM2) == -1) + { + G_FLOAT(OFS_RETURN) = qres->columns; + return; + } + if (G_FLOAT(OFS_PARM2) == -2) + { + G_FLOAT(OFS_RETURN) = qres->rows; + return; + } + + data = SQL_ReadField(server, qres, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), true); + if (data) + { + G_FLOAT(OFS_RETURN) = Q_atof(data); + return; + } + } + else + { + Con_Printf("Invalid sql request/row\n"); + } + } } } // else we failed to get anything @@ -5676,7 +5793,7 @@ void QCBUILTIN PF_sqlerror (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob { // query-specific error request if (server->active) // didn't check this earlier so check it now { - queryresult_t *qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1)); + queryresult_t *qres = SQL_GetQueryResult(server, G_FLOAT(OFS_PARM1), G_FLOAT(OFS_PARM2)); if (qres) { RETURN_TSTRING(qres->error); @@ -5738,14 +5855,9 @@ void QCBUILTIN PF_sqlversion (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl void PR_SQLCycle(void) { - globalvars_t *pr_globals; - - if (!SQL_Available() || !svprogfuncs) + if (!SQL_Available()) return; - - pr_globals = PR_globals(svprogfuncs, PR_CURRENT); - - SQL_ServerCycle(svprogfuncs, pr_globals); + SQL_ServerCycle(); } #endif @@ -7653,17 +7765,6 @@ static void QCBUILTIN PF_sv_pointparticles(pubprogfuncs_t *prinst, struct global #endif } - -typedef struct qcstate_s { - float resumetime; - struct qcthread_s *thread; - int self; - int other; - - struct qcstate_s *next; -} qcstate_t; - -qcstate_t *qcthreads; void PRSV_RunThreads(void) { struct globalvars_s *pr_globals; @@ -7674,7 +7775,7 @@ void PRSV_RunThreads(void) { next = state->next; - if (state->resumetime > sv.time) + if (state->resumetime > sv.time || state->waiting) { //not time yet, reform original list. state->next = qcthreads; qcthreads = state; @@ -7685,7 +7786,7 @@ void PRSV_RunThreads(void) pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, EDICT_NUM(svprogfuncs, state->self)); pr_global_struct->other = EDICT_TO_PROG(svprogfuncs, EDICT_NUM(svprogfuncs, state->other)); - G_FLOAT(OFS_RETURN) = 1; + G_FLOAT(OFS_RETURN) = state->returnval; svprogfuncs->RunThread(svprogfuncs, state->thread); svprogfuncs->parms->memfree(state->thread); @@ -7713,29 +7814,17 @@ static void PRSV_ClearThreads(void) static void QCBUILTIN PF_Sleep(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - qcstate_t *state; - struct qcthread_s *thread; float sleeptime; sleeptime = G_FLOAT(OFS_PARM0); - thread = svprogfuncs->Fork(svprogfuncs); + PR_CreateThread(prinst, 1, sv.time + sleeptime, false); - state = svprogfuncs->parms->memalloc(sizeof(qcstate_t)); - state->next = qcthreads; - qcthreads = state; - state->resumetime = sv.time + sleeptime; - state->self = NUM_FOR_EDICT(svprogfuncs, PROG_TO_EDICT(svprogfuncs, pr_global_struct->self)); - state->other = NUM_FOR_EDICT(svprogfuncs, PROG_TO_EDICT(svprogfuncs, pr_global_struct->other)); - state->thread = thread; - - svprogfuncs->AbortStack(svprogfuncs); + prinst->AbortStack(prinst); } static void QCBUILTIN PF_Fork(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - qcstate_t *state; - struct qcthread_s *thread; float sleeptime; if (svprogfuncs->callargc >= 1) @@ -7743,15 +7832,7 @@ static void QCBUILTIN PF_Fork(pubprogfuncs_t *prinst, struct globalvars_s *pr_gl else sleeptime = 0; - thread = svprogfuncs->Fork(svprogfuncs); - - state = svprogfuncs->parms->memalloc(sizeof(qcstate_t)); - state->next = qcthreads; - qcthreads = state; - state->resumetime = sv.time + sleeptime; - state->self = NUM_FOR_EDICT(svprogfuncs, PROG_TO_EDICT(svprogfuncs, pr_global_struct->self)); - state->other = NUM_FOR_EDICT(svprogfuncs, PROG_TO_EDICT(svprogfuncs, pr_global_struct->other)); - state->thread = thread; + PR_CreateThread(prinst, 1, sv.time + sleeptime, false); PRSV_RunThreads(); diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index 0dc7c645..ebcd484a 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" -#include "qwsvdef.h" #ifdef VM_Q1 diff --git a/engine/server/qwsvdef.h b/engine/server/qwsvdef.h deleted file mode 100644 index b0ed8477..00000000 --- a/engine/server/qwsvdef.h +++ /dev/null @@ -1,106 +0,0 @@ -/* -Copyright (C) 1996-1997 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ -// quakedef.h -- primary header for server -#define QUAKEDEF_H__ -#if 1//ndef SERVERONLY -#include "../client/quakedef.h" -#else - -#define QUAKE_GAME // as opposed to utilities - -//define PARANOID // speed sapping error checking - -#include -#include -#include -#include -#include -#include -#include - -#include "bothdefs.h" - -#ifdef MSVCDISABLEWARNINGS -#pragma warning( disable : 4244 4127 4201 4214 4514 4305 4115 4018) -#endif - -#include "translate.h" - -#include "common.h" -#include "bspfile.h" -#include "sys.h" -#include "zone.h" -#include "mathlib.h" - -#include "cvar.h" -#include "net.h" -#include "protocol.h" -#include "cmd.h" -#include "model.h" -#include "crc.h" -#include "progtype.h" -#include "progdefs.h" -#include "progs.h" -#include "q2game.h" - -#include "server.h" -#include "world.h" -#include "pmove.h" - -//============================================================================= - -// the host system specifies the base of the directory tree, the -// command line parms passed to the program, and the amount of memory -// available for the program to use - -typedef struct quakeparms_s -{ - char *basedir; - int argc; - char **argv; - void *membase; - int memsize; -} quakeparms_t; - - -//============================================================================= - -// -// host -// -extern quakeparms_t host_parms; - -extern cvar_t sys_nostdout; -extern cvar_t developer; - -extern qboolean host_initialized; // true if into command execution -extern double host_frametime; -extern double realtime; // not bounded in any way, changed at - // start of every frame, never reset - -void SV_Error (char *error, ...) LIKEPRINTF(1); -void SV_Init (struct quakeparms_s *parms); - -void Con_Printf (char *fmt, ...) LIKEPRINTF(1); -void Con_TPrintf (translation_t fmt, ...); -void Con_DPrintf (char *fmt, ...) LIKEPRINTF(1); - -#endif - diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 4c8a947f..bad7eabc 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -1,4 +1,4 @@ -#include "qwsvdef.h" +#include "quakedef.h" #ifndef CLIENTONLY diff --git a/engine/server/server.h b/engine/server/server.h index e7dbd18b..5a276b84 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -941,9 +941,7 @@ struct quakeparms_s; void SV_Init (struct quakeparms_s *parms); int SV_CalcPing (client_t *cl, qboolean forcecalc); -void SV_FullClientUpdate (client_t *client, sizebuf_t *buf, unsigned int ftepext); -void SV_FullClientUpdateToClient (client_t *client, client_t *cl); -void SVNQ_FullClientUpdate (client_t *client, sizebuf_t *buf); +void SV_FullClientUpdate (client_t *client, client_t *to); int SV_ModelIndex (char *name); diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 90784767..3c390d2c 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "qwsvdef.h" +#include "quakedef.h" #ifndef CLIENTONLY @@ -374,7 +374,7 @@ void SV_Give_f (void) } } -int ShowMapList (const char *name, int flags, void *parm) +int ShowMapList (const char *name, int flags, void *parm, struct searchpath_s *spath) { if (name[5] == 'b' && name[6] == '_') //skip box models return true; @@ -1454,6 +1454,18 @@ void SV_Status_f (void) Con_Printf ("current map : %s\n", sv.name); Con_Printf("entities : %i/%i\n", sv.world.num_edicts, sv.world.max_edicts); + if (svs.gametype == GT_PROGS) + { + int count = 0; + for (count = 1; count < MAX_MODELS; count++) + if (!sv.strings.model_precache[count]) + break; + Con_Printf("models : %i/%i\n", count, MAX_MODELS); + for (count = 1; count < MAX_SOUNDS; count++) + if (!*sv.strings.sound_precache[count]) + break; + Con_Printf("sounds : %i/%i\n", count, MAX_SOUNDS); + } Con_Printf("gamedir : %s\n", FS_GetGamedir()); if (sv.csqcdebug) Con_Printf("csqc debug : true\n"); diff --git a/engine/server/sv_chat.c b/engine/server/sv_chat.c index 637ce50e..175aba13 100644 --- a/engine/server/sv_chat.c +++ b/engine/server/sv_chat.c @@ -1,4 +1,4 @@ -#include "qwsvdef.h" +#include "quakedef.h" /* NPC chat: diff --git a/engine/server/sv_demo.c b/engine/server/sv_demo.c index b8bb9d41..780da30e 100644 --- a/engine/server/sv_demo.c +++ b/engine/server/sv_demo.c @@ -1,4 +1,4 @@ -#include "qwsvdef.h" +#include "quakedef.h" #ifndef CLIENTONLY #ifdef SERVER_DEMO_PLAYBACK diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 2c3e12be..0b599e77 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "qwsvdef.h" +#include "quakedef.h" #include "pr_common.h" #ifndef CLIENTONLY @@ -436,7 +436,7 @@ void SV_CSQC_DroppedPacket(client_t *client, int sequence) int m; if (!client->frameunion.frames) { - Con_Printf("BLAME %s\n", client->state?client->name:"a zombie"); + Con_Printf("Server bug: No frames!\n"); return; } diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index a209c695..b776b234 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "qwsvdef.h" +#include "quakedef.h" #ifndef CLIENTONLY extern int total_loading_size, current_loading_size, loading_stage; char *T_GetString(int num); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 73277947..619518d0 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "qwsvdef.h" +#include "quakedef.h" #include "netinc.h" #include #ifndef CLIENTONLY @@ -150,22 +150,6 @@ cvar_t sv_masterport = CVAR("sv_masterport", "0"); cvar_t sv_gamespeed = CVAR("sv_gamespeed", "1"); cvar_t sv_csqcdebug = CVAR("sv_csqcdebug", "0"); cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat"); -#ifdef TCPCONNECT -cvar_t sv_port_tcp = CVARC("sv_port_tcp", "", SV_Tcpport_Callback); -#ifdef IPPROTO_IPV6 -cvar_t sv_port_tcp6 = CVARC("sv_port_tcp6", "", SV_Tcpport6_Callback); -#endif -#endif -#ifdef HAVE_IPV4 -cvar_t sv_port_ipv4 = CVARC("sv_port", "27500", SV_Port_Callback); -#endif -#ifdef IPPROTO_IPV6 -cvar_t sv_port_ipv6 = CVARC("sv_port_ipv6", "", SV_PortIPv6_Callback); -#endif -#ifdef USEIPX -cvar_t sv_port_ipx = CVARC("sv_port_ipx", "", SV_PortIPX_Callback); -#endif - cvar_t pausable = CVAR("pausable", "1"); @@ -646,10 +630,7 @@ void SV_DropClient (client_t *drop) if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) //gamecode should do it all for us. { // send notification to all remaining clients - SV_FullClientUpdate (drop, &sv.reliable_datagram, 0); -#ifdef NQPROT - SVNQ_FullClientUpdate (drop, &sv.nqreliable_datagram); -#endif + SV_FullClientUpdate (drop, NULL); SV_MVD_FullClientUpdate(NULL, drop); } @@ -732,10 +713,10 @@ void PIN_SaveMessages(void) pinnedmessages_t *p; vfsfile_t *f; - f = FS_OpenVFS("pinned.txt", "wt", FS_GAMEONLY); + f = FS_OpenVFS("pinned.txt", "wb", FS_GAMEONLY); if (!f) { - Con_Printf("couldn't write anything\n"); + Con_Printf("couldn't write to %s\n", "pinned.txt"); return; } @@ -746,7 +727,11 @@ void PIN_SaveMessages(void) } void PIN_DeleteOldestMessage(void) { - pinnedmessages_t *old = pinned; + pinnedmessages_t *old; + if (dopinnedload) + PIN_LoadMessages(); + + old = pinned; if (old) { pinned = pinned->next; @@ -758,6 +743,9 @@ void PIN_MakeMessage(char *from, char *msg) pinnedmessages_t *p; pinnedmessages_t *newp; + if (dopinnedload) + PIN_LoadMessages(); + newp = BZ_Malloc(sizeof(pinnedmessages_t)); Q_strncpyz(newp->setby, from, sizeof(newp->setby)); Q_strncpyz(newp->message, msg, sizeof(newp->message)); @@ -884,156 +872,89 @@ void SV_GenerateBasicUserInfo(client_t *cl) =================== SV_FullClientUpdate -Writes all update values to a sizebuf +Writes all update values to client. use to=NULL to broadcast. =================== */ -void SV_FullClientUpdate (client_t *client, sizebuf_t *buf, unsigned int ftepext) +void SV_FullClientUpdate (client_t *client, client_t *to) { int i; char info[MAX_INFO_STRING]; + if (!to) + { + for (i = 0; i < sv.allocated_client_slots; i++) + { + SV_FullClientUpdate(client, &svs.clients[i]); + } + return; + } + i = client - svs.clients; -#ifdef SERVER_DEMO_PLAYBACK - if (sv.demofile) +//Sys_Printf("SV_FullClientUpdate: Updated frags for client %d\n", i); + + if (ISQWCLIENT(to)) { - MSG_WriteByte (buf, svc_updatefrags); - MSG_WriteByte (buf, i); - MSG_WriteShort (buf, sv.recordedplayer[i].frags); + ClientReliableWrite_Begin(to, svc_updatefrags, 4); + ClientReliableWrite_Byte (to, i); + ClientReliableWrite_Short(to, client->old_frags); - MSG_WriteByte (buf, svc_updateping); - MSG_WriteByte (buf, i); - MSG_WriteShort (buf, sv.recordedplayer[i].ping); + ClientReliableWrite_Begin (to, svc_updateping, 4); + ClientReliableWrite_Byte (to, i); + ClientReliableWrite_Short (to, SV_CalcPing (client, false)); - MSG_WriteByte (buf, svc_updatepl); - MSG_WriteByte (buf, i); - MSG_WriteByte (buf, sv.recordedplayer[i].pl); + ClientReliableWrite_Begin (to, svc_updatepl, 3); + ClientReliableWrite_Byte (to, i); + ClientReliableWrite_Byte (to, client->lossage); - MSG_WriteByte (buf, svc_updateentertime); - MSG_WriteByte (buf, i); - MSG_WriteFloat (buf, 0); + ClientReliableWrite_Begin (to, svc_updateentertime, 6); + ClientReliableWrite_Byte (to, i); + ClientReliableWrite_Float (to, realtime - client->connection_started); - Q_strncpyz (info, sv.recordedplayer[i].userinfo, sizeof(info)); + if ((to->fteprotocolextensions) & PEXT_BIGUSERINFOS) + Q_strncpyz (info, client->userinfo, sizeof(info)); + else + Q_strncpyz (info, client->userinfobasic, sizeof(info)); Info_RemoveKey(info, "password"); //main password key - Info_RemoveKey(info, "*ip"); //don't broadcast this in playback Info_RemovePrefixedKeys (info, '_'); // server passwords, etc - MSG_WriteByte (buf, svc_updateuserinfo); - MSG_WriteByte (buf, i); - MSG_WriteLong (buf, sv.recordedplayer[i].userid); - MSG_WriteString (buf, info); - return; + ClientReliableWrite_Begin(to, svc_updateuserinfo, 7 + strlen(info)); + ClientReliableWrite_Byte (to, i); + ClientReliableWrite_Long (to, client->userid); + ClientReliableWrite_String(to, info); } -#endif - -//Sys_Printf("SV_FullClientUpdate: Updated frags for client %d\n", i); - - MSG_WriteByte (buf, svc_updatefrags); - MSG_WriteByte (buf, i); - MSG_WriteShort (buf, client->old_frags); - - MSG_WriteByte (buf, svc_updateping); - MSG_WriteByte (buf, i); - MSG_WriteShort (buf, SV_CalcPing (client, false)); - - MSG_WriteByte (buf, svc_updatepl); - MSG_WriteByte (buf, i); - MSG_WriteByte (buf, client->lossage); - - MSG_WriteByte (buf, svc_updateentertime); - MSG_WriteByte (buf, i); - MSG_WriteFloat (buf, realtime - client->connection_started); - -#ifdef warningmsg -#pragma warningmsg("this is a bug: it can be broadcast to all qw clients") -#endif - if (ftepext & PEXT_BIGUSERINFOS) - Q_strncpyz (info, client->userinfo, sizeof(info)); - else - Q_strncpyz (info, client->userinfobasic, sizeof(info)); - Info_RemoveKey(info, "password"); //main password key - Info_RemovePrefixedKeys (info, '_'); // server passwords, etc - - MSG_WriteByte (buf, svc_updateuserinfo); - MSG_WriteByte (buf, i); - MSG_WriteLong (buf, client->userid); - MSG_WriteString (buf, info); -} -#ifdef NQPROT -void SVNQ_FullClientUpdate (client_t *client, sizebuf_t *buf) -{ - int playercolor, top, bottom; - int i; - - i = client - svs.clients; - - if (i >= 16) - return; - -//Sys_Printf("SV_FullClientUpdate: Updated frags for client %d\n", i); - - MSG_WriteByte (buf, svc_updatefrags); - MSG_WriteByte (buf, i); - MSG_WriteShort (buf, client->old_frags); - - MSG_WriteByte (buf, svc_updatename); - MSG_WriteByte (buf, i); - MSG_WriteString (buf, Info_ValueForKey(client->userinfo, "name")); - - top = atoi(Info_ValueForKey(client->userinfo, "topcolor")); - bottom = atoi(Info_ValueForKey(client->userinfo, "bottomcolor")); - top &= 15; - if (top > 13) - top = 13; - bottom &= 15; - if (bottom > 13) - bottom = 13; - playercolor = top*16 + bottom; - MSG_WriteByte (buf, svc_updatecolors); - MSG_WriteByte (buf, i); - MSG_WriteByte (buf, playercolor); -} -#endif -/* -=================== -SV_FullClientUpdateToClient - -Writes all update values to a client's reliable stream -=================== -*/ -void SV_FullClientUpdateToClient (client_t *client, client_t *cl) -{ -#ifdef NQPROT - if (!ISQWCLIENT(cl)) + else if (ISNQCLIENT(to)) { - ClientReliableCheckBlock(cl, 24 + strlen(client->userinfo)); - if (cl->num_backbuf) { - SVNQ_FullClientUpdate (client, &cl->backbuf); - ClientReliable_FinishWrite(cl); - } else - SVNQ_FullClientUpdate (client, &cl->netchan.message); - } - else -#endif - { -#ifdef SERVER_DEMO_PLAYBACK - if (sv.demofile) - { - int i = client - svs.clients; - ClientReliableCheckBlock(cl, 24 + strlen(sv.recordedplayer[i].userinfo)); - } - else -#endif - ClientReliableCheckBlock(cl, 24 + strlen(client->userinfo)); - if (cl->num_backbuf) { - SV_FullClientUpdate (client, &cl->backbuf, cl->fteprotocolextensions); - ClientReliable_FinishWrite(cl); - } else - SV_FullClientUpdate (client, &cl->netchan.message, cl->fteprotocolextensions); + int top, bottom, playercolor; + char *nam = Info_ValueForKey(client->userinfo, "name"); + + if (i >= 16) + return; //NQ clients will crash if they see a player index above 16. + + ClientReliableWrite_Begin(to, svc_updatefrags, 4); + ClientReliableWrite_Byte (to, i); + ClientReliableWrite_Short(to, client->old_frags); + + ClientReliableWrite_Begin(to, svc_updatename, 3 + strlen(nam)); + ClientReliableWrite_Byte (to, i); + ClientReliableWrite_String(to, nam); + + top = atoi(Info_ValueForKey(client->userinfo, "topcolor")); + bottom = atoi(Info_ValueForKey(client->userinfo, "bottomcolor")); + top &= 15; + if (top > 13) + top = 13; + bottom &= 15; + if (bottom > 13) + bottom = 13; + playercolor = top*16 + bottom; + + ClientReliableWrite_Begin (to, svc_updatecolors, 3); + ClientReliableWrite_Byte (to, i); + ClientReliableWrite_Byte (to, playercolor); } } - /* ============================================================================== @@ -3101,7 +3022,7 @@ qboolean SV_ConnectionlessPacket (void) } #ifdef NQPROT -void SVNQ_ConnectionlessPacket(void) +qboolean SVNQ_ConnectionlessPacket(void) { sizebuf_t sb; int header; @@ -3113,15 +3034,16 @@ void SVNQ_ConnectionlessPacket(void) char buffer[256], buffer2[256]; netadr_t localaddr; if (net_from.type == NA_LOOPBACK) - return; + return false; if (!sv_listen_nq.value) - return; + return false; MSG_BeginReading(svs.netprim); header = LongSwap(MSG_ReadLong()); if (!(header & NETFLAG_CTL)) { + //this nasty chunk of code is to try to handle challenges with nq's challengeless protocol, by using stringcmds. woo. evil hacks. if (sv_listen_nq.ival == 2) if ((header & (NETFLAG_DATA|NETFLAG_EOM)) == (NETFLAG_DATA|NETFLAG_EOM)) { @@ -3154,7 +3076,7 @@ void SVNQ_ConnectionlessPacket(void) newcl->netchan.incoming_reliable_sequence = sequence; /*if there is anything else in the packet, we don't actually care. its reliable, so they'll resend*/ - return; + return true; } else MSG_ReadString(); @@ -3193,15 +3115,17 @@ void SVNQ_ConnectionlessPacket(void) *(int*)sb.data = BigLong(NETFLAG_UNRELIABLE|sb.cursize); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); + + return true; } } } - return; //no idea what it is. + return false; //no idea what it is. } length = header & NETFLAG_LENGTH_MASK; if (length != net_message.cursize) - return; //corrupt or not ours + return false; //corrupt or not ours switch(MSG_ReadByte()) { @@ -3216,7 +3140,7 @@ void SVNQ_ConnectionlessPacket(void) MSG_WriteString(&sb, "Incorrect game\n"); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); - return; //not our game. + return false; //not our game. } if (MSG_ReadByte() != NET_PROTOCOL_VERSION) { @@ -3226,7 +3150,7 @@ void SVNQ_ConnectionlessPacket(void) MSG_WriteString(&sb, "Incorrect version\n"); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); - return; //not our version... + return false; //not our version... } mod = MSG_ReadByte(); modver = MSG_ReadByte(); @@ -3272,10 +3196,10 @@ void SVNQ_ConnectionlessPacket(void) SVC_DirectConnect(); } } - break; + return true; case CCREQ_SERVER_INFO: if (Q_strcmp (MSG_ReadString(), NET_GAMENAME_NQ) != 0) - break; + return false; sb.maxsize = sizeof(buffer); sb.data = buffer; @@ -3298,7 +3222,7 @@ void SVNQ_ConnectionlessPacket(void) MSG_WriteByte (&sb, NET_PROTOCOL_VERSION); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); - break; + return true; case CCREQ_PLAYER_INFO: /*one request per player, ouch ouch ouch, what will it make of 32 players, I wonder*/ sb.maxsize = sizeof(buffer); @@ -3326,7 +3250,7 @@ void SVNQ_ConnectionlessPacket(void) } *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); - break; + return true; case CCREQ_RULE_INFO: /*lol, nq is evil*/ sb.maxsize = sizeof(buffer); @@ -3366,8 +3290,9 @@ void SVNQ_ConnectionlessPacket(void) } *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, net_from); - break; + return true; } + return false; } #endif @@ -3476,7 +3401,6 @@ SV_ReadPackets //FIMXE: move to header qboolean SV_GetPacket (void); #endif - qboolean SV_ReadPackets (float *delay) { int i; @@ -3518,7 +3442,7 @@ qboolean SV_ReadPackets (float *delay) if (ISNQCLIENT(cl)) { - if (cl->state != cs_zombie) + if (cl->state > cs_zombie) { if (NQNetChan_Process(&cl->netchan)) { @@ -3695,9 +3619,13 @@ dominping: #endif #ifdef NQPROT - SVNQ_ConnectionlessPacket(); + if (SVNQ_ConnectionlessPacket()) + continue; #endif + if (NET_WasSpecialPacket()) + continue; + // packet is not from a known client // Con_Printf ("%s:sequenced packet without connection\n" // ,NET_AdrToString(net_from)); @@ -4297,26 +4225,7 @@ void SV_InitLocal (void) Cvar_Register (&sv_listen_q3, cvargroup_servercontrol); sv_listen_qw.restriction = RESTRICT_MAX; -#ifdef TCPCONNECT - Cvar_Register (&sv_port_tcp, cvargroup_servercontrol); - sv_port_tcp.restriction = RESTRICT_MAX; -#ifdef IPPROTO_IPV6 - Cvar_Register (&sv_port_tcp6, cvargroup_servercontrol); - sv_port_tcp6.restriction = RESTRICT_MAX; -#endif -#endif -#ifdef IPPROTO_IPV6 - Cvar_Register (&sv_port_ipv6, cvargroup_servercontrol); - sv_port_ipv6.restriction = RESTRICT_MAX; -#endif -#ifdef USEIPX - Cvar_Register (&sv_port_ipx, cvargroup_servercontrol); - sv_port_ipx.restriction = RESTRICT_MAX; -#endif -#ifdef HAVE_IPV4 - Cvar_Register (&sv_port_ipv4, cvargroup_servercontrol); - sv_port_ipv4.restriction = RESTRICT_MAX; -#endif + SVNET_RegisterCvars(); Cvar_Register (&sv_reportheartbeats, cvargroup_servercontrol); @@ -4397,32 +4306,7 @@ void SV_InitLocal (void) svs.log[1].cursize = 0; svs.log[1].allowoverflow = true; - svs.free_lagged_packet = NULL; - - // parse params for cvars - p = COM_CheckParm ("-port"); - if (!p) - p = COM_CheckParm ("-svport"); - if (p && p < com_argc) - { - int port = atoi(com_argv[p+1]); - if (!port) - port = PORT_QWSERVER; -#ifdef HAVE_IPV4 - if (*sv_port_ipv4.string) - Cvar_SetValue(&sv_port_ipv4, port); -#endif -#ifdef IPPROTO_IPV6 - if (*sv_port_ipv6.string) - Cvar_SetValue(&sv_port_ipv6, port); -#endif -#ifdef USEIPX - if (*sv_port_ipx.string) - Cvar_SetValue(&sv_port_ipx, port); -#endif - } - } diff --git a/engine/server/sv_master.c b/engine/server/sv_master.c index d06d0a95..91e2a227 100644 --- a/engine/server/sv_master.c +++ b/engine/server/sv_master.c @@ -1,4 +1,4 @@ -#include "qwsvdef.h" +#include "quakedef.h" #ifdef SV_MASTER diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 97aa345d..d2104be0 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "qwsvdef.h" +#include "quakedef.h" #ifndef CLIENTONLY #include "winquake.h" @@ -683,7 +683,7 @@ typedef struct #define SORT_NO 0 #define SORT_BY_DATE 1 -int Sys_listdirFound(const char *fname, int fsize, void *uptr) +int Sys_listdirFound(const char *fname, int fsize, void *uptr, struct searchpath_s *spath) { file_t *f; dir_t *dir = uptr; diff --git a/engine/server/sv_nchan.c b/engine/server/sv_nchan.c index 78f571f3..f0e84e4a 100644 --- a/engine/server/sv_nchan.c +++ b/engine/server/sv_nchan.c @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_nchan.c, user reliable data stream writes -#include "qwsvdef.h" +#include "quakedef.h" #ifndef CLIENTONLY // check to see if client block will fit, if not, rotate buffers diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index fffa4317..eec845e9 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_phys.c -#include "qwsvdef.h" +#include "quakedef.h" #if !defined(CLIENTONLY) || defined(CSQC_DAT) #include "pr_common.h" diff --git a/engine/server/sv_rankin.c b/engine/server/sv_rankin.c index ae16aa56..d23a13f7 100644 --- a/engine/server/sv_rankin.c +++ b/engine/server/sv_rankin.c @@ -1,4 +1,4 @@ -#include "qwsvdef.h" +#include "quakedef.h" #ifndef CLIENTONLY diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 2b292f38..81d3272c 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_main.c -- server main program -#include "qwsvdef.h" +#include "quakedef.h" #ifndef CLIENTONLY @@ -2147,7 +2147,7 @@ void SV_UpdateToReliableMessages (void) if (host_client->sendinfo) { host_client->sendinfo = false; - SV_FullClientUpdate (host_client, &sv.reliable_datagram, host_client->fteprotocolextensions); + SV_FullClientUpdate (host_client, NULL); } if (host_client->old_frags != curfrags) { diff --git a/engine/server/sv_sql.c b/engine/server/sv_sql.c index 0247a042..c3176e21 100644 --- a/engine/server/sv_sql.c +++ b/engine/server/sv_sql.c @@ -131,27 +131,30 @@ queryresult_t *SQL_PullResult(sqlserver_t *server) return qres; } +//called by main thread void SQL_PushRequest(sqlserver_t *server, queryrequest_t *qreq) { + qreq->state = SR_PENDING; Sys_LockConditional(server->requestcondv); - qreq->next = NULL; + qreq->nextqueue = NULL; if (!server->requestslast) - server->requests = server->requestslast = qreq; + server->requestqueue = server->requestslast = qreq; else - server->requestslast = server->requestslast->next = qreq; + server->requestslast = server->requestslast->nextqueue = qreq; Sys_UnlockConditional(server->requestcondv); } +//called by sql worker thread queryrequest_t *SQL_PullRequest(sqlserver_t *server, qboolean lock) { queryrequest_t *qreq; if (lock) Sys_LockConditional(server->requestcondv); - qreq = server->requests; + qreq = server->requestqueue; if (qreq) { - server->requests = qreq->next; - if (!server->requests) + server->requestqueue = qreq->nextqueue; + if (!server->requestqueue) server->requestslast = NULL; } Sys_UnlockConditional(server->requestcondv); @@ -249,7 +252,7 @@ int sql_serverworker(void *sref) while (allokay) { Sys_LockConditional(server->requestcondv); - if (!server->requests) // this is needed for thread startup and to catch any "lost" changes + if (!server->requestqueue) // this is needed for thread startup and to catch any "lost" changes Sys_ConditionWait(server->requestcondv); needlock = false; // so we don't try to relock first round @@ -313,7 +316,6 @@ int sql_serverworker(void *sref) qres->columns = columns; qres->request = qreq; qres->eof = true; // store result has no more rows to read afterwards - qreq->next = NULL; SQL_PushResult(server, qres); } @@ -363,7 +365,7 @@ int sql_serverworker(void *sref) qres->request = qreq; qres->firstrow = totalrows; qres->eof = false; - qreq->next = NULL; + qreq->nextqueue = NULL; //headers technically take a row. for (i = 0; i < columns; i++) @@ -428,7 +430,7 @@ int sql_serverworker(void *sref) qres->firstrow = totalrows; qres->request = qreq; qres->eof = true; - qreq->next = NULL; + qreq->nextqueue = NULL; SQL_PushResult(server, qres); } @@ -495,16 +497,26 @@ sqlserver_t *SQL_GetServer (int serveridx, qboolean inactives) return sqlservers[serveridx]; } -queryresult_t *SQL_GetQueryResult (sqlserver_t *server, int queryidx) +queryrequest_t *SQL_GetQueryRequest (sqlserver_t *server, int queryidx) +{ + queryrequest_t *qreq; + for (qreq = server->requests; qreq; qreq = qreq->nextreq) + { + if (qreq->num == queryidx) + return qreq; + } + + return NULL; +} + +queryresult_t *SQL_GetQueryResult (sqlserver_t *server, int queryidx, int row) { queryresult_t *qres; + queryrequest_t *qreq; - qres = server->currentresult; - if (qres && qres->request && qres->request->num == queryidx) - return qres; - - for (qres = server->persistresults; qres; qres = qres->next) - if (qres->request && qres->request->num == queryidx) + qreq = SQL_GetQueryRequest(server, queryidx); + for (qres = qreq->results; qres; qres = qres->next) + if (qres->request && qres->request->num == queryidx && row >= qres->firstrow && row < qres->firstrow + qres->rows) return qres; return NULL; @@ -533,20 +545,18 @@ static void SQL_DeallocResult(sqlserver_t *server, queryresult_t *qres) break; #endif } - if (qres->request) - Z_Free(qres->request); Z_Free(qres); } -void SQL_ClosePersistantResult(sqlserver_t *server, queryresult_t *qres) +static void SQL_CloseRequestResult(sqlserver_t *server, queryresult_t *qres) { queryresult_t *prev, *cur; - prev = server->persistresults; + prev = qres->request->results; if (prev == qres) { - server->persistresults = prev->next; + qres->request->results = prev->next; SQL_DeallocResult(server, prev); return; } @@ -562,25 +572,62 @@ void SQL_ClosePersistantResult(sqlserver_t *server, queryresult_t *qres) } } +//MT only. flush a result without discarding the request. will result in gaps. void SQL_CloseResult(sqlserver_t *server, queryresult_t *qres) { if (!qres) return; - if (qres == server->currentresult) +/* if (qres == server->currentresult) { SQL_DeallocResult(server, server->currentresult); server->currentresult = NULL; return; } +*/ // else we have a persistant query - SQL_ClosePersistantResult(server, qres); + SQL_CloseRequestResult(server, qres); } -void SQL_CloseAllResults(sqlserver_t *server) +//MT only. releases the request. +void SQL_CloseRequest(sqlserver_t *server, queryrequest_t *qreq, qboolean force) +{ + while(qreq->results) + { + SQL_CloseResult(server, qreq->results); + } + //if the worker thread is still active with it for whatever reason, flag it as aborted but keep it otherwise valid. actually close it later on when we get the results back. + if (qreq->state != SR_FINISHED && qreq->state != SR_NEW) + qreq->state = SR_ABORTED; + else + { + queryrequest_t *prev, *cur; + + //unlink and free it now that its complete. + prev = server->requests; + if (prev == qreq) + server->requests = prev->nextreq; + else + { + for (cur = prev->nextreq; cur; prev = cur, cur = prev->nextreq) + { + if (cur == qreq) + { + prev->nextreq = cur->nextreq; + break; + } + } + } + Z_Free(qreq); + } +} + +void SQL_CloseAllRequests(sqlserver_t *server) { queryresult_t *oldqres, *qres; - // close orphaned results (we assume the lock is active or non-existant at this point) + //we assume lock is either held or the thread has already died. this function isn't (worker)thread safe. + + // close pending results qres = server->results; while (qres) { @@ -588,21 +635,13 @@ void SQL_CloseAllResults(sqlserver_t *server) qres = qres->next; SQL_DeallocResult(server, oldqres); } - // close current - if (server->currentresult) + + //now terminate all the requests + while(server->requests) { - SQL_DeallocResult(server, server->currentresult); - server->currentresult = NULL; + SQL_CloseRequest(server, server->requests, true); } - // close persistant results - qres = server->persistresults; - while (qres) - { - oldqres = qres; - qres = qres->next; - SQL_DeallocResult(server, oldqres); - } - server->persistresults = NULL; + // close server result if (server->serverresult) { @@ -613,10 +652,11 @@ void SQL_CloseAllResults(sqlserver_t *server) char *SQL_ReadField (sqlserver_t *server, queryresult_t *qres, int row, int col, qboolean fields) { - if (!qres->result) // TODO: partial resultset logic not implemented yet + if (!qres->result) return NULL; else { // store_result query + row -= qres->firstrow; if (qres->rows < row || qres->columns < col || col < 0) return NULL; @@ -705,15 +745,15 @@ void SQL_CleanupServer(sqlserver_t *server) Sys_DestroyMutex(server->resultlock); // close orphaned requests - qreq = server->requests; + qreq = server->requestqueue; while (qreq) { oldqreq = qreq; - qreq = qreq->next; + qreq = qreq->nextqueue; Z_Free(oldqreq); } - SQL_CloseAllResults(server); + SQL_CloseAllRequests(server); for (i = SQL_CONNECT_STRUCTPARAMS; i < SQL_CONNECT_PARAMS; i++) Z_Free(server->connectparams[i]); @@ -833,7 +873,7 @@ int SQL_NewServer(char *driver, char **paramstr) return serverref; } -int SQL_NewQuery(sqlserver_t *server, int callfunc, int type, int self, float selfid, int other, float otherid, char *str) +int SQL_NewQuery(sqlserver_t *server, qboolean (*callback)(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof), char *str, queryrequest_t **reqout) { int qsize = Q_strlen(str); queryrequest_t *qreq; @@ -842,27 +882,32 @@ int SQL_NewQuery(sqlserver_t *server, int callfunc, int type, int self, float se qreq = (queryrequest_t *)ZF_Malloc(sizeof(queryrequest_t) + qsize); if (qreq) { - qreq->persistant = (type == 1); - qreq->callback = callfunc; - - qreq->selfent = self; - qreq->selfid = selfid; - qreq->otherent = other; - qreq->otherid = otherid; - + qreq->state = SR_NEW; querynum = qreq->num = server->querynum; // prevent the reference num from getting too big to prevent FP problems - if (++server->querynum > 1000000) - server->querynum = 1; - + while(1) + { + if (++server->querynum > (1<<21)) + server->querynum = 1; + + if (!SQL_GetQueryRequest(server, server->querynum)) + break; + } + + qreq->callback = callback; Q_strncpy(qreq->query, str, qsize); + qreq->nextreq = server->requests; + server->requests = qreq; + SQL_PushRequest(server, qreq); Sys_ConditionSignal(server->requestcondv); + *reqout = qreq; return querynum; } + *reqout = NULL; return -1; } @@ -945,6 +990,7 @@ qboolean SQL_Available(void) void SQL_Status_f(void) { int i; + char *stat; if (!SQL_Available()) Con_Printf("No SQL library available.\n"); @@ -964,7 +1010,7 @@ void SQL_Status_f(void) Sys_LockMutex(server->resultlock); Sys_LockConditional(server->requestcondv); - for (qreq = server->requests; qreq; qreq = qreq->next) + for (qreq = server->requests; qreq; qreq = qreq->nextreq) reqnum++; for (qres = server->results; qres; qres = qres->next) resnum++; @@ -988,11 +1034,21 @@ void SQL_Status_f(void) if (reqnum) { - Con_Printf ("- %i requests\n"); - for (qreq = server->requests; qreq; qreq = qreq->next) + Con_Printf ("- %i requests\n", reqnum); + for (qreq = server->requests; qreq; qreq = qreq->nextqueue) { - Con_Printf (" query #%i: %s\n", + switch (qreq->state) + { + case SR_NEW: stat = "new"; break; + case SR_PENDING: stat = "pending"; break; + case SR_PARTIAL: stat = "partial"; break; + case SR_FINISHED: stat = "finished"; break; + case SR_ABORTED: stat = "aborted"; break; + default: stat = "???"; break; + } + Con_Printf (" query #%i (%s): %s\n", qreq->num, + stat, qreq->query); // TODO: function lookup? } @@ -1000,7 +1056,7 @@ void SQL_Status_f(void) if (resnum) { - Con_Printf ("- %i results\n"); + Con_Printf ("- %i pending results\n", resnum); for (qres = server->results; qres; qres = qres->next) { Con_Printf (" * %i rows, %i columns", @@ -1047,7 +1103,7 @@ void SQL_Killall_f (void) SQL_KillServers(); } -void SQL_ServerCycle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +void SQL_ServerCycle (void) { int i; @@ -1055,69 +1111,61 @@ void SQL_ServerCycle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { sqlserver_t *server = sqlservers[i]; queryresult_t *qres; + queryrequest_t *qreq; if (!server) continue; + while (qres = SQL_PullResult(server)) + { + qreq = qres->request; + qres->next = NULL; + if (qreq && qreq->callback) + { + qboolean persist; + + //save it for later. + qres->next = qreq->results; + qreq->results = qres; + + if (qreq->state == SR_ABORTED) + { + persist = false; + if (qres->eof) + SQL_CloseRequest(server, qreq, true); + } + else + { + if (qreq->state == SR_FINISHED) + Sys_Error("SQL: Results after finished!\n"); + if (qreq->state == SR_PENDING) + qreq->state = SR_PARTIAL; + if (qres->eof) + qreq->state = SR_FINISHED; + persist = qreq->callback(qreq, qres->firstrow, qres->rows, qres->columns, qres->eof); + } + + if (!persist) + { + SQL_CloseResult(server, qres); + if (qreq->state == SR_FINISHED) + SQL_CloseRequest(server, qreq, false); + } + } + else // error or server-only result + { + if (server->serverresult) + SQL_CloseResult(server, server->serverresult); + server->serverresult = qres; + } + } + if (server->terminated) { sqlservers[i] = NULL; SQL_CleanupServer(server); continue; } - - while (qres = SQL_PullResult(server)) - { - qres->next = NULL; - if (qres->request && qres->request->callback) - { - if (server->active) - { // only process results to callback if server is active - edict_t *ent; - - server->currentresult = qres; - G_FLOAT(OFS_PARM0) = i; - G_FLOAT(OFS_PARM1) = qres->request->num; - G_FLOAT(OFS_PARM2) = qres->rows; - G_FLOAT(OFS_PARM3) = qres->columns; - G_FLOAT(OFS_PARM4) = qres->eof; - G_FLOAT(OFS_PARM5) = qres->firstrow; - - // recall self and other references - ent = PROG_TO_EDICT(prinst, qres->request->selfent); - if (ent->isfree || ent->xv->uniquespawnid != qres->request->selfid) - pr_global_struct->self = pr_global_struct->world; - else - pr_global_struct->self = qres->request->selfent; - ent = PROG_TO_EDICT(prinst, qres->request->otherent); - if (ent->isfree || ent->xv->uniquespawnid != qres->request->otherid) - pr_global_struct->other = pr_global_struct->world; - else - pr_global_struct->other = qres->request->otherent; - - PR_ExecuteProgram(prinst, qres->request->callback); - - if (server->currentresult) - { - if (server->currentresult->request && server->currentresult->request->persistant) - { - // move into persistant list - server->currentresult->next = server->persistresults; - server->persistresults = server->currentresult; - } - else // just close the query - SQL_CloseResult(server, server->currentresult); - } - } - } - else // error or server-only result - { - if (server->serverresult) - Z_Free(server->serverresult); - server->serverresult = qres; - } - } - server->currentresult = NULL; } } diff --git a/engine/server/sv_sql.h b/engine/server/sv_sql.h index 7ffbb0f2..fb8dc35f 100644 --- a/engine/server/sv_sql.h +++ b/engine/server/sv_sql.h @@ -20,14 +20,30 @@ typedef enum typedef struct queryrequest_s { - int num; /* query number reference */ - qboolean persistant; /* persistant query */ - struct queryrequest_s *next; /* next request in queue */ - int callback; /* callback function reference */ - int selfent; /* self entity on call */ - float selfid; /* self entity id on call */ - int otherent; /* other entity on call */ - float otherid; /* other entity id on call */ + int srvid; + int num; /* query number reference */ + struct queryrequest_s *nextqueue; /* next request in queue */ + struct queryrequest_s *nextreq; /* next request in queue */ + struct queryresult_s *results; /* chain of received results */ + enum + { + SR_NEW, + SR_PENDING, + SR_PARTIAL, // + SR_FINISHED, //waiting for close + SR_ABORTED //don't notify. destroy on finish. + } state; //maintained by main thread. worker *may* check for aborted state as a way to quickly generate an error. + qboolean (*callback)(struct queryrequest_s *req, int firstrow, int numrows, int numcols, qboolean eof); /* called on main thread once complete */ + struct + { + qboolean persistant; /* persistant query */ + int qccallback; /* callback function reference */ + int selfent; /* self entity on call */ + float selfid; /* self entity id on call */ + int otherent; /* other entity on call */ + float otherid; /* other entity id on call */ + void *thread; + } user; /* sql code does not write anything in this struct */ char query[1]; /* query to run */ } queryrequest_t; @@ -61,13 +77,12 @@ typedef struct sqlserver_s void *requestcondv; /* lock and conditional variable for queue read/write */ void *resultlock; /* mutex for queue read/write */ int querynum; /* next reference number for queries */ - queryrequest_t *requests; /* query requests queue */ + queryrequest_t *requests; /* list of pending and persistant requests */ + queryrequest_t *requestqueue; /* query requests queue */ queryrequest_t *requestslast; /* query requests queue last link */ queryresult_t *results; /* query results queue */ queryresult_t *resultslast; /* query results queue last link */ - queryresult_t *currentresult; /* current called result */ - queryresult_t *persistresults; /* list of persistant results */ - queryresult_t *serverresult; /* server error results */ + queryresult_t *serverresult; /* most recent (orphaned) server error result */ char **connectparams; /* connect parameters (0 = host, 1 = user, 2 = pass, 3 = defaultdb) */ } sqlserver_t; @@ -77,19 +92,21 @@ void SQL_KillServers(void); void SQL_DeInit(void); sqlserver_t *SQL_GetServer (int serveridx, qboolean inactives); -queryresult_t *SQL_GetQueryResult (sqlserver_t *server, int queryidx); +queryrequest_t *SQL_GetQueryRequest (sqlserver_t *server, int queryidx); +queryresult_t *SQL_GetQueryResult (sqlserver_t *server, int queryidx, int row); //void SQL_DeallocResult(sqlserver_t *server, queryresult_t *qres); void SQL_ClosePersistantResult(sqlserver_t *server, queryresult_t *qres); void SQL_CloseResult(sqlserver_t *server, queryresult_t *qres); +void SQL_CloseRequest(sqlserver_t *server, queryrequest_t *qres, qboolean force); void SQL_CloseAllResults(sqlserver_t *server); char *SQL_ReadField (sqlserver_t *server, queryresult_t *qres, int row, int col, qboolean fields); int SQL_NewServer(char *driver, char **paramstr); -int SQL_NewQuery(sqlserver_t *server, int callfunc, int type, int self, float selfid, int other, float otherid, char *str); +int SQL_NewQuery(sqlserver_t *server, qboolean (*callback)(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof), char *str, queryrequest_t **reqout); //callback will be called on the main thread once the result is back void SQL_Disconnect(sqlserver_t *server); void SQL_Escape(sqlserver_t *server, char *src, char *dst, int dstlen); const char *SQL_Info(sqlserver_t *server); qboolean SQL_Available(void); -void SQL_ServerCycle (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void SQL_ServerCycle (void); extern cvar_t sql_driver; extern cvar_t sql_host; diff --git a/engine/server/sv_sys_win.c b/engine/server/sv_sys_win.c index 2cc65510..45779193 100644 --- a/engine/server/sv_sys_win.c +++ b/engine/server/sv_sys_win.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "qwsvdef.h" +#include "quakedef.h" #include #include @@ -425,7 +425,7 @@ qboolean Sys_Rename (char *oldfname, char *newfname) return !rename(oldfname, newfname); } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *fname, int fsize, void *parm, void *spath), void *parm, void *spath) { HANDLE r; WIN32_FIND_DATA fd; @@ -457,13 +457,13 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const if (*fd.cFileName != '.') { Q_snprintfz(file, sizeof(file), "%s%s/", apath, fd.cFileName); - go = func(file, fd.nFileSizeLow, parm); + go = func(file, fd.nFileSizeLow, parm, spath); } } else { Q_snprintfz(file, sizeof(file), "%s%s", apath, fd.cFileName); - go = func(file, fd.nFileSizeLow, parm); + go = func(file, fd.nFileSizeLow, parm, spath); } } while(FindNextFile(r, &fd) && go); @@ -731,11 +731,15 @@ void ApplyColour(unsigned int chr) void Sys_PrintColouredChar(unsigned int chr) { + DWORD dummy; + wchar_t wc; + if (chr & CON_HIDDEN) return; ApplyColour(chr); - printf("%c", chr & CON_CHARMASK); + wc = chr & CON_CHARMASK; + WriteConsoleW(hconsoleout, &wc, 1, &dummy, NULL); } /* @@ -1003,6 +1007,9 @@ void Sys_Init (void) Cmd_AddCommand("hide", Sys_HideConsole); hconsoleout = GetStdHandle(STD_OUTPUT_HANDLE); + +// SetConsoleCP(CP_UTF8); +// SetConsoleOutputCP(CP_UTF8); } void Sys_Shutdown (void) @@ -1336,4 +1343,28 @@ void Sys_Sleep (double seconds) { Sleep(seconds * 1000); } + +/* +================ +Sys_RandomBytes +================ +*/ +#include +qboolean Sys_RandomBytes(qbyte *string, int len) +{ + HCRYPTPROV prov; + + if(!CryptAcquireContext( &prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + return false; + } + + if(!CryptGenRandom(prov, len, (BYTE *)string)) + { + CryptReleaseContext( prov, 0); + return false; + } + CryptReleaseContext(prov, 0); + return true; +} #endif diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index c7f9a453..5f74e1f7 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_user.c -- server code for moving users -#include "qwsvdef.h" +#include "quakedef.h" #ifndef CLIENTONLY #include "pr_common.h" @@ -1458,7 +1458,7 @@ void SVQW_Spawn_f (void) // normally this could overflow, but no need to check due to backbuf for (i=0, client = svs.clients ; idownload = FS_OpenVFS(name+8, "rb", FS_ROOT); } @@ -2805,6 +2806,15 @@ void SV_BeginDownload_f(void) //redirection protocol-specific code goes here. if (result == -4) { +#ifdef PEXT_CHUNKEDDOWNLOADS + if (host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) + { + //redirect the client (before the message saying download failed) + char *s = va("dlsize \"%s\" r \"%s\"\n", name, redirection); + ClientReliableWrite_Begin (host_client, svc_stufftext, 2+strlen(s)); + ClientReliableWrite_String (host_client, s); + } +#endif } if (result == 0) @@ -2830,18 +2840,11 @@ void SV_BeginDownload_f(void) break; case -4: result = -1; - error = ""; + error = "Package contents not available individually\n"; break; } - if (ISNQCLIENT(host_client)) - { - SV_PrintToClient(host_client, PRINT_HIGH, error); - - ClientReliableWrite_Begin (host_client, svc_stufftext, 2+12); - ClientReliableWrite_String (host_client, "\nstopdownload\n"); - } #ifdef PEXT_CHUNKEDDOWNLOADS - else if (host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) + if (host_client->fteprotocolextensions & PEXT_CHUNKEDDOWNLOADS) { ClientReliableWrite_Begin (host_client, svc_download, 10+strlen(name)); ClientReliableWrite_Long (host_client, -1); @@ -2850,6 +2853,14 @@ void SV_BeginDownload_f(void) } else #endif + if (ISNQCLIENT(host_client)) + { + SV_PrintToClient(host_client, PRINT_HIGH, error); + + ClientReliableWrite_Begin (host_client, svc_stufftext, 2+12); + ClientReliableWrite_String (host_client, "\nstopdownload\n"); + } + else { SV_PrintToClient(host_client, PRINT_HIGH, error); @@ -2857,15 +2868,6 @@ void SV_BeginDownload_f(void) ClientReliableWrite_Short (host_client, -1); ClientReliableWrite_Byte (host_client, 0); } - - //it errored because it was a redirection. - //ask the client to grab the alternate file instead. - if (redirection) - { - //tell the client to download the new one. - ClientReliableWrite_Begin (host_client, ISQ2CLIENT(host_client)?svcq2_stufftext:svc_stufftext, 2+strlen(redirection)); - ClientReliableWrite_String (host_client, va("\ndownload \"%s\"\n", redirection)); - } return; } @@ -4418,7 +4420,7 @@ void SVNQ_Spawn_f (void) // normally this could overflow, but no need to check due to backbuf for (i=0, client = svs.clients; iedicts) / ge->edict_size) diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index 1b9e557d..432d1208 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -1,4 +1,4 @@ -#include "qwsvdef.h" +#include "quakedef.h" //An implementation of a Q3 server... //requires qvm implementation and existing q3 client stuff (or at least the overlapping stuff in q3common.c). diff --git a/fteqtv/netchan.c b/fteqtv/netchan.c index 6fcd7217..220024e1 100644 --- a/fteqtv/netchan.c +++ b/fteqtv/netchan.c @@ -229,6 +229,7 @@ void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, net } } +#if 0 int Netchan_IsLocal (netadr_t adr) { struct sockaddr_in *sadr = (struct sockaddr_in *)&adr; @@ -267,7 +268,7 @@ int Netchan_IsLocal (netadr_t adr) return false; } } - +#endif diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index e90eb9bc..bd803deb 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -862,7 +862,7 @@ void PM_PlayerMove (pmove_t *pmove); void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport, qboolean isclient); void Netchan_OutOfBandPrint (cluster_t *cluster, netadr_t adr, char *format, ...) PRINTFWARNING(3); -int Netchan_IsLocal (netadr_t adr); +//int Netchan_IsLocal (netadr_t adr); void NET_InitUDPSocket(cluster_t *cluster, int port, qboolean ipv6); void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, netadr_t adr); SOCKET NET_ChooseSocket(SOCKET sock[], netadr_t *adr); diff --git a/fteqtv/qw.c b/fteqtv/qw.c index be68e94c..7f0f148f 100644 --- a/fteqtv/qw.c +++ b/fteqtv/qw.c @@ -2770,13 +2770,13 @@ I've removed the following from this function as it covered the menu (~Moodles): tuiadmin: if (!*cluster->adminpassword) { - if (Netchan_IsLocal(v->netchan.remote_address)) + /*if (Netchan_IsLocal(v->netchan.remote_address)) { Sys_Printf(cluster, "Local player %s logs in as admin\n", v->name); QW_SetMenu(v, MENU_ADMIN); v->isadmin = true; } - else + else*/ QW_PrintfToViewer(v, "There is no admin password set\nYou may not log in.\n"); } else if (v->isadmin) diff --git a/plugins/jabber/jabberclient.c b/plugins/jabber/jabberclient.c index 72f4140c..4f5ce7ea 100644 --- a/plugins/jabber/jabberclient.c +++ b/plugins/jabber/jabberclient.c @@ -1,16 +1,22 @@ //Released under the terms of the gpl as this file uses a bit of quake derived code. All sections of the like are marked as such #include "../plugin.h" +#include #define Q_strncpyz(o, i, l) do {strncpy(o, i, l-1);o[l-1]='\0';}while(0) -#define JCL_BUILD "1" +#define JCL_BUILD "2" -#define ARGNAMES ,sock -BUILTINR(int, Net_SetTLSClient, (qhandle_t sock)); +#define ARGNAMES ,sock,certhostname +BUILTINR(int, Net_SetTLSClient, (qhandle_t sock, const char *certhostname)); #undef ARGNAMES +void (*Con_TrySubPrint)(const char *conname, const char *message); +void Fallback_ConPrint(const char *conname, const char *message) +{ + Con_Print(message); +} void Con_SubPrintf(char *subname, char *format, ...) { @@ -21,7 +27,7 @@ void Con_SubPrintf(char *subname, char *format, ...) vsnprintf (string, sizeof(string), format,argptr); va_end (argptr); - Con_SubPrint(subname, string); + Con_TrySubPrint(subname, string); } @@ -123,7 +129,7 @@ void Con_SubPrintf(char *subname, char *format, ...) void JCL_Command(void); -int JCL_ExecuteCommand(int *args) +qintptr_t JCL_ExecuteCommand(qintptr_t *args) { char cmd[256]; Cmd_Argv(0, cmd, sizeof(cmd)); @@ -135,13 +141,11 @@ int JCL_ExecuteCommand(int *args) return false; } -int JCL_ConExecuteCommand(int *args); +qintptr_t JCL_ConExecuteCommand(qintptr_t *args); -int JCL_Frame(int *args); +qintptr_t JCL_Frame(qintptr_t *args); -int (*Con_TrySubPrint)(char *conname, char *message); - -int Plug_Init(int *args) +qintptr_t Plug_Init(qintptr_t *args) { if ( Plug_Export("Tick", JCL_Frame) && Plug_Export("ExecuteCommand", JCL_ExecuteCommand)) @@ -155,7 +159,7 @@ int Plug_Init(int *args) if (!Plug_Export("ConExecuteCommand", JCL_ConExecuteCommand)) { Con_Printf("Jabber client plugin in single-console mode\n"); - Con_TrySubPrint = Con_Print; + Con_TrySubPrint = Fallback_ConPrint; } else Con_TrySubPrint = Con_SubPrint; @@ -182,7 +186,7 @@ int Plug_Init(int *args) //but never used cos it breaks strings -#define JCL_MAXMSGLEN 2048 +#define JCL_MAXMSGLEN 10000 typedef struct { @@ -193,7 +197,9 @@ typedef struct { qhandle_t inlog; qhandle_t outlog; - char bufferedinmessage[JCL_MAXMSGLEN+1]; //there is a max size for protocol. (conveinient eh?) (and it's text format) + char bufferedinmessage[JCL_MAXMSGLEN+1]; //servers are required to be able to handle messages no shorter than a specific size. + //which means we need to be able to handle messages when they get to us. + //servers can still handle larger messages if they choose, so this might not be enough. int bufferedinammount; char defaultdest[256]; @@ -207,12 +213,16 @@ typedef struct { int openbracket; int instreampos; - qboolean noplain; - qboolean issecure; + qboolean connected; //fully on server and authed and everything. + qboolean noplain; //block plain-text password exposure + qboolean issecure; //tls enabled + + char curquakeserver[2048]; + char defaultnamespace[2048]; //should be 'jabber:client' or blank (and spammy with all the extra xmlns attribs) } jclient_t; jclient_t *jclient; -int JCL_ConExecuteCommand(int *args) +qintptr_t JCL_ConExecuteCommand(qintptr_t *args) { if (!jclient) { @@ -229,7 +239,7 @@ int JCL_ConExecuteCommand(int *args) void JCL_AddClientMessage(jclient_t *jcl, char *msg, int datalen) { Net_Send(jcl->socket, msg, datalen); //FIXME: This needs rewriting to cope with errors. - Con_Printf(COLOURYELLOW "<< %s \n",msg); + Con_SubPrintf("xmppout", COLOURYELLOW "%s \n",msg); } void JCL_AddClientMessageString(jclient_t *jcl, char *msg) { @@ -275,7 +285,7 @@ jclient_t *JCL_Connect(char *server, int defport, qboolean usesecure, char *acco if (usesecure) { - if (Net_SetTLSClient(jcl->socket)<0) + if (Net_SetTLSClient(jcl->socket, server)<0) { Net_Close(jcl->socket); free(jcl); @@ -299,7 +309,7 @@ jclient_t *JCL_Connect(char *server, int defport, qboolean usesecure, char *acco strlcpy(jcl->domain, at+1, sizeof(jcl->domain)); strlcpy(jcl->password, password, sizeof(jcl->password)); - strcpy(jcl->resource, "Quake"); + strlcpy(jcl->resource, "Quake", sizeof(jcl->password)); Con_Printf("Trying to connect\n"); JCL_AddClientMessageString(jcl, @@ -320,6 +330,8 @@ typedef struct xmlparams_s { typedef struct subtree_s { char name[64]; + char xmlns[64]; //namespace of the element + char xmlns_dflt[64]; //default namespace of children char body[2048]; xmlparams_t *params; @@ -329,7 +341,18 @@ typedef struct subtree_s { } xmltree_t; void XML_Destroy(xmltree_t *t); -xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronly) + +char *XML_ParameterOfTree(xmltree_t *t, char *paramname) +{ + xmlparams_t *p; + for (p = t->params; p; p = p->next) + if (!strcmp(p->name, paramname)) + return p->val; + return NULL; +} + +//fixme: we should accept+parse the default namespace +xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronly, char *defaultnamespace) { xmlparams_t *p; xmltree_t *child; @@ -338,6 +361,7 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl int pos; char *tagend; char *tagstart; + char *ns; pos = *startpos; while (buffer[pos] >= '\0' && buffer[pos] <= ' ') { @@ -346,6 +370,12 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl pos++; } + if (pos == maxpos) + { + *startpos = pos; + return NULL; //nothing anyway. + } + //expect a < if (buffer[pos] != '<') @@ -384,9 +414,23 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl ret = malloc(sizeof(xmltree_t)); memset(ret, 0, sizeof(*ret)); - strlcpy(ret->name, com_token, sizeof(ret->name)); - // FIXME:parse the parameters + ns = strchr(com_token, ':'); + if (ns) + { + *ns = 0; + ns++; + + memcpy(ret->xmlns, "xmlns:", 6); + strlcpy(ret->xmlns+6, com_token, sizeof(ret->xmlns)-6); + strlcpy(ret->name, ns, sizeof(ret->name)); + } + else + { + strlcpy(ret->xmlns, "xmlns", sizeof(ret->xmlns)); + strlcpy(ret->name, com_token, sizeof(ret->name)); + } + while(*tagstart) { int nlen; @@ -463,6 +507,12 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl ret->params = p; } + ns = XML_ParameterOfTree(ret, ret->xmlns); + strlcpy(ret->xmlns, ns?ns:"", sizeof(ret->xmlns)); + + ns = XML_ParameterOfTree(ret, "xmlns"); + strlcpy(ret->xmlns_dflt, ns?ns:defaultnamespace, sizeof(ret->xmlns_dflt)); + tagend[-1] = '>'; if (tagend[-2] == '/') @@ -516,7 +566,7 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl break; } - child = XML_Parse(buffer, &pos, maxpos, false); + child = XML_Parse(buffer, &pos, maxpos, false, ret->xmlns_dflt); if (!child) { Con_Printf("Child block is unparsable\n"); @@ -526,8 +576,12 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl child->sibling = ret->child; ret->child = child; } - else - ret->body[bodypos++] = buffer[pos++]; + else + { + char c = buffer[pos++]; + if (bodypos < sizeof(ret->body)-1) + ret->body[bodypos++] = c; + } } ret->body[bodypos++] = '\0'; @@ -536,15 +590,6 @@ xmltree_t *XML_Parse(char *buffer, int *startpos, int maxpos, qboolean headeronl return ret; } -char *XML_ParameterOfTree(xmltree_t *t, char *paramname) -{ - xmlparams_t *p; - for (p = t->params; p; p = p->next) - if (!strcmp(p->name, paramname)) - return p->val; - return NULL; -} - void XML_Destroy(xmltree_t *t) { xmlparams_t *p, *np; @@ -631,7 +676,7 @@ void Base64_Byte(unsigned int byt) base64[base64_len++] = Base64_From64((base64_cur>>6)&63); base64[base64_len++] = Base64_From64((base64_cur>>0)&63); base64[base64_len] = '\0'; - Con_Printf("base64: %s\n", base64+base64_len-4); +// Con_Printf("base64: %s\n", base64+base64_len-4); base64_bits = 0; base64_cur = 0; } @@ -714,26 +759,23 @@ int JCL_ClientFrame(jclient_t *jcl) ret = Net_Recv(jcl->socket, jcl->bufferedinmessage+jcl->bufferedinammount, sizeof(jcl->bufferedinmessage)-1 - jcl->bufferedinammount); if (ret == 0) { - Con_Printf("JCL: Remote host disconnected\n"); - return JCL_KILL; + if (!jcl->bufferedinammount) //if we are half way through a message, read any possible conjunctions. + return JCL_DONE; //remove } if (ret < 0) { - if (ret == N_WOULDBLOCK) - { - if (!jcl->bufferedinammount) //if we are half way through a message, read any possible conjunctions. - return JCL_DONE; //remove - } - else - { - Con_Printf("JCL: socket error\n"); - return JCL_KILL; - } + Con_Printf("JCL: socket error\n"); + return JCL_KILL; } if (ret>0) + { jcl->bufferedinammount+=ret; + jcl->bufferedinmessage[jcl->bufferedinammount] = 0; + Con_TrySubPrint("xmppin", jcl->bufferedinmessage+jcl->bufferedinammount-ret); + } + olddepth = jcl->tagdepth; //we never end parsing in the middle of a < > @@ -771,11 +813,11 @@ int JCL_ClientFrame(jclient_t *jcl) { //first bit of info pos = 0; - tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, true); + tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, true, ""); while (tree && !strcmp(tree->name, "?xml")) { XML_Destroy(tree); - tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, true); + tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, true, ""); } if (!tree) @@ -783,17 +825,19 @@ int JCL_ClientFrame(jclient_t *jcl) Con_Printf("Not an xml stream\n"); return JCL_KILL; } - if (strcmp(tree->name, "stream:stream")) + if (strcmp(tree->name, "stream") || strcmp(tree->xmlns, "http://etherx.jabber.org/streams")) { Con_Printf("Not an xmpp stream\n"); return JCL_KILL; } + strlcpy(jcl->defaultnamespace, tree->xmlns_dflt, sizeof(jcl->defaultnamespace)); ot = tree; tree = tree->child; ot->child = NULL; - Con_Printf("Discard\n"); - XML_ConPrintTree(ot, 0); + +// Con_Printf("Discard\n"); +// XML_ConPrintTree(ot, 0); XML_Destroy(ot); if (!tree) @@ -818,7 +862,7 @@ int JCL_ClientFrame(jclient_t *jcl) } pos = 0; - tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, false); + tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, false, jcl->defaultnamespace); if (!tree) { @@ -827,12 +871,12 @@ int JCL_ClientFrame(jclient_t *jcl) } } - Con_Printf("read\n"); - XML_ConPrintTree(tree, 0); +// Con_Printf("read\n"); +// XML_ConPrintTree(tree, 0); unparsable = true; - if (!strcmp(tree->name, "stream:features")) + if (!strcmp(tree->name, "features")) { if ((ot=XML_ChildOfTree(tree, "bind", 0))) { @@ -846,6 +890,9 @@ int JCL_ClientFrame(jclient_t *jcl) unparsable = false; JCL_AddClientMessageString(jcl, ""); JCL_AddClientMessageString(jcl, ""); + jcl->connected = true; + + JCL_AddClientMessageString(jcl, ""); } @@ -853,6 +900,7 @@ int JCL_ClientFrame(jclient_t *jcl) { if ((!jclient->issecure) && BUILTINISVALID(Net_SetTLSClient) && XML_ChildOfTree(tree, "starttls", 0) != NULL) { + Con_Printf("Attempting to switch to TLS\n"); JCL_AddClientMessageString(jcl, ""); unparsable = false; } @@ -862,24 +910,28 @@ int JCL_ClientFrame(jclient_t *jcl) { if (!strcmp(ot->body, "PLAIN")) { + char msg[2048]; if (jclient->noplain && !jclient->issecure) //probably don't send plain without tls. { //plain can still be read with man-in-the-middle attacks, of course, even with stl. Con_Printf("Ignoring auth \'%s\'\n", ot->body); continue; } - Con_Printf("Authing with \'%s\'\n", ot->body); - JCL_AddClientMessageString(jcl, ""); - Base64_Add(jclient->username, strlen(jcl->username)); - Base64_Add("@", 1); - Base64_Add(jclient->domain, strlen(jcl->domain)); + Con_Printf("Authing with \'%s\'%s\n", ot->body, jclient->issecure?" over tls/ssl":""); + +// Base64_Add(jclient->username, strlen(jcl->username)); +// Base64_Add("@", 1); +// Base64_Add(jclient->domain, strlen(jcl->domain)); Base64_Add("", 1); Base64_Add(jclient->username, strlen(jcl->username)); Base64_Add("", 1); Base64_Add(jcl->password, strlen(jcl->password)); Base64_Finish(); - JCL_AddClientMessageString(jcl, base64); - JCL_AddClientMessageString(jcl, ""); + snprintf(msg, sizeof(msg), "%s", base64); + JCL_AddClientMessageString(jcl, msg); +// JCL_AddClientMessageString(jcl, ""); +// JCL_AddClientMessageString(jcl, base64); +// JCL_AddClientMessageString(jcl, ""); unparsable = false; break; } @@ -911,12 +963,14 @@ int JCL_ClientFrame(jclient_t *jcl) if (!BUILTINISVALID(Net_SetTLSClient)) { Con_Printf("JCL: proceed without TLS\n"); + XML_Destroy(tree); return JCL_KILL; } - if (Net_SetTLSClient(jcl->socket)<0) + if (Net_SetTLSClient(jcl->socket, jcl->domain)<0) { Con_Printf("JCL: failed to switch to TLS\n"); + XML_Destroy(tree); return JCL_KILL; } jclient->issecure = true; @@ -927,6 +981,7 @@ int JCL_ClientFrame(jclient_t *jcl) JCL_AddClientMessageString(jcl, jcl->domain); JCL_AddClientMessageString(jcl, "' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>"); + XML_Destroy(tree); return JCL_DONE; } else if (!strcmp(tree->name, "stream:error")) @@ -938,6 +993,7 @@ int JCL_ClientFrame(jclient_t *jcl) Con_Printf("JCL: Failure: %s\n", tree->child->name); else Con_Printf("JCL: Unknown failure\n"); + XML_Destroy(tree); return JCL_KILL; } else if (!strcmp(tree->name, "success")) @@ -960,7 +1016,6 @@ int JCL_ClientFrame(jclient_t *jcl) char *from; char *to; char *id; - unparsable = false; id = XML_ParameterOfTree(tree, "id"); from = XML_ParameterOfTree(tree, "from"); @@ -972,55 +1027,213 @@ int JCL_ClientFrame(jclient_t *jcl) ot = XML_ChildOfTree(tree, "query", 0); if (ot) { - f = XML_ParameterOfTree(tree, "xmlns"); - if (f && to && from && !strcmp(f, "jabber:iq:version")) - { //client->client version request - JCL_AddClientMessageString(jcl, ""); + if (from && !strcmp(ot->xmlns, "http://jabber.org/protocol/disco#info")) + { //http://xmpp.org/extensions/xep-0030.html + char msg[2048]; + int idletime = 0; + unparsable = false; - JCL_AddClientMessageString(jcl, "" - "FTEQW Jabber Plugin" - ""JCL_BUILD"" -#ifdef Q3_VM - "QVM plugin" -#endif - ""); - - JCL_AddClientMessageString(jcl, ""); + snprintf(msg, sizeof(msg), + "" + "" + "" + "" +#ifndef Q3_VM + "" +#endif + "" + "", from, id, idletime); + + JCL_AddClientMessageString(jcl, msg); } + else if (from && !strcmp(ot->xmlns, "jabber:iq:version")) + { //client->client version request + char msg[2048]; + unparsable = false; + + snprintf(msg, sizeof(msg), + "" + "" + "FTEQW Jabber Plugin" + "V"JCL_BUILD"" +#ifdef Q3_VM + "QVM plugin" +#endif + "" + "", from, id); + + JCL_AddClientMessageString(jcl, msg); + } +/* else if (from && !strcmp(ot->xmlns, "jabber:iq:last")) + { //http://xmpp.org/extensions/xep-0012.html + char msg[2048]; + int idletime = 0; + unparsable = false; + + //last activity + snprintf(msg, sizeof(msg), + "" + "" + "", from, id, idletime); + + JCL_AddClientMessageString(jcl, msg); + } +*/ + } +#ifndef Q3_VM + ot = XML_ChildOfTree(tree, "time", 0); + if (ot && !strcmp(ot->xmlns, "urn:xmpp:time")) + { //http://xmpp.org/extensions/xep-0202.html + char msg[2048]; + char tz[256]; + char timestamp[256]; + int idletime = 0; + struct tm * timeinfo; + int tzs; + time_t rawtime; + time (&rawtime); + timeinfo = gmtime (&rawtime); + tzs = _timezone; + tzs *= -1; + snprintf(tz, sizeof(tz), "%+i:%i", tzs/(60*60), abs(tzs/60) % 60); + strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%SZ", timeinfo); + unparsable = false; + //strftime + snprintf(msg, sizeof(msg), + "" + "" + "", from, id, tz, timestamp); + JCL_AddClientMessageString(jcl, msg); + } +#endif + + if (unparsable) + { //unsupported stuff + char msg[2048]; + unparsable = false; + + Con_Print("Unsupported iq get\n"); + XML_ConPrintTree(tree, 0); + + //tell them OH NOES, instead of requiring some timeout. + snprintf(msg, sizeof(msg), + "" + "" + "" + "" + "", from, id); + JCL_AddClientMessageString(jcl, msg); } } - else + else if (f && !strcmp(f, "result")) + { + xmltree_t *c, *v; + unparsable = false; + c = XML_ChildOfTree(tree, "bind", 0); + if (c) + { + v = XML_ChildOfTree(c, "jid", 0); + if (v) + Con_Printf("Bound to jid \"%s\"\n", v->body); + } + else + { + Con_Print("Unrecognised iq result\n"); + XML_ConPrintTree(tree, 0); + } + } + + if (unparsable) + { + unparsable = false; Con_Print("Unrecognised iq type\n"); + XML_ConPrintTree(tree, 0); + } } else if (!strcmp(tree->name, "message")) { - unparsable = false; + f = XML_ParameterOfTree(tree, "from"); + + if (f) + { + strlcpy(jcl->defaultdest, f, sizeof(jcl->defaultdest)); + RenameConsole(f); + } + + if (f) + { + ot = XML_ChildOfTree(tree, "composing", 0); + if (ot && !strcmp(ot->xmlns, "http://jabber.org/protocol/chatstates")) + { + unparsable = false; + Con_SubPrintf(f, "%s is typing\r", f); + } + ot = XML_ChildOfTree(tree, "paused", 0); + if (ot && !strcmp(ot->xmlns, "http://jabber.org/protocol/chatstates")) + { + unparsable = false; + Con_SubPrintf(f, "%s has stopped typing\r", f); + } + ot = XML_ChildOfTree(tree, "inactive", 0); + if (ot && !strcmp(ot->xmlns, "http://jabber.org/protocol/chatstates")) + { + unparsable = false; + Con_SubPrintf(f, "%s has become inactive\r", f); + } + ot = XML_ChildOfTree(tree, "active", 0); + if (ot && !strcmp(ot->xmlns, "http://jabber.org/protocol/chatstates")) + { + unparsable = false; + Con_SubPrintf(f, "\r", f); + } + ot = XML_ChildOfTree(tree, "gone", 0); + if (ot && !strcmp(ot->xmlns, "http://jabber.org/protocol/chatstates")) + { + unparsable = false; + Con_SubPrintf(f, "%s has gone away\r", f); + } + } + ot = XML_ChildOfTree(tree, "body", 0); if (ot) { - f = XML_ParameterOfTree(tree, "from"); + unparsable = false; if (f) - { - strlcpy(jcl->defaultdest, f, sizeof(jcl->defaultdest)); - RenameConsole(f); Con_SubPrintf(f, "%s: %s\n", f, ot->body); - } else Con_Print(ot->body); LocalSound("misc/talk.wav"); } - else + + if (unparsable) + { + unparsable = false; Con_Print("Received a message without a body\n"); + XML_ConPrintTree(tree, 0); + } } else if (!strcmp(tree->name, "presence")) { + char *from = XML_ParameterOfTree(tree, "from"); + xmltree_t *show = XML_ChildOfTree(tree, "show", 0); + xmltree_t *status = XML_ChildOfTree(tree, "status", 0); + xmltree_t *quake = XML_ChildOfTree(tree, "quake", 0); + xmltree_t *serverip = NULL; + + if (quake && !strcmp(quake->xmlns, "fteqw.com:game")) + serverip = XML_ChildOfTree(quake, "serverip", 0); + + if (serverip && *serverip->body) + Con_Printf("%s is now playing quake! ^[JOIN THEM!\\join\\%s^]\n", from, serverip->body); + else if (status && *status->body) + Con_Printf("%s is now %s: %s\n", from, show?show->body:"present", status->body); + else + Con_Printf("%s is now %s\n", from, show?show->body:"present"); + //we should keep a list of the people that we know of. unparsable = false; } @@ -1054,11 +1267,40 @@ void JCL_CloseConnection(jclient_t *jcl) //functions above this line allow connections to multiple servers. //it is just the control functions that only allow one server. -int JCL_Frame(int *args) +qintptr_t JCL_Frame(qintptr_t *args) { int stat = JCL_CONTINUE; if (jclient) { + if (jclient->connected) + { + int dummystat; + char serveraddr[1024*16]; + //get the last server address + if (!Cvar_GetString("cl_serveraddress", serveraddr, sizeof(serveraddr))) + serveraddr[0] = 0; + //if we can't get any stats, its because we're not actually on the server. + if (!CL_GetStats(0, &dummystat, 1)) + serveraddr[0] = 0; + + if (strcmp(jclient->curquakeserver, serveraddr)) + { + char msg[1024]; + strlcpy(jclient->curquakeserver, serveraddr, sizeof(jclient->curquakeserver)); + if (!*jclient->curquakeserver) + strlcpy(msg, "", sizeof(msg)); + else + snprintf(msg, sizeof(msg), + "" + "" + "sha1-hash-of-image" + "" + "" + ); + JCL_AddClientMessageString(jclient, msg); + } + } + while(stat == JCL_CONTINUE) stat = JCL_ClientFrame(jclient); if (stat == JCL_KILL) @@ -1163,6 +1405,10 @@ void JCL_Command(void) Con_SubPrintf(jclient->defaultdest, "%s: "COLOURYELLOW"%s\n", ">>", msg); } + else if (!strcmp(arg[0]+1, "raw")) + { + JCL_AddClientMessageString(jclient, arg[1]); + } else Con_Printf("Unrecognised command: %s\n", arg[0]); } diff --git a/plugins/plugin.c b/plugins/plugin.c index f78817dc..fa110734 100644 --- a/plugins/plugin.c +++ b/plugins/plugin.c @@ -55,7 +55,7 @@ BUILTIN(void, Con_Print, (const char *text)); //on to main console. #undef ARGNAMES #define ARGNAMES ,conname,text -BUILTIN(void, Con_SubPrint, (char *conname, char *text)); //on to named sub console (creating it too). +BUILTIN(void, Con_SubPrint, (const char *conname, const char *text)); //on to named sub console (creating it too). #undef ARGNAMES #define ARGNAMES ,old,new BUILTIN(void, Con_RenameSub, (char *old, char *new)); //rename a subconsole @@ -120,7 +120,7 @@ BUILTINR(int, Cvar_Update, (qhandle_t handle, int *modificationcount, char *stri #undef ARGNAMES #define ARGNAMES ,pnum,stats,maxstats -BUILTIN(void, CL_GetStats, (int pnum, unsigned int *stats, int maxstats)); +BUILTINR(int, CL_GetStats, (int pnum, unsigned int *stats, int maxstats)); #undef ARGNAMES #define ARGNAMES ,pnum,info BUILTINR(int, GetPlayerInfo, (int pnum, plugclientinfo_t *info)); diff --git a/plugins/plugin.h b/plugins/plugin.h index aca81aef..47425c12 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -6,6 +6,9 @@ typedef int qintptr_t; typedef unsigned int quintptr_t; +typedef unsigned int size_t; +typedef signed int ssize_t; + #define TESTBI 1 #ifdef TESTBI # define EBUILTIN(t, n, args) extern t (*n) args @@ -139,7 +142,7 @@ EBUILTIN(qboolean, Plug_ExportNative, (const char *funcname, void *func)); //set #endif EBUILTIN(void, Con_Print, (const char *text)); //on to main console. -EBUILTIN(void, Con_SubPrint, (char *subname, char *text)); //on to sub console. +EBUILTIN(void, Con_SubPrint, (const char *subname, const char *text)); //on to sub console. EBUILTIN(void, Con_RenameSub, (char *oldname, char *newname)); //rename a console. EBUILTIN(int, Con_IsActive, (char *conname)); EBUILTIN(void, Con_SetActive, (char *conname)); @@ -165,7 +168,7 @@ EBUILTIN(int, Cvar_Update, (qhandle_t handle, int *modificationcount, char *stri EBUILTIN(void, GetPluginName, (int plugnum, char *buffer, int bufsize)); EBUILTIN(void, LocalSound, (char *soundname)); -EBUILTIN(void, CL_GetStats, (int pnum, unsigned int *stats, int maxstats)); +EBUILTIN(int, CL_GetStats, (int pnum, unsigned int *stats, int maxstats)); EBUILTIN(int, GetPlayerInfo, (int pnum, plugclientinfo_t *info)); EBUILTIN(int, LocalPlayerNumber, (void)); diff --git a/plugins/qvm_api.c b/plugins/qvm_api.c index 66a0e25b..654e2edf 100644 --- a/plugins/qvm_api.c +++ b/plugins/qvm_api.c @@ -57,7 +57,7 @@ retry: precision=precision*10+*format-'0'; goto retry; case '%': /*emit a %*/ - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = *format; break; @@ -69,7 +69,7 @@ retry: { while (*string && precision--) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = *string++; } @@ -78,7 +78,7 @@ retry: { while (*string) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = *string++; } @@ -87,7 +87,7 @@ retry: break; case 'c': _int = va_arg(vargs, int); - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = _int; tokens++; @@ -96,7 +96,7 @@ retry: _int = va_arg(vargs, int); if (_int < 0) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = '-'; _int *= -1; @@ -134,7 +134,7 @@ retry: while (*string) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = *string++; } @@ -178,7 +178,7 @@ Con_Printf("%i bytes left\n", maxlen); */ if (_int < 0) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = '-'; _int *= -1; @@ -211,7 +211,7 @@ Con_Printf("%i bytes left\n", maxlen); */ while(precision>0) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} if (use0s) *buffer++ = '0'; @@ -222,7 +222,7 @@ Con_Printf("%i bytes left\n", maxlen); while (*string) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = *string++; } @@ -235,7 +235,7 @@ Con_Printf("%i bytes left\n", maxlen); _int = (int)_float; if (_int < 0) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = '-'; _int *= -1; @@ -257,7 +257,7 @@ Con_Printf("%i bytes left\n", maxlen); string = tempbuffer+i+1; while (*string) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = *string++; } @@ -287,7 +287,7 @@ Con_Printf("%i bytes left\n", maxlen); string = tempbuffer; while (*string) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = *string++; } @@ -298,7 +298,7 @@ Con_Printf("%i bytes left\n", maxlen); string = "ERROR IN FORMAT"; while (*string) { - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = *string++; } @@ -306,7 +306,7 @@ Con_Printf("%i bytes left\n", maxlen); } break; default: - if (--maxlen < 0) + if (maxlen-- == 0) {*buffer++='\0';return tokens;} *buffer++ = *format; break;