summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--src/client/libmumblelink.c63
-rw-r--r--src/client/libmumblelink.h9
-rw-r--r--src/qcommon/common.c6
-rw-r--r--src/qcommon/cvar.c18
-rw-r--r--src/renderer/tr_init.c4
-rw-r--r--src/renderer/tr_local.h1
-rw-r--r--src/renderer/tr_scene.c8
-rw-r--r--src/server/sv_main.c217
-rw-r--r--src/sys/con_tty.c7
-rw-r--r--src/sys/sys_main.c1
-rw-r--r--src/sys/sys_unix.c40
12 files changed, 334 insertions, 50 deletions
diff --git a/Makefile b/Makefile
index 6af788ee..f19d0d65 100644
--- a/Makefile
+++ b/Makefile
@@ -192,7 +192,6 @@ ifneq ($(BUILD_CLIENT),0)
CURL_LIBS=$(shell pkg-config --silence-errors --libs libcurl)
OPENAL_CFLAGS=$(shell pkg-config --silence-errors --cflags openal)
OPENAL_LIBS=$(shell pkg-config --silence-errors --libs openal)
- # FIXME: introduce CLIENT_CFLAGS
SDL_CFLAGS=$(shell pkg-config --silence-errors --cflags sdl|sed 's/-Dmain=SDL_main//')
SDL_LIBS=$(shell pkg-config --silence-errors --libs sdl)
endif
@@ -556,7 +555,7 @@ ifeq ($(PLATFORM),freebsd)
CLIENT_CFLAGS += -DUSE_CODEC_VORBIS
endif
- OPTIMIZEVM = -DNDEBUG -O3 -funroll-loops -fomit-frame-pointer
+ OPTIMIZEVM = -O3 -funroll-loops -fomit-frame-pointer
ifeq ($(ARCH),axp)
BASE_CFLAGS += -DNO_VM_COMPILED
@@ -745,7 +744,7 @@ ifeq ($(PLATFORM),sunos)
CLIENT_CFLAGS = $(SDL_CFLAGS)
SERVER_CFLAGS =
- OPTIMIZEVM = -O3 -funroll-loops -DNDEBUG
+ OPTIMIZEVM = -O3 -funroll-loops
ifeq ($(ARCH),sparc)
OPTIMIZEVM += -O3 \
@@ -787,7 +786,7 @@ else # ifeq sunos
# SETUP AND BUILD -- GENERIC
#############################################################################
BASE_CFLAGS=-DNO_VM_COMPILED
- OPTIMIZE = -DNDEBUG -O3
+ OPTIMIZE = -O3
SHLIBEXT=so
SHLIBCFLAGS=-fPIC
@@ -845,6 +844,7 @@ endif
ifeq ($(USE_VOIP),1)
CLIENT_CFLAGS += -DUSE_VOIP
+ SERVER_CFLAGS += -DUSE_VOIP
ifeq ($(USE_INTERNAL_SPEEX),1)
CLIENT_CFLAGS += -DFLOATING_POINT -DUSE_ALLOCA -I$(SPEEXDIR)/include
else
@@ -966,7 +966,7 @@ endif
release:
@$(MAKE) targets B=$(BR) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \
- OPTIMIZE="$(OPTIMIZE)" OPTIMIZEVM="$(OPTIMIZEVM)" \
+ OPTIMIZE="-DNDEBUG $(OPTIMIZE)" OPTIMIZEVM="-DNDEBUG $(OPTIMIZEVM)" \
CLIENT_CFLAGS="$(CLIENT_CFLAGS)" SERVER_CFLAGS="$(SERVER_CFLAGS)" V=$(V)
ifeq ($(BUILD_MASTER_SERVER),1)
$(MAKE) -C $(MASTERDIR) release
diff --git a/src/client/libmumblelink.c b/src/client/libmumblelink.c
index 07b0c1ea..1b1e521e 100644
--- a/src/client/libmumblelink.c
+++ b/src/client/libmumblelink.c
@@ -40,14 +40,26 @@
#include "libmumblelink.h"
+#ifndef MIN
+#define MIN(a, b) ((a)<(b)?(a):(b))
+#endif
+
typedef struct
{
uint32_t uiVersion;
uint32_t uiTick;
- float fPosition[3];
- float fFront[3];
- float fTop[3];
+ float fAvatarPosition[3];
+ float fAvatarFront[3];
+ float fAvatarTop[3];
wchar_t name[256];
+ /* new in mumble 1.2 */
+ float fCameraPosition[3];
+ float fCameraFront[3];
+ float fCameraTop[3];
+ wchar_t identity[256];
+ uint32_t context_len;
+ unsigned char context[256];
+ wchar_t description[2048];
} LinkedMem;
static LinkedMem *lm = NULL;
@@ -95,6 +107,8 @@ int mumble_link(const char* name)
lm = (LinkedMem *) (mmap(NULL, sizeof(LinkedMem), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd,0));
if (lm == (void *) (-1)) {
lm = NULL;
+ close(shmfd);
+ return -1;
}
close(shmfd);
#endif
@@ -105,16 +119,51 @@ int mumble_link(const char* name)
void mumble_update_coordinates(float fPosition[3], float fFront[3], float fTop[3])
{
+ mumble_update_coordinates2(fPosition, fFront, fTop, fPosition, fFront, fTop);
+}
+
+void mumble_update_coordinates2(float fAvatarPosition[3], float fAvatarFront[3], float fAvatarTop[3],
+ float fCameraPosition[3], float fCameraFront[3], float fCameraTop[3])
+{
if (!lm)
return;
- memcpy(lm->fPosition, fPosition, sizeof(fPosition));
- memcpy(lm->fFront, fFront, sizeof(fFront));
- memcpy(lm->fTop, fTop, sizeof(fTop));
- lm->uiVersion = 1;
+ memcpy(lm->fAvatarPosition, fAvatarPosition, sizeof(fAvatarPosition));
+ memcpy(lm->fAvatarFront, fAvatarFront, sizeof(fAvatarFront));
+ memcpy(lm->fAvatarTop, fAvatarTop, sizeof(fAvatarTop));
+ memcpy(lm->fCameraPosition, fCameraPosition, sizeof(fCameraPosition));
+ memcpy(lm->fCameraFront, fCameraFront, sizeof(fCameraFront));
+ memcpy(lm->fCameraTop, fCameraTop, sizeof(fCameraTop));
+ lm->uiVersion = 2;
lm->uiTick = GetTickCount();
}
+void mumble_set_identity(const char* identity)
+{
+ size_t len;
+ if (!lm)
+ return;
+ len = MIN(sizeof(lm->identity), strlen(identity)+1);
+ mbstowcs(lm->identity, identity, len);
+}
+
+void mumble_set_context(const unsigned char* context, size_t len)
+{
+ if (!lm)
+ return;
+ len = MIN(sizeof(lm->context), len);
+ memcpy(lm->context, context, len);
+}
+
+void mumble_set_description(const char* description)
+{
+ size_t len;
+ if (!lm)
+ return;
+ len = MIN(sizeof(lm->description), strlen(description)+1);
+ mbstowcs(lm->description, description, len);
+}
+
void mumble_unlink()
{
if(!lm)
diff --git a/src/client/libmumblelink.h b/src/client/libmumblelink.h
index 805b9850..fc4929ff 100644
--- a/src/client/libmumblelink.h
+++ b/src/client/libmumblelink.h
@@ -24,4 +24,13 @@
int mumble_link(const char* name);
int mumble_islinked(void);
void mumble_update_coordinates(float fPosition[3], float fFront[3], float fTop[3]);
+
+/* new for mumble 1.2: also set camera position */
+void mumble_update_coordinates2(float fAvatarPosition[3], float fAvatarFront[3], float fAvatarTop[3],
+ float fCameraPosition[3], float fCameraFront[3], float fCameraTop[3]);
+
+void mumble_set_description(const char* description);
+void mumble_set_context(const unsigned char* context, size_t len);
+void mumble_set_identity(const char* identity);
+
void mumble_unlink(void);
diff --git a/src/qcommon/common.c b/src/qcommon/common.c
index eb3eca1b..d9fb4495 100644
--- a/src/qcommon/common.c
+++ b/src/qcommon/common.c
@@ -2919,6 +2919,12 @@ void Com_Frame( void ) {
if ( com_speeds->integer ) {
timeAfter = Sys_Milliseconds ();
}
+#else
+ if ( com_speeds->integer ) {
+ timeAfter = Sys_Milliseconds ();
+ timeBeforeEvents = timeAfter;
+ timeBeforeClient = timeAfter;
+ }
#endif
//
diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c
index 6358bf04..b0a21506 100644
--- a/src/qcommon/cvar.c
+++ b/src/qcommon/cvar.c
@@ -383,12 +383,12 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
var->latchedString = NULL; // otherwise cvar_set2 would free it
Cvar_Set2( var_name, s, qtrue );
Z_Free( s );
-
- // ZOID--needs to be set so that cvars the game sets as
- // SERVERINFO get sent to clients
- cvar_modifiedFlags |= flags;
}
+ // ZOID--needs to be set so that cvars the game sets as
+ // SERVERINFO get sent to clients
+ cvar_modifiedFlags |= flags;
+
return var;
}
@@ -1165,6 +1165,16 @@ void Cvar_Register(vmCvar_t *vmCvar, const char *varName, const char *defaultVal
{
cvar_t *cv;
+ // There is code in Cvar_Get to prevent CVAR_ROM cvars being changed by the
+ // user. In other words CVAR_ARCHIVE and CVAR_ROM are mutually exclusive
+ // flags. Unfortunately some historical game code (including single player
+ // baseq3) sets both flags. We unset CVAR_ROM for such cvars.
+ if ((flags & (CVAR_ARCHIVE | CVAR_ROM)) == (CVAR_ARCHIVE | CVAR_ROM)) {
+ Com_DPrintf( S_COLOR_YELLOW "WARNING: Unsetting CVAR_ROM cvar '%s', "
+ "since it is also CVAR_ARCHIVE\n", varName );
+ flags &= ~CVAR_ROM;
+ }
+
cv = Cvar_Get(varName, defaultValue, flags | CVAR_VM_CREATED);
if (!vmCvar)
diff --git a/src/renderer/tr_init.c b/src/renderer/tr_init.c
index 90b74683..89fcf3e3 100644
--- a/src/renderer/tr_init.c
+++ b/src/renderer/tr_init.c
@@ -42,8 +42,6 @@ cvar_t *r_ignoreFastPath;
cvar_t *r_verbose;
cvar_t *r_ignore;
-cvar_t *r_displayRefresh;
-
cvar_t *r_detailTextures;
cvar_t *r_znear;
@@ -938,8 +936,6 @@ void R_Register( void )
//
// temporary latched variables that can only change over a restart
//
- r_displayRefresh = ri.Cvar_Get( "r_displayRefresh", "0", CVAR_LATCH );
- ri.Cvar_CheckRange( r_displayRefresh, 0, 200, qtrue );
r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT );
r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "2", CVAR_LATCH );
r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH );
diff --git a/src/renderer/tr_local.h b/src/renderer/tr_local.h
index 231855e9..ad32c260 100644
--- a/src/renderer/tr_local.h
+++ b/src/renderer/tr_local.h
@@ -1044,7 +1044,6 @@ extern cvar_t *r_pixelAspect;
extern cvar_t *r_fullscreen;
extern cvar_t *r_noborder;
extern cvar_t *r_gamma;
-extern cvar_t *r_displayRefresh; // optional display refresh option
extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities
extern cvar_t *r_allowExtensions; // global enable/disable of OpenGL extensions
diff --git a/src/renderer/tr_scene.c b/src/renderer/tr_scene.c
index ae1376e9..232cb684 100644
--- a/src/renderer/tr_scene.c
+++ b/src/renderer/tr_scene.c
@@ -213,10 +213,10 @@ void RE_AddRefEntityToScene( const refEntity_t *ent ) {
return;
}
if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
- static qboolean first_time = qtrue;
- if (first_time) {
- first_time = qfalse;
- Com_Printf(S_COLOR_YELLOW "WARNING: You might have built ioquake3 with a buggy compiler!\n");
+ static qboolean firstTime = qtrue;
+ if (firstTime) {
+ firstTime = qfalse;
+ Com_DPrintf(S_COLOR_YELLOW "WARNING: RE_AddRefEntityToScene passed a refEntity which has an origin with a NaN component\n");
}
return;
}
diff --git a/src/server/sv_main.c b/src/server/sv_main.c
index 75e9dc72..4363e532 100644
--- a/src/server/sv_main.c
+++ b/src/server/sv_main.c
@@ -370,6 +370,182 @@ CONNECTIONLESS COMMANDS
==============================================================================
*/
+typedef struct leakyBucket_s leakyBucket_t;
+struct leakyBucket_s {
+ netadrtype_t type;
+
+ union {
+ byte _4[4];
+ byte _6[16];
+ } ipv;
+
+ int lastTime;
+ signed char burst;
+
+ long hash;
+
+ leakyBucket_t *prev, *next;
+};
+
+// This is deliberately quite large to make it more of an effort to DoS
+#define MAX_BUCKETS 16384
+#define MAX_HASHES 1024
+
+static leakyBucket_t buckets[ MAX_BUCKETS ];
+static leakyBucket_t *bucketHashes[ MAX_HASHES ];
+
+/*
+================
+SVC_HashForAddress
+================
+*/
+static long SVC_HashForAddress( netadr_t address ) {
+ byte *ip = NULL;
+ size_t size = 0;
+ int i;
+ long hash = 0;
+
+ switch ( address.type ) {
+ case NA_IP: ip = address.ip; size = 4; break;
+ case NA_IP6: ip = address.ip6; size = 16; break;
+ default: break;
+ }
+
+ for ( i = 0; i < size; i++ ) {
+ hash += (long)( ip[ i ] ) * ( i + 119 );
+ }
+
+ hash = ( hash ^ ( hash >> 10 ) ^ ( hash >> 20 ) );
+ hash &= ( MAX_HASHES - 1 );
+
+ return hash;
+}
+
+/*
+================
+SVC_BucketForAddress
+
+Find or allocate a bucket for an address
+================
+*/
+static leakyBucket_t *SVC_BucketForAddress( netadr_t address, int burst, int period ) {
+ leakyBucket_t *bucket = NULL;
+ int i;
+ long hash = SVC_HashForAddress( address );
+ int now = Sys_Milliseconds();
+
+ for ( bucket = bucketHashes[ hash ]; bucket; bucket = bucket->next ) {
+ switch ( bucket->type ) {
+ case NA_IP:
+ if ( memcmp( bucket->ipv._4, address.ip, 4 ) == 0 ) {
+ return bucket;
+ }
+ break;
+
+ case NA_IP6:
+ if ( memcmp( bucket->ipv._6, address.ip6, 16 ) == 0 ) {
+ return bucket;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ for ( i = 0; i < MAX_BUCKETS; i++ ) {
+ int interval;
+
+ bucket = &buckets[ i ];
+ interval = now - bucket->lastTime;
+
+ // Reclaim expired buckets
+ if ( bucket->lastTime > 0 && interval > ( burst * period ) ) {
+ if ( bucket->prev != NULL ) {
+ bucket->prev->next = bucket->next;
+ } else {
+ bucketHashes[ bucket->hash ] = bucket->next;
+ }
+
+ if ( bucket->next != NULL ) {
+ bucket->next->prev = bucket->prev;
+ }
+
+ Com_Memset( bucket, 0, sizeof( leakyBucket_t ) );
+ }
+
+ if ( bucket->type == NA_BAD ) {
+ bucket->type = address.type;
+ switch ( address.type ) {
+ case NA_IP: Com_Memcpy( bucket->ipv._4, address.ip, 4 ); break;
+ case NA_IP6: Com_Memcpy( bucket->ipv._6, address.ip6, 16 ); break;
+ default: break;
+ }
+
+ bucket->lastTime = now;
+ bucket->burst = 0;
+ bucket->hash = hash;
+
+ // Add to the head of the relevant hash chain
+ bucket->next = bucketHashes[ hash ];
+ if ( bucketHashes[ hash ] != NULL ) {
+ bucketHashes[ hash ]->prev = bucket;
+ }
+
+ bucket->prev = NULL;
+ bucketHashes[ hash ] = bucket;
+
+ return bucket;
+ }
+ }
+
+ // Couldn't allocate a bucket for this address
+ return NULL;
+}
+
+/*
+================
+SVC_RateLimit
+================
+*/
+static qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period ) {
+ if ( bucket != NULL ) {
+ int now = Sys_Milliseconds();
+ int interval = now - bucket->lastTime;
+ int expired = interval / period;
+ int expiredRemainder = interval % period;
+
+ if ( expired > bucket->burst ) {
+ bucket->burst = 0;
+ bucket->lastTime = now;
+ } else {
+ bucket->burst -= expired;
+ bucket->lastTime = now - expiredRemainder;
+ }
+
+ if ( bucket->burst < burst ) {
+ bucket->burst++;
+
+ return qfalse;
+ }
+ }
+
+ return qtrue;
+}
+
+/*
+================
+SVC_RateLimitAddress
+
+Rate limit for a particular address
+================
+*/
+static qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period ) {
+ leakyBucket_t *bucket = SVC_BucketForAddress( from, burst, period );
+
+ return SVC_RateLimit( bucket, burst, period );
+}
+
/*
================
SVC_Status
@@ -388,6 +564,21 @@ static void SVC_Status( netadr_t from ) {
int statusLength;
int playerLength;
char infostring[MAX_INFO_STRING];
+ static leakyBucket_t bucket;
+
+ // Prevent using getstatus as an amplifier
+ if ( SVC_RateLimitAddress( from, 10, 1000 ) ) {
+ Com_DPrintf( "SVC_Status: rate limit from %s exceeded, dropping request\n",
+ NET_AdrToString( from ) );
+ return;
+ }
+
+ // Allow getstatus to be DoSed relatively easily, but prevent
+ // excess outbound bandwidth usage when being flooded inbound
+ if ( SVC_RateLimit( &bucket, 10, 100 ) ) {
+ Com_DPrintf( "SVC_Status: rate limit exceeded, dropping request\n" );
+ return;
+ }
strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO ) );
@@ -501,24 +692,30 @@ Redirect all printfs
*/
static void SVC_RemoteCommand( netadr_t from, msg_t *msg ) {
qboolean valid;
- unsigned int time;
char remaining[1024];
// TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc.
// (OOB messages are the bottleneck here)
#define SV_OUTPUTBUF_LENGTH (1024 - 16)
char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
- static unsigned int lasttime = 0;
char *cmd_aux;
- // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534
- time = Com_Milliseconds();
- if ( (unsigned)( time - lasttime ) < 500u ) {
+ // Prevent using rcon as an amplifier and make dictionary attacks impractical
+ if ( SVC_RateLimitAddress( from, 10, 1000 ) ) {
+ Com_DPrintf( "SVC_Status: rate limit from %s exceeded, dropping request\n",
+ NET_AdrToString( from ) );
return;
}
- lasttime = time;
if ( !strlen( sv_rconPassword->string ) ||
strcmp (Cmd_Argv(1), sv_rconPassword->string) ) {
+ static leakyBucket_t bucket;
+
+ // Make DoS via rcon impractical
+ if ( SVC_RateLimit( &bucket, 10, 1000 ) ) {
+ Com_DPrintf( "SVC_Status: rate limit exceeded, dropping request\n" );
+ return;
+ }
+
valid = qfalse;
Com_Printf ("Bad rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) );
} else {
@@ -587,7 +784,7 @@ static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
Com_DPrintf ("SV packet %s : %s\n", NET_AdrToString(from), c);
if (!Q_stricmp(c, "getstatus")) {
- SVC_Status( from );
+ SVC_Status( from );
} else if (!Q_stricmp(c, "getinfo")) {
SVC_Info( from );
} else if (!Q_stricmp(c, "getchallenge")) {
@@ -601,8 +798,8 @@ static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
// server disconnect messages when their new server sees our final
// sequenced messages to the old client
} else {
- Com_DPrintf ("bad connectionless packet from %s:\n%s\n"
- , NET_AdrToString (from), s);
+ Com_DPrintf ("bad connectionless packet from %s:\n%s\n",
+ NET_AdrToString (from), s);
}
}
@@ -610,7 +807,7 @@ static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
/*
=================
-SV_ReadPackets
+SV_PacketEvent
=================
*/
void SV_PacketEvent( netadr_t from, msg_t *msg ) {
diff --git a/src/sys/con_tty.c b/src/sys/con_tty.c
index 547521c7..e4b2ad5c 100644
--- a/src/sys/con_tty.c
+++ b/src/sys/con_tty.c
@@ -42,6 +42,7 @@ called before and after a stdout or stderr output
=============================================================
*/
+extern qboolean stdinIsATTY;
static qboolean stdin_active;
// general flag to tell about tty console mode
static qboolean ttycon_on = qfalse;
@@ -270,21 +271,19 @@ Initialize the console input (tty mode if possible)
void CON_Init( void )
{
struct termios tc;
- const char* term = getenv("TERM");
// If the process is backgrounded (running non interactively)
// then SIGTTIN or SIGTOU is emitted, if not caught, turns into a SIGSTP
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
-
+
// If SIGCONT is received, reinitialize console
signal(SIGCONT, CON_SigCont);
// Make stdin reads non-blocking
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK );
- if (isatty(STDIN_FILENO) != 1
- || (term && (!strcmp(term, "raw") || !strcmp(term, "dumb"))))
+ if (!stdinIsATTY)
{
Com_Printf("tty console mode disabled\n");
ttycon_on = qfalse;
diff --git a/src/sys/sys_main.c b/src/sys/sys_main.c
index 9fadfa06..f76cb014 100644
--- a/src/sys/sys_main.c
+++ b/src/sys/sys_main.c
@@ -558,6 +558,7 @@ int main( int argc, char **argv )
signal( SIGFPE, Sys_SigHandler );
signal( SIGSEGV, Sys_SigHandler );
signal( SIGTERM, Sys_SigHandler );
+ signal( SIGINT, Sys_SigHandler );
while( 1 )
{
diff --git a/src/sys/sys_unix.c b/src/sys/sys_unix.c
index 7863c082..ccff6312 100644
--- a/src/sys/sys_unix.c
+++ b/src/sys/sys_unix.c
@@ -38,6 +38,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <libgen.h>
#include <fcntl.h>
+qboolean stdinIsATTY;
+
// Used to determine where to store user-specific files
static char homePath[ MAX_OSPATH ] = { 0 };
@@ -355,7 +357,7 @@ char **Sys_ListFiles( const char *directory, const char *extension, char *filter
}
extLen = strlen( extension );
-
+
// search
nfiles = 0;
@@ -465,24 +467,35 @@ Block execution for msec or until input is recieved.
*/
void Sys_Sleep( int msec )
{
- fd_set fdset;
-
if( msec == 0 )
return;
- FD_ZERO(&fdset);
- FD_SET(fileno(stdin), &fdset);
- if( msec < 0 )
+ if( stdinIsATTY )
{
- select((fileno(stdin) + 1), &fdset, NULL, NULL, NULL);
+ fd_set fdset;
+
+ FD_ZERO(&fdset);
+ FD_SET(STDIN_FILENO, &fdset);
+ if( msec < 0 )
+ {
+ select(STDIN_FILENO + 1, &fdset, NULL, NULL, NULL);
+ }
+ else
+ {
+ struct timeval timeout;
+
+ timeout.tv_sec = msec/1000;
+ timeout.tv_usec = (msec%1000)*1000;
+ select(STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout);
+ }
}
else
{
- struct timeval timeout;
+ // With nothing to select() on, we can't wait indefinitely
+ if( msec < 0 )
+ msec = 10;
- timeout.tv_sec = msec/1000;
- timeout.tv_usec = (msec%1000)*1000;
- select((fileno(stdin) + 1), &fdset, NULL, NULL, &timeout);
+ usleep( msec * 1000 );
}
}
@@ -572,11 +585,16 @@ Unix specific initialisation
*/
void Sys_PlatformInit( void )
{
+ const char* term = getenv( "TERM" );
+
signal( SIGHUP, Sys_SigHandler );
signal( SIGQUIT, Sys_SigHandler );
signal( SIGTRAP, Sys_SigHandler );
signal( SIGIOT, Sys_SigHandler );
signal( SIGBUS, Sys_SigHandler );
+
+ stdinIsATTY = isatty( STDIN_FILENO ) &&
+ !( term && ( !strcmp( term, "raw" ) || !strcmp( term, "dumb" ) ) );
}
/*