diff --git a/code/null/null_client.c b/code/null/null_client.c index 1cf97730..4c767182 100644 --- a/code/null/null_client.c +++ b/code/null/null_client.c @@ -27,7 +27,7 @@ clientStatic_t cls; clientActive_t cl; clientGameExport_t *cge; -void CL_Shutdown( void ) { +void CL_Shutdown(const char* finalmsg, qboolean disconnect, qboolean quit) { } void CL_Init( void ) { diff --git a/code/null/null_input.c b/code/null/null_input.c index 02c6e09b..9ebadebc 100644 --- a/code/null/null_input.c +++ b/code/null/null_input.c @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA static cvar_t in_mouse_real; cvar_t* in_mouse = NULL; -void IN_Init() { +void IN_Init(void *windowsData) { memset(&in_mouse_real, 0, sizeof(in_mouse_real)); in_mouse_real.integer = 0; in_mouse = &in_mouse_real; diff --git a/code/null/null_snddma.c b/code/null/null_snddma.c index da6e1e1e..28cfb1ec 100644 --- a/code/null/null_snddma.c +++ b/code/null/null_snddma.c @@ -50,12 +50,12 @@ void SNDDMA_Submit(void) void SNDDMA_Activate(void) { } -sfxHandle_t S_RegisterSound( const char *sample, qboolean compressed, qboolean force_load ) +sfxHandle_t S_RegisterSound( const char *sample, qboolean compressed ) { return 0; } -void S_StartLocalSound( const char *sound_name, qboolean force_load ) { +void S_StartLocalSound( sfxHandle_t sfx, int channelNum ) { } void S_ClearSoundBuffer( void ) { diff --git a/code/qcommon/cm_patch.c b/code/qcommon/cm_patch.c index 9d48d0af..ef4e31e6 100644 --- a/code/qcommon/cm_patch.c +++ b/code/qcommon/cm_patch.c @@ -1134,7 +1134,7 @@ static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) { pf->facets = Hunk_Alloc(numFacets * sizeof(*pf->facets), h_dontcare); Com_Memcpy(pf->facets, facets, numFacets * sizeof(*pf->facets)); pf->planes = Hunk_Alloc(numPlanes * sizeof(*pf->planes), h_dontcare); - Com_Memcpy(pf->planes, planes, numPlanes * sizeof(*pf->planes), h_dontcare); + Com_Memcpy(pf->planes, planes, numPlanes * sizeof(*pf->planes)); } diff --git a/code/qcommon/common.cpp b/code/qcommon/common.cpp index 3bfe8809..f0c9c3d4 100644 --- a/code/qcommon/common.cpp +++ b/code/qcommon/common.cpp @@ -366,7 +366,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { FS_PureServerSetLoadedPaks("", ""); longjmp (abortframe, -1); } else { - CL_Shutdown (); + CL_Shutdown (va("Client fatal crashed: %s", com_errorMessage), qtrue, qtrue); SV_Shutdown (va("Server fatal crashed: %s", com_errorMessage)); } @@ -381,14 +381,21 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { Com_Quit_f Both client and server can use this, and it will -do the apropriate things. +do the appropriate things. ============= */ void Com_Quit_f( void ) { // don't try to shutdown if we are in a recursive error + char *p = Cmd_Args( ); if ( !com_errorEntered ) { - SV_Shutdown ("Server quit"); - CL_Shutdown (); + // Some VMs might execute "quit" command directly, + // which would trigger an unload of active VM error. + // Sys_Quit will kill this process anyways, so + // a corrupt call stack makes no difference + VM_Forced_Unload_Start(); + SV_Shutdown(p[0] ? p : "Server quit"); + CL_Shutdown(p[0] ? p : "Client quit", qtrue, qtrue); + VM_Forced_Unload_Done(); Com_Shutdown (); FS_Shutdown(qtrue); } diff --git a/code/qcommon/memory.c b/code/qcommon/memory.c index a6665f4c..69edddfd 100644 --- a/code/qcommon/memory.c +++ b/code/qcommon/memory.c @@ -151,7 +151,7 @@ void Z_FreeTags( int tag ) Z_TagMalloc ======================== */ -void *Z_TagMalloc( size_t size, int tag ) +void *Z_TagMalloc( int size, int tag ) { memblock_t *block; @@ -497,7 +497,7 @@ void Com_TouchMemory( void ) { Z_Malloc ======================== */ -void *Z_Malloc( size_t size ) { +void *Z_Malloc( int size ) { void *ptr; ptr = Z_TagMalloc( size, TAG_GENERAL ); diff --git a/code/qcommon/net_chan.c b/code/qcommon/net_chan.c index b60be8df..78969782 100644 --- a/code/qcommon/net_chan.c +++ b/code/qcommon/net_chan.c @@ -689,49 +689,66 @@ NET_StringToAdr Traps "localhost" for loopback, passes everything else to system ============= */ -qboolean NET_StringToAdr( const char *s, netadr_t *a ) { - qboolean r; - char base[MAX_STRING_CHARS]; - char *port; +int NET_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ) +{ + char base[MAX_STRING_CHARS], *search; + char *port = NULL; if (!strcmp (s, "localhost")) { Com_Memset (a, 0, sizeof(*a)); a->type = NA_LOOPBACK; - /*// wombat: localhost resolves to 0.0.0.0 ? - a->ip[0] = 127; - a->ip[1] = 0; - a->ip[2] = 0; - a->ip[3] = 1;*/ - return qtrue; +// as NA_LOOPBACK doesn't require ports report port was given. + return 1; } - // look for a port number Q_strncpyz( base, s, sizeof( base ) ); - port = strstr( base, ":" ); - if ( port ) { - *port = 0; - port++; + + if(*base == '[' || Q_CountChar(base, ':') > 1) + { + // This is an ipv6 address, handle it specially. + search = strchr(base, ']'); + if(search) + { + *search = '\0'; + search++; + + if(*search == ':') + port = search + 1; + } + + if(*base == '[') + search = base + 1; + else + search = base; + } + else + { + // look for a port number + port = strchr( base, ':' ); + + if ( port ) { + *port = '\0'; + port++; + } + + search = base; } - r = Sys_StringToAdr( base, a ); - - if ( !r ) { + if(!Sys_StringToAdr(search, a, family)) + { a->type = NA_BAD; - return qfalse; + return 0; } - // inet_addr returns this if out of range - if ( a->ip[0] == 255 && a->ip[1] == 255 && a->ip[2] == 255 && a->ip[3] == 255 ) { - a->type = NA_BAD; - return qfalse; + if(port) + { + a->port = BigShort((short) atoi(port)); + return 1; } - - if ( port ) { - a->port = BigShort( (short)atoi( port ) ); - } else { - a->port = BigShort( PORT_SERVER ); + else + { + a->port = BigShort(PORT_SERVER); + return 2; } - - return qtrue; } diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index b9405ee7..15201c88 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -144,6 +144,22 @@ extern "C" { #endif #endif +#ifdef __GNUC__ +#define UNUSED_VAR __attribute__((unused)) +#else +#define UNUSED_VAR +#endif + +#if (defined _MSC_VER) +#define Q_EXPORT __declspec(dllexport) +#elif (defined __SUNPRO_C) +#define Q_EXPORT __global +#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun)) +#define Q_EXPORT __attribute__((visibility("default"))) +#else +#define Q_EXPORT +#endif + /********************************************************************** VM Considerations diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 6273c60d..49a090b9 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -914,7 +914,7 @@ void Com_BeginRedirect (char *buffer, int buffersize, void (*flush)(char *)); void Com_EndRedirect( void ); void QDECL Com_Printf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2))); void QDECL Com_DPrintf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2))); -void QDECL Com_Error( int level, const char *fmt, ... ) __attribute__ ((format (printf, 2, 3))); +void QDECL Com_Error( int code, const char *fmt, ... ) __attribute__ ((noreturn, format(printf, 2, 3))); void Com_Quit_f( void ); int Com_Milliseconds( void ); // will be journaled properly @@ -1089,7 +1089,7 @@ void CL_InitKeyCommands( void ); void CL_Init( void ); void CL_Disconnect( qboolean showMainMenu ); -void CL_Shutdown( void ); +void CL_Shutdown(const char *finalmsg, qboolean disconnect, qboolean quit); void CL_SetFrameNumber(int frameNumber); void CL_Frame( int msec ); qboolean CL_GameCommand( void ); @@ -1259,10 +1259,11 @@ cpuFeatures_t Sys_GetProcessorFeatures( void ); void Sys_SetErrorText( const char *text ); -void Sys_SendPacket( size_t length, const void *data, netadr_t to ); +void Sys_SendPacket( int length, const void *data, netadr_t to ); + +qboolean Sys_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ); qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ); -qboolean Sys_StringToAdr( const char *s, netadr_t *a ); //Does NOT parse port numbers, only base addresses. qboolean Sys_IsLANAddress (netadr_t adr); diff --git a/code/server/server.h b/code/server/server.h index ae59be3e..afc17094 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -164,7 +164,8 @@ typedef struct client_s { int deltaMessage; // frame last client usercmd message int nextReliableTime; // svs.time when another reliable command will be allowed int lastPacketTime; // svs.time when packet was last received - int lastConnectTime; // svs.time when connection started + int lastConnectTime; // svs.time when connection started + int lastSnapshotTime; // svs.time of last sent snapshot int nextSnapshotTime; // send another snapshot when svs.time >= nextSnapshotTime qboolean rateDelayed; // true if nextSnapshotTime was set based on rate instead of snapshotMsec int timeoutCount; // must timeout a few frames in a row so debugging doesn't break diff --git a/code/server/sv_snapshot.c b/code/server/sv_snapshot.c index acc3f87c..6f2823ae 100644 --- a/code/server/sv_snapshot.c +++ b/code/server/sv_snapshot.c @@ -568,39 +568,6 @@ static void SV_BuildClientSnapshot( client_t *client ) { } } - -/* -==================== -SV_RateMsec - -Return the number of msec a given size message is supposed -to take to clear, based on the current rate -==================== -*/ -#define HEADER_RATE_BYTES 48 // include our header, IP header, and some overhead -static int SV_RateMsec( client_t *client, size_t messageSize ) { - int rate; - int rateMsec; - - // individual messages will never be larger than fragment size - if ( messageSize > 1500 ) { - messageSize = 1500; - } - rate = client->rate; - if ( sv_maxRate->integer ) { - if ( sv_maxRate->integer < 1000 ) { - Cvar_Set( "sv_MaxRate", "1000" ); - } - if ( sv_maxRate->integer < rate ) { - rate = sv_maxRate->integer; - } - } - - rateMsec = ( int )( messageSize + HEADER_RATE_BYTES ) * 1000 / rate * com_timescale->value; - - return rateMsec; -} - /* ======================= SV_SendMessageToClient @@ -609,47 +576,13 @@ Called by SV_SendClientSnapshot and SV_SendClientGameState ======================= */ void SV_SendMessageToClient( msg_t *msg, client_t *client ) { - int rateMsec; - // record information about the message client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg->cursize; client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = svs.time; client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageAcked = -1; // send the datagram - SV_Netchan_Transmit( client, msg ); //msg->cursize, msg->data ); - - // set nextSnapshotTime based on rate and requested number of updates - - // local clients get snapshots every server frame - // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491 - // added sv_lanForceRate check - if ( client->netchan.remoteAddress.type == NA_LOOPBACK || (sv_lanForceRate->integer && Sys_IsLANAddress (client->netchan.remoteAddress)) ) { - client->nextSnapshotTime = svs.time + (1000.0 / sv_fps->integer * com_timescale->value); - return; - } - - // normal rate / snapshotMsec calculation - rateMsec = SV_RateMsec(client, msg->cursize); - - if ( rateMsec < client->snapshotMsec * com_timescale->value) { - // never send more packets than this, no matter what the rate is at - rateMsec = client->snapshotMsec * com_timescale->value; - client->rateDelayed = qfalse; - } else { - client->rateDelayed = qtrue; - } - - client->nextSnapshotTime = svs.time + rateMsec * com_timescale->value; - - // don't pile up empty snapshots while connecting - if ( client->state != CS_ACTIVE ) { - // a gigantic connection message may have already put the nextSnapshotTime - // more than a second away, so don't shorten it - // do shorten if client is downloading - if (!*client->downloadName && client->nextSnapshotTime < svs.time + 1000 * com_timescale->value) - client->nextSnapshotTime = svs.time + 1000 * com_timescale->value; - } + SV_Netchan_Transmit(client, msg); } @@ -729,17 +662,31 @@ void SV_SendClientMessages( void ) { continue; // not time yet } - // send additional message fragments if the last message - // was too large to send at once - if ( c->netchan.unsentFragments ) { - c->nextSnapshotTime = svs.time + - SV_RateMsec( c, c->netchan.unsentLength - c->netchan.unsentFragmentStart ); - SV_Netchan_TransmitNextFragment( c ); - continue; + if(*c->downloadName) + continue; // Client is downloading, don't send snapshots + + if(c->netchan.unsentFragments || c->netchan_start_queue) + { + c->rateDelayed = qtrue; + continue; // Drop this snapshot if the packet queue is still full or delta compression will break + } + + if(!(c->netchan.remoteAddress.type == NA_LOOPBACK || + (sv_lanForceRate->integer && Sys_IsLANAddress(c->netchan.remoteAddress)))) + { + // rate control for clients not on LAN + if(SV_RateMsec(c) > 0) + { + // Not enough time since last packet passed through the line + c->rateDelayed = qtrue; + continue; + } } // generate and send a new message - SV_SendClientSnapshot( c ); + SV_SendClientSnapshot(c); + c->lastSnapshotTime = svs.time; + c->rateDelayed = qfalse; } } diff --git a/code/sys/new/sys_local_new.h b/code/sys/new/sys_local_new.h index d9c232af..b02973c6 100644 --- a/code/sys/new/sys_local_new.h +++ b/code/sys/new/sys_local_new.h @@ -20,4 +20,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -void Sys_InitEx(); \ No newline at end of file +void Sys_InitEx(); + +void Sys_PrepareBackTrace(); +void Sys_PrintBackTrace(); \ No newline at end of file diff --git a/code/sys/new/sys_main_new.c b/code/sys/new/sys_main_new.c index 56658a08..1e0788d9 100644 --- a/code/sys/new/sys_main_new.c +++ b/code/sys/new/sys_main_new.c @@ -404,9 +404,11 @@ void* Sys_GetCGameAPI(void* parms) } void VM_Forced_Unload_Start(void) { + Sys_PrepareBackTrace(); } void VM_Forced_Unload_Done(void) { + Sys_PrintBackTrace(); } void Sys_InitEx() diff --git a/code/sys/new/sys_unix_new.c b/code/sys/new/sys_unix_new.c index 8a2d1a8f..5de5a71c 100644 --- a/code/sys/new/sys_unix_new.c +++ b/code/sys/new/sys_unix_new.c @@ -22,6 +22,24 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../sys_local.h" +#include +#include +#include + +static void* backtrace_arr[20]; +static size_t backtrace_size; + +void Sys_PrepareBackTrace() { + void* backtrace_arr[20]; + + // get void*'s for all entries on the stack + backtrace_size = backtrace(backtrace_arr, sizeof(backtrace_arr) / sizeof(backtrace_arr[0])); +} + +void Sys_PrintBackTrace() { + backtrace_symbols_fd(backtrace_arr, backtrace_size, STDERR_FILENO); +} + /* ============== Sys_PumpMessageLoop diff --git a/code/sys/new/sys_win32_new.c b/code/sys/new/sys_win32_new.c index 8e26785d..f6d625b4 100644 --- a/code/sys/new/sys_win32_new.c +++ b/code/sys/new/sys_win32_new.c @@ -24,6 +24,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include + +void Sys_PrepareBackTrace() { +} + +void Sys_PrintBackTrace() { +} + /* ============== Sys_PumpMessageLoop diff --git a/code/sys/sys_unix.c b/code/sys/sys_unix.c index e0c63238..c69b04f4 100644 --- a/code/sys/sys_unix.c +++ b/code/sys/sys_unix.c @@ -391,7 +391,7 @@ void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, ch Sys_ListFiles ================== */ -char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) +char **Sys_ListFiles( const char *directory, const char *extension, const char *filter, int *numfiles, qboolean wantsubs ) { struct dirent *d; DIR *fdir; diff --git a/code/sys/sys_win32.c b/code/sys/sys_win32.c index e40caaa0..48ff3112 100644 --- a/code/sys/sys_win32.c +++ b/code/sys/sys_win32.c @@ -552,7 +552,7 @@ static qboolean strgtr(const char *s0, const char *s1) Sys_ListFiles ============== */ -char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) +char **Sys_ListFiles( const char *directory, const char *extension, const char *filter, int *numfiles, qboolean wantsubs ) { char search[MAX_OSPATH]; int nfiles;