shithub: qk3

Download patch

ref: 06334302be79aac913acdcf2c357f3f4e48fc6f3
parent: a8a53b1228ec040b0b449150b7d62b06a8c7f4e1
author: qwx <>
date: Sat Jan 12 16:06:56 EST 2019

kludge dedicated compilation

- networking code from qk1/qw
- simple common sys code -> sys.c
- client main -> qk3.c

--- a/code/mkfile
+++ b/code/mkfile
@@ -34,10 +34,10 @@
 	game/q_math.$O\
 	game/q_shared.$O\
 	unix/qk3ded.$O\
+	unix/sys.$O\
 	unix/linux_common.$O\
 	unix/unix_net.$O\
 	unix/unix_shared.$O\
-	unix/linux_signals.$O\
 
 HFILES=\
 	game/ai_chat.h\
@@ -84,3 +84,8 @@
 
 </sys/src/cmd/mkone
 CFLAGS=$CFLAGS -DDEDICATED -DC_ONLY
+
+%.$O:	%.c
+	$CC $CFLAGS -o $stem.$O $stem.c
+
+CLEANFILES=$CLEANFILES $OFILES
--- a/code/qcommon/net_chan.c
+++ b/code/qcommon/net_chan.c
@@ -126,7 +126,7 @@
 	MSG_WriteData( &send, chan->unsentBuffer + chan->unsentFragmentStart, fragmentLength );
 
 	// send the datagram
-	NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );
+	NET_SendPacket(chan->sock, send.cursize, send.data, &chan->remoteAddress );
 
 	if ( showpackets->integer ) {
 		Com_Printf ("%s send %4i : s=%i fragment=%i,%i\n"
@@ -192,7 +192,7 @@
 	MSG_WriteData( &send, data, length );
 
 	// send the datagram
-	NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );
+	NET_SendPacket(chan->sock, send.cursize, send.data, &chan->remoteAddress );
 
 	if ( showpackets->integer ) {
 		Com_Printf( "%s send %4i : s=%i ack=%i\n"
@@ -271,7 +271,7 @@
 	if ( sequence <= chan->incomingSequence ) {
 		if ( showdrop->integer || showpackets->integer ) {
 			Com_Printf( "%s:Out of order packet %i at %i\n"
-				, NET_AdrToString( chan->remoteAddress )
+				, chan->remoteAddress.sys
 				,  sequence
 				, chan->incomingSequence );
 		}
@@ -285,7 +285,7 @@
 	if ( chan->dropped > 0 ) {
 		if ( showdrop->integer || showpackets->integer ) {
 			Com_Printf( "%s:Dropped %i packets at %i\n"
-			, NET_AdrToString( chan->remoteAddress )
+			, chan->remoteAddress.sys
 			, chan->dropped
 			, sequence );
 		}
@@ -311,7 +311,7 @@
 		if ( fragmentStart != chan->fragmentLength ) {
 			if ( showdrop->integer || showpackets->integer ) {
 				Com_Printf( "%s:Dropped a message fragment\n"
-				, NET_AdrToString( chan->remoteAddress )
+				, chan->remoteAddress.sys
 				, sequence);
 			}
 			// we can still keep the part that we have so far,
@@ -324,7 +324,7 @@
 			chan->fragmentLength + fragmentLength > sizeof( chan->fragmentBuffer ) ) {
 			if ( showdrop->integer || showpackets->integer ) {
 				Com_Printf ("%s:illegal fragment length\n"
-				, NET_AdrToString (chan->remoteAddress ) );
+				, chan->remoteAddress.sys);
 			}
 			return qfalse;
 		}
@@ -341,7 +341,7 @@
 
 		if ( chan->fragmentLength > msg->maxsize ) {
 			Com_Printf( "%s:fragmentLength %i > msg->maxsize\n"
-				, NET_AdrToString (chan->remoteAddress ),
+				, chan->remoteAddress.sys,
 				chan->fragmentLength );
 			return qfalse;
 		}
@@ -382,83 +382,60 @@
 Compares without the port
 ===================
 */
-qboolean	NET_CompareBaseAdr (netadr_t a, netadr_t b)
+qboolean	NET_CompareBaseAdr(netadr_t *a, netadr_t *b)
 {
-	if (a.type != b.type)
+	if (a->type != b->type)
 		return qfalse;
 
-	if (a.type == NA_LOOPBACK)
+	if (a->type == NA_LOOPBACK)
 		return qtrue;
 
-	if (a.type == NA_IP)
+	if (a->type == NA_IP)
 	{
-		if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
+		if(strcmp(a->addr, b->addr) == 0)
 			return qtrue;
 		return qfalse;
 	}
 
-	if (a.type == NA_IPX)
-	{
-		if ((memcmp(a.ipx, b.ipx, 10) == 0))
-			return qtrue;
-		return qfalse;
-	}
-
-
 	Com_Printf ("NET_CompareBaseAdr: bad address type\n");
 	return qfalse;
 }
 
-const char	*NET_AdrToString (netadr_t a)
+const char	*NET_AdrToString(netadr_t *a)
 {
-	static	char	s[64];
-
-	if (a.type == NA_LOOPBACK) {
-		Com_sprintf (s, sizeof(s), "loopback");
-	} else if (a.type == NA_BOT) {
-		Com_sprintf (s, sizeof(s), "bot");
-	} else if (a.type == NA_IP) {
-		Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%hu",
-			a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));
+	if (a->type == NA_LOOPBACK) {
+		return "loopback";
+	} else if (a->type == NA_BOT) {
+		return "bot";
+	} else if (a->type == NA_IP) {
+		return a->sys;
 	} else {
-		Com_sprintf (s, sizeof(s), "%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x:%hu",
-		a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], 
-		BigShort(a.port));
+		Com_Printf ("NET_AdrToString: bad address type\n");
+		return nil;
 	}
-
-	return s;
 }
 
-
-qboolean	NET_CompareAdr (netadr_t a, netadr_t b)
+qboolean	NET_CompareAdr (netadr_t *a, netadr_t *b)
 {
-	if (a.type != b.type)
+	if (a->type != b->type)
 		return qfalse;
 
-	if (a.type == NA_LOOPBACK)
+	if (a->type == NA_LOOPBACK)
 		return qtrue;
 
-	if (a.type == NA_IP)
+	if (a->type == NA_IP)
 	{
-		if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
+		if(strcmp(a->sys, b->sys) == 0)
 			return qtrue;
 		return qfalse;
 	}
 
-	if (a.type == NA_IPX)
-	{
-		if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port)
-			return qtrue;
-		return qfalse;
-	}
-
 	Com_Printf ("NET_CompareAdr: bad address type\n");
 	return qfalse;
 }
 
-
-qboolean	NET_IsLocalAddress( netadr_t adr ) {
-	return adr.type == NA_LOOPBACK;
+qboolean	NET_IsLocalAddress( netadr_t *adr ) {
+	return adr->type == NA_LOOPBACK;
 }
 
 
@@ -513,7 +490,7 @@
 }
 
 
-void NET_SendLoopPacket (netsrc_t sock, int length, const void *data, netadr_t to)
+void NET_SendLoopPacket (netsrc_t sock, int length, const void *data, netadr_t *to)
 {
 	int		i;
 	loopback_t	*loop;
@@ -530,7 +507,7 @@
 //=============================================================================
 
 
-void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to ) {
+void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t *to ) {
 
 	// sequenced packets are shown in netchan, so just show oob
 	if ( showpackets->integer && *(int *)data == -1 )	{
@@ -537,14 +514,14 @@
 		Com_Printf ("send packet %4i\n", length);
 	}
 
-	if ( to.type == NA_LOOPBACK ) {
+	if ( to->type == NA_LOOPBACK ) {
 		NET_SendLoopPacket (sock, length, data, to);
 		return;
 	}
-	if ( to.type == NA_BOT ) {
+	if ( to->type == NA_BOT ) {
 		return;
 	}
-	if ( to.type == NA_BAD ) {
+	if ( to->type == NA_BAD ) {
 		return;
 	}
 
@@ -558,7 +535,7 @@
 Sends a text message in an out-of-band datagram
 ================
 */
-void QDECL NET_OutOfBandPrint( netsrc_t sock, netadr_t adr, const char *format, ... ) {
+void QDECL NET_OutOfBandPrint( netsrc_t sock, netadr_t *adr, const char *format, ... ) {
 	va_list		argptr;
 	char		string[MAX_MSGLEN];
 
@@ -584,7 +561,7 @@
 Sends a data message in an out-of-band datagram (only used for "connect")
 ================
 */
-void QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len ) {
+void QDECL NET_OutOfBandData( netsrc_t sock, netadr_t *adr, byte *format, int len ) {
 	byte		string[MAX_MSGLEN*2];
 	int			i;
 	msg_t		mbuf;
@@ -615,8 +592,6 @@
 */
 qboolean	NET_StringToAdr( const char *s, netadr_t *a ) {
 	qboolean	r;
-	char	base[MAX_STRING_CHARS];
-	char	*port;
 
 	if (!strcmp (s, "localhost")) {
 		Com_Memset (a, 0, sizeof(*a));
@@ -624,33 +599,10 @@
 		return qtrue;
 	}
 
-	// look for a port number
-	Q_strncpyz( base, s, sizeof( base ) );
-	port = strstr( base, ":" );
-	if ( port ) {
-		*port = 0;
-		port++;
-	}
-
-	r = Sys_StringToAdr( base, a );
-
+	r = Sys_StringToAdr(s, a);
 	if ( !r ) {
 		a->type = NA_BAD;
 		return qfalse;
 	}
-
-	// 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 ) );
-	} else {
-		a->port = BigShort( PORT_SERVER );
-	}
-
 	return qtrue;
 }
-
--- a/code/qcommon/qcommon.h
+++ b/code/qcommon/qcommon.h
@@ -141,27 +141,29 @@
 
 typedef struct {
 	netadrtype_t	type;
-
-	byte	ip[4];
-	byte	ipx[10];
-
-	unsigned short	port;
+	int fd;
+	char sys[72];
+	char addr[64];
+	char srv[8];
 } netadr_t;
 
+extern netadr_t *net_from, cons[2*MAX_CLIENTS];
+extern int svonly;
+
 void		NET_Init( void );
 void		NET_Shutdown( void );
 void		NET_Restart( void );
 void		NET_Config( qboolean enableNetworking );
 
-void		NET_SendPacket (netsrc_t sock, int length, const void *data, netadr_t to);
-void		QDECL NET_OutOfBandPrint( netsrc_t net_socket, netadr_t adr, const char *format, ...);
-void		QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len );
+void		NET_SendPacket (netsrc_t sock, int length, const void *data, netadr_t *to);
+void		QDECL NET_OutOfBandPrint( netsrc_t net_socket, netadr_t *adr, const char *format, ...);
+void		QDECL NET_OutOfBandData( netsrc_t sock, netadr_t *adr, byte *format, int len );
 
-qboolean	NET_CompareAdr (netadr_t a, netadr_t b);
-qboolean	NET_CompareBaseAdr (netadr_t a, netadr_t b);
-qboolean	NET_IsLocalAddress (netadr_t adr);
-const char	*NET_AdrToString (netadr_t a);
-qboolean	NET_StringToAdr ( const char *s, netadr_t *a);
+qboolean	NET_CompareAdr(netadr_t*, netadr_t*);
+qboolean	NET_CompareBaseAdr(netadr_t*, netadr_t*);
+qboolean	NET_IsLocalAddress(netadr_t*);
+char*	NET_AdrToString(netadr_t*);
+qboolean	NET_StringToAdr(char*, netadr_t*);
 qboolean	NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, msg_t *net_message);
 void		NET_Sleep(int msec);
 
@@ -982,17 +984,17 @@
 void	Sys_ShowConsole( int level, qboolean quitOnClose );
 void	Sys_SetErrorText( const char *text );
 
-void	Sys_SendPacket( int 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 );
 //Does NOT parse port numbers, only base addresses.
 
-qboolean	Sys_IsLANAddress (netadr_t adr);
+qboolean	Sys_IsLANAddress (netadr_t *adr);
 void		Sys_ShowIP(void);
 
 qboolean	Sys_CheckCD( void );
 
-void	Sys_Mkdir( const char *path );
+int	Sys_Mkdir( const char *path );
 char	*Sys_Cwd( void );
 void	Sys_SetDefaultCDPath(const char *path);
 char	*Sys_DefaultCDPath(void);
@@ -1011,6 +1013,9 @@
 unsigned int Sys_ProcessorCount();
 
 int Sys_MonkeyShouldBeSpanked( void );
+
+void*	emalloc(ulong);
+vlong	flen(int);
 
 /* This is based on the Adaptive Huffman algorithm described in Sayood's Data
  * Compression book.  The ranks are not actually stored, but implicitly defined
--- a/code/server/sv_ccmds.c
+++ b/code/server/sv_ccmds.c
@@ -121,8 +121,6 @@
 		return NULL;
 	}
 	return cl;
-
-	return NULL;
 }
 
 //=========================================================
@@ -413,24 +411,22 @@
 	}
 
 	// look up the authorize server's IP
-	if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
-		Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
-		if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {
-			Com_Printf( "Couldn't resolve address\n" );
+	if ( !svs.authorizeAddress.sys[0] && svs.authorizeAddress.type != NA_BAD ) {
+		char s[128];
+
+		snprint(s, sizeof s, "%s!%d", AUTHORIZE_SERVER_NAME, PORT_AUTHORIZE);
+		Com_Printf("Resolving %s\n", s);
+		if(!NET_StringToAdr(s, &svs.authorizeAddress)){
+			Com_Printf("Couldn't resolve address\n");
 			return;
 		}
-		svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
-		Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
-			svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
-			svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
-			BigShort( svs.authorizeAddress.port ) );
+		Com_Printf( "Resolved to %s\n", svs.authorizeAddress.sys);
 	}
 
 	// otherwise send their ip to the authorize server
 	if ( svs.authorizeAddress.type != NA_BAD ) {
-		NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
-			"banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1], 
-								   cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
+		NET_OutOfBandPrint( NS_SERVER, &svs.authorizeAddress,
+			"banUser %s", cl->netchan.remoteAddress.addr);
 		Com_Printf("%s was banned from coming back\n", cl->name);
 	}
 }
@@ -467,24 +463,22 @@
 	}
 
 	// look up the authorize server's IP
-	if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
-		Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
-		if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {
-			Com_Printf( "Couldn't resolve address\n" );
+	if ( !svs.authorizeAddress.sys[0] && svs.authorizeAddress.type != NA_BAD ) {
+		char s[128];
+
+		snprint(s, sizeof s, "%s!%d", AUTHORIZE_SERVER_NAME, PORT_AUTHORIZE);
+		Com_Printf("Resolving %s\n", s);
+		if(!NET_StringToAdr(s, &svs.authorizeAddress)){
+			Com_Printf("Couldn't resolve address\n");
 			return;
 		}
-		svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
-		Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
-			svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
-			svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
-			BigShort( svs.authorizeAddress.port ) );
+		Com_Printf( "Resolved to %s\n", svs.authorizeAddress.sys);
 	}
 
 	// otherwise send their ip to the authorize server
 	if ( svs.authorizeAddress.type != NA_BAD ) {
-		NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
-			"banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1], 
-								   cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
+		NET_OutOfBandPrint( NS_SERVER, &svs.authorizeAddress,
+			"banUser %s", cl->netchan.remoteAddress.addr);
 		Com_Printf("%s was banned from coming back\n", cl->name);
 	}
 }
@@ -573,7 +567,7 @@
 
 		Com_Printf ("%7i ", svs.time - cl->lastPacketTime );
 
-		s = NET_AdrToString( cl->netchan.remoteAddress );
+		s = NET_AdrToString(&cl->netchan.remoteAddress);
 		Com_Printf ("%s", s);
 		l = 22 - strlen(s);
 		for (j=0 ; j<l ; j++)
--- a/code/server/sv_client.c
+++ b/code/server/sv_client.c
@@ -60,7 +60,7 @@
 	// see if we already have a challenge for this ip
 	challenge = &svs.challenges[0];
 	for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) {
-		if ( !challenge->connected && NET_CompareAdr( from, challenge->adr ) ) {
+		if(!challenge->connected && NET_CompareAdr(&from, &challenge->adr)){
 			break;
 		}
 		if ( challenge->time < oldestTime ) {
@@ -82,24 +82,23 @@
 	}
 
 	// if they are on a lan address, send the challengeResponse immediately
-	if ( Sys_IsLANAddress( from ) ) {
+	if ( Sys_IsLANAddress( &from ) ) {
 		challenge->pingTime = svs.time;
-		NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge );
+		NET_OutOfBandPrint( NS_SERVER, &from, "challengeResponse %i", challenge->challenge );
 		return;
 	}
 
 	// look up the authorize server's IP
-	if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) {
-		Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
-		if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) {
-			Com_Printf( "Couldn't resolve address\n" );
+	if ( !svs.authorizeAddress.sys[0] && svs.authorizeAddress.type != NA_BAD ) {
+		char s[128];
+
+		snprint(s, sizeof s, "%s!%d", AUTHORIZE_SERVER_NAME, PORT_AUTHORIZE);
+		Com_Printf("Resolving %s\n", s);
+		if(!NET_StringToAdr(s, &svs.authorizeAddress)){
+			Com_Printf("Couldn't resolve address\n");
 			return;
 		}
-		svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE );
-		Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
-			svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1],
-			svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3],
-			BigShort( svs.authorizeAddress.port ) );
+		Com_Printf("Resolved to %s\n", svs.authorizeAddress.sys);
 	}
 
 	// if they have been challenging for a long time and we
@@ -109,7 +108,7 @@
 		Com_DPrintf( "authorize server timed out\n" );
 
 		challenge->pingTime = svs.time;
-		NET_OutOfBandPrint( NS_SERVER, challenge->adr, 
+		NET_OutOfBandPrint( NS_SERVER, &challenge->adr, 
 			"challengeResponse %i", challenge->challenge );
 		return;
 	}
@@ -119,7 +118,7 @@
 		cvar_t	*fs;
 		char	game[1024];
 
-		Com_DPrintf( "sending getIpAuthorize for %s\n", NET_AdrToString( from ));
+		Com_DPrintf("sending getIpAuthorize for %s\n", NET_AdrToString(&from));
 		
 		strcpy(game, BASEGAME);
 		fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
@@ -129,9 +128,9 @@
 		
 		// the 0 is for backwards compatibility with obsolete sv_allowanonymous flags
 		// getIpAuthorize <challenge> <IP> <game> 0 <auth-flag>
-		NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
-			"getIpAuthorize %i %i.%i.%i.%i %s 0 %s",  svs.challenges[i].challenge,
-			from.ip[0], from.ip[1], from.ip[2], from.ip[3], game, sv_strictAuth->string );
+		NET_OutOfBandPrint( NS_SERVER, &svs.authorizeAddress,
+			"getIpAuthorize %i %s %s 0 %s",  svs.challenges[i].challenge,
+			from.addr, game, sv_strictAuth->string );
 	}
 }
 
@@ -151,7 +150,7 @@
 	char	*r;
 	char	ret[1024];
 
-	if ( !NET_CompareBaseAdr( from, svs.authorizeAddress ) ) {
+	if(!NET_CompareBaseAdr(&from, &svs.authorizeAddress)){
 		Com_Printf( "SV_AuthorizeIpPacket: not from authorize server\n" );
 		return;
 	}
@@ -176,27 +175,27 @@
 	if ( !Q_stricmp( s, "demo" ) ) {
 		if ( Cvar_VariableValue( "fs_restrict" ) ) {
 			// a demo client connecting to a demo server
-			NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, 
+			NET_OutOfBandPrint( NS_SERVER, &svs.challenges[i].adr, 
 				"challengeResponse %i", svs.challenges[i].challenge );
 			return;
 		}
 		// they are a demo client trying to connect to a real server
-		NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nServer is not a demo server\n" );
+		NET_OutOfBandPrint( NS_SERVER, &svs.challenges[i].adr, "print\nServer is not a demo server\n" );
 		// clear the challenge record so it won't timeout and let them through
 		Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );
 		return;
 	}
 	if ( !Q_stricmp( s, "accept" ) ) {
-		NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, 
+		NET_OutOfBandPrint( NS_SERVER, &svs.challenges[i].adr, 
 			"challengeResponse %i", svs.challenges[i].challenge );
 		return;
 	}
 	if ( !Q_stricmp( s, "unknown" ) ) {
 		if (!r) {
-			NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nAwaiting CD key authorization\n" );
+			NET_OutOfBandPrint( NS_SERVER, &svs.challenges[i].adr, "print\nAwaiting CD key authorization\n" );
 		} else {
 			sprintf(ret, "print\n%s\n", r);
-			NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, ret );
+			NET_OutOfBandPrint( NS_SERVER, &svs.challenges[i].adr, ret );
 		}
 		// clear the challenge record so it won't timeout and let them through
 		Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) );
@@ -205,10 +204,10 @@
 
 	// authorization failed
 	if (!r) {
-		NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nSomeone is using this CD Key\n" );
+		NET_OutOfBandPrint( NS_SERVER, &svs.challenges[i].adr, "print\nSomeone is using this CD Key\n" );
 	} else {
 		sprintf(ret, "print\n%s\n", r);
-		NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, ret );
+		NET_OutOfBandPrint( NS_SERVER, &svs.challenges[i].adr, ret );
 	}
 
 	// clear the challenge record so it won't timeout and let them through
@@ -248,7 +247,7 @@
 
 	version = atoi( Info_ValueForKey( userinfo, "protocol" ) );
 	if ( version != PROTOCOL_VERSION ) {
-		NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i.\n", PROTOCOL_VERSION );
+		NET_OutOfBandPrint( NS_SERVER, &from, "print\nServer uses protocol version %i.\n", PROTOCOL_VERSION );
 		Com_DPrintf ("    rejected connect from version %i\n", version);
 		return;
 	}
@@ -261,12 +260,12 @@
 		if ( cl->state == CS_FREE ) {
 			continue;
 		}
-		if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )
+		if(NET_CompareBaseAdr(&from, &cl->netchan.remoteAddress)
 			&& ( cl->netchan.qport == qport 
-			|| from.port == cl->netchan.remoteAddress.port ) ) {
+			|| strcmp(from.srv, cl->netchan.remoteAddress.srv) == 0)) {
 			if (( svs.time - cl->lastConnectTime) 
 				< (sv_reconnectlimit->integer * 1000)) {
-				Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (from));
+				Com_DPrintf("%s: reconnect rejected: too soon\n", from.sys);
 				return;
 			}
 			break;
@@ -274,11 +273,11 @@
 	}
 
 	// see if the challenge is valid (LAN clients don't need to challenge)
-	if ( !NET_IsLocalAddress (from) ) {
+	if(!NET_IsLocalAddress(&from)){
 		int		ping;
 
 		for (i=0 ; i<MAX_CHALLENGES ; i++) {
-			if (NET_CompareAdr(from, svs.challenges[i].adr)) {
+			if(NET_CompareAdr(&from, &svs.challenges[i].adr)){
 				if ( challenge == svs.challenges[i].challenge ) {
 					break;		// good
 				}
@@ -285,11 +284,11 @@
 			}
 		}
 		if (i == MAX_CHALLENGES) {
-			NET_OutOfBandPrint( NS_SERVER, from, "print\nNo or bad challenge for address.\n" );
+			NET_OutOfBandPrint( NS_SERVER, &from, "print\nNo or bad challenge for address.\n" );
 			return;
 		}
 		// force the IP key/value pair so the game can filter based on ip
-		Info_SetValueForKey( userinfo, "ip", NET_AdrToString( from ) );
+		Info_SetValueForKey( userinfo, "ip", from.addr);
 
 		ping = svs.time - svs.challenges[i].pingTime;
 		Com_Printf( "Client %i connecting with %i challenge ping\n", i, ping );
@@ -296,18 +295,25 @@
 		svs.challenges[i].connected = qtrue;
 
 		// never reject a LAN client based on ping
-		if ( !Sys_IsLANAddress( from ) ) {
+		if ( !Sys_IsLANAddress( &from ) ) {
 			if ( sv_minPing->value && ping < sv_minPing->value ) {
+				char *s;
+
 				// don't let them keep trying until they get a big delay
-				NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for high pings only\n" );
+				NET_OutOfBandPrint( NS_SERVER, &from, "print\nServer is for high pings only\n" );
 				Com_DPrintf ("Client %i rejected on a too low ping\n", i);
 				// reset the address otherwise their ping will keep increasing
 				// with each connect message and they'd eventually be able to connect
-				svs.challenges[i].adr.port = 0;
+				svs.challenges[i].adr.srv[0] = 0;
+				s = strrchr(svs.challenges[i].adr.sys, '!');
+				if(s != nil){
+					s[1] = '0';
+					s[2] = 0;
+				}
 				return;
 			}
 			if ( sv_maxPing->value && ping > sv_maxPing->value ) {
-				NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for low pings only\n" );
+				NET_OutOfBandPrint( NS_SERVER, &from, "print\nServer is for low pings only\n" );
 				Com_DPrintf ("Client %i rejected on a too high ping\n", i);
 				return;
 			}
@@ -325,10 +331,10 @@
 		if ( cl->state == CS_FREE ) {
 			continue;
 		}
-		if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress )
+		if(NET_CompareBaseAdr(&from, &cl->netchan.remoteAddress)
 			&& ( cl->netchan.qport == qport 
-			|| from.port == cl->netchan.remoteAddress.port ) ) {
-			Com_Printf ("%s:reconnect\n", NET_AdrToString (from));
+			|| strcmp(from.srv, cl->netchan.remoteAddress.srv) == 0)){
+			Com_Printf("%s: reconnect\n", from.sys);
 			newcl = cl;
 
 			// this doesn't work because it nukes the players userinfo
@@ -370,7 +376,7 @@
 	}
 
 	if ( !newcl ) {
-		if ( NET_IsLocalAddress( from ) ) {
+		if(NET_IsLocalAddress(&from)){
 			count = 0;
 			for ( i = startIndex; i < sv_maxclients->integer ; i++ ) {
 				cl = &svs.clients[i];
@@ -389,7 +395,7 @@
 			}
 		}
 		else {
-			NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is full.\n" );
+			NET_OutOfBandPrint( NS_SERVER, &from, "print\nServer is full.\n" );
 			Com_DPrintf ("Rejected a connection.\n");
 			return;
 		}
@@ -425,7 +431,7 @@
 		// we can't just use VM_ArgPtr, because that is only valid inside a VM_Call
 		denied = VM_ExplicitArgPtr( gvm, (int)denied );
 
-		NET_OutOfBandPrint( NS_SERVER, from, "print\n%s\n", denied );
+		NET_OutOfBandPrint( NS_SERVER, &from, "print\n%s\n", denied );
 		Com_DPrintf ("Game rejected a connection: %s.\n", denied);
 		return;
 	}
@@ -433,7 +439,7 @@
 	SV_UserinfoChanged( newcl );
 
 	// send the connect packet to the client
-	NET_OutOfBandPrint( NS_SERVER, from, "connectResponse" );
+	NET_OutOfBandPrint( NS_SERVER, &from, "connectResponse" );
 
 	Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name );
 
@@ -483,7 +489,7 @@
 		challenge = &svs.challenges[0];
 
 		for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) {
-			if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) {
+			if(NET_CompareAdr(&drop->netchan.remoteAddress, &challenge->adr)){
 				challenge->connected = qfalse;
 				break;
 			}
@@ -1123,7 +1129,7 @@
 
 	// if the client is on the same subnet as the server and we aren't running an
 	// internet public server, assume they don't need a rate choke
-	if ( Sys_IsLANAddress( cl->netchan.remoteAddress ) && com_dedicated->integer != 2 && sv_lanForceRate->integer == 1) {
+	if ( Sys_IsLANAddress( &cl->netchan.remoteAddress ) && com_dedicated->integer != 2 && sv_lanForceRate->integer == 1) {
 		cl->rate = 99999;	// lans should not rate limit
 	} else {
 		val = Info_ValueForKey (cl->userinfo, "rate");
@@ -1169,8 +1175,8 @@
 	if (!val[0])
 	{
 		//Com_DPrintf("Maintain IP in userinfo for '%s'\n", cl->name);
-		if ( !NET_IsLocalAddress(cl->netchan.remoteAddress) )
-			Info_SetValueForKey( cl->userinfo, "ip", NET_AdrToString( cl->netchan.remoteAddress ) );
+		if(!NET_IsLocalAddress(&cl->netchan.remoteAddress))
+			Info_SetValueForKey( cl->userinfo, "ip", cl->netchan.remoteAddress.addr);
 		else
 			// force the "ip" info key to "localhost" for local clients
 			Info_SetValueForKey( cl->userinfo, "ip", "localhost" );
--- a/code/server/sv_main.c
+++ b/code/server/sv_main.c
@@ -239,23 +239,24 @@
 		// resolving usually causes hitches on win95, so only
 		// do it when needed
 		if ( sv_master[i]->modified ) {
+			char s[128], *p;
+
 			sv_master[i]->modified = qfalse;
-	
-			Com_Printf( "Resolving %s\n", sv_master[i]->string );
-			if ( !NET_StringToAdr( sv_master[i]->string, &adr[i] ) ) {
+			p = sv_master[i]->string;
+			if(strrchr(p, ':') == nil && strrchr(p, '!') == nil){
+				p = s;
+				snprint(s, sizeof s, "%s!%d", sv_master[i]->string, PORT_MASTER);
+			}
+			Com_Printf("Resolving %s\n", p);
+			if(!NET_StringToAdr(p, &adr[i])){
 				// if the address failed to resolve, clear it
 				// so we don't take repeated dns hits
-				Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string );
-				Cvar_Set( sv_master[i]->name, "" );
+				Com_Printf("Couldn't resolve address: %s\n", sv_master[i]->string);
+				Cvar_Set(sv_master[i]->name, "");
 				sv_master[i]->modified = qfalse;
 				continue;
 			}
-			if ( !strstr( ":", sv_master[i]->string ) ) {
-				adr[i].port = BigShort( PORT_MASTER );
-			}
-			Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", sv_master[i]->string,
-				adr[i].ip[0], adr[i].ip[1], adr[i].ip[2], adr[i].ip[3],
-				BigShort( adr[i].port ) );
+			Com_Printf("Resolved to %s\n", adr[i].sys);
 		}
 
 
@@ -262,7 +263,7 @@
 		Com_Printf ("Sending heartbeat to %s\n", sv_master[i]->string );
 		// this command should be changed if the server info / status format
 		// ever incompatably changes
-		NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", HEARTBEAT_GAME );
+		NET_OutOfBandPrint( NS_SERVER, &adr[i], "heartbeat %s\n", HEARTBEAT_GAME );
 	}
 }
 
@@ -352,7 +353,7 @@
 		}
 	}
 
-	NET_OutOfBandPrint( NS_SERVER, from, "statusResponse\n%s\n%s", infostring, status );
+	NET_OutOfBandPrint( NS_SERVER, &from, "statusResponse\n%s\n%s", infostring, status );
 }
 
 /*
@@ -407,7 +408,7 @@
 		Info_SetValueForKey( infostring, "game", gamedir );
 	}
 
-	NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
+	NET_OutOfBandPrint( NS_SERVER, &from, "infoResponse\n%s", infostring );
 }
 
 /*
@@ -417,7 +418,7 @@
 ================
 */
 void SV_FlushRedirect( char *outputbuf ) {
-	NET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, "print\n%s", outputbuf );
+	NET_OutOfBandPrint( NS_SERVER, &svs.redirectAddress, "print\n%s", outputbuf );
 }
 
 /*
@@ -450,10 +451,10 @@
 	if ( !strlen( sv_rconPassword->string ) ||
 		strcmp (Cmd_Argv(1), sv_rconPassword->string) ) {
 		valid = qfalse;
-		Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) );
+		Com_Printf("Bad rcon from %s:\n%s\n", from.sys, Cmd_Argv(2));
 	} else {
 		valid = qtrue;
-		Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) );
+		Com_Printf("Rcon from %s:\n%s\n", from.sys, Cmd_Argv(2));
 	}
 
 	// start redirecting all print outputs to the packet
@@ -514,7 +515,7 @@
 	Cmd_TokenizeString( s );
 
 	c = Cmd_Argv(0);
-	Com_DPrintf ("SV packet %s : %s\n", NET_AdrToString(from), c);
+	Com_DPrintf("SV packet %s : %s\n", from.sys, c);
 
 	if (!Q_stricmp(c, "getstatus")) {
 		SVC_Status( from  );
@@ -534,7 +535,7 @@
 		// sequenced messages to the old client
 	} else {
 		Com_DPrintf ("bad connectionless packet from %s:\n%s\n"
-		, NET_AdrToString (from), s);
+		, from.sys, s);
 	}
 }
 
@@ -567,9 +568,8 @@
 		if (cl->state == CS_FREE) {
 			continue;
 		}
-		if ( !NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) ) {
+		if(!NET_CompareBaseAdr(&from, &cl->netchan.remoteAddress))
 			continue;
-		}
 		// it is possible to have multiple clients from a single IP
 		// address, so they are differentiated by the qport variable
 		if (cl->netchan.qport != qport) {
@@ -579,9 +579,9 @@
 		// the IP port can't be used to differentiate them, because
 		// some address translating routers periodically change UDP
 		// port assignments
-		if (cl->netchan.remoteAddress.port != from.port) {
+		if(strcmp(cl->netchan.remoteAddress.srv, from.srv) != 0){
 			Com_Printf( "SV_PacketEvent: fixing up a translated port\n" );
-			cl->netchan.remoteAddress.port = from.port;
+			memcpy(&cl->netchan.remoteAddress, &from, sizeof from);
 		}
 
 		// make sure it is a valid, in sequence packet
@@ -599,7 +599,7 @@
 	
 	// if we received a sequenced packet from an address we don't recognize,
 	// send an out of band disconnect packet to it
-	NET_OutOfBandPrint( NS_SERVER, from, "disconnect" );
+	NET_OutOfBandPrint( NS_SERVER, &from, "disconnect" );
 }
 
 
--- a/code/server/sv_snapshot.c
+++ b/code/server/sv_snapshot.c
@@ -569,7 +569,7 @@
 	// local clients get snapshots every 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)) ) {
+	if ( client->netchan.remoteAddress.type == NA_LOOPBACK || (sv_lanForceRate->integer && Sys_IsLANAddress (&client->netchan.remoteAddress)) ) {
 		client->nextSnapshotTime = svs.time - 1;
 		return;
 	}
--- /dev/null
+++ b/code/unix/qk3.c
@@ -1,0 +1,21 @@
+#include "../game/q_shared.h"
+#include "../qcommon/qcommon.h"
+#include "../renderer/tr_public.h"
+#include "../client/client.h"
+
+#include <thread.h>
+
+mainstacksize = 256*1024;
+
+int svonly;
+
+void
+NET_Sleep(int)
+{
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	/* FIXME */
+}
--- a/code/unix/qk3ded.c
+++ b/code/unix/qk3ded.c
@@ -5,15 +5,24 @@
 
 #include <thread.h>
 
-void *
-emalloc(ulong n)
+mainstacksize = 256*1024;
+
+extern Channel *echan;
+
+int svonly = 1;
+
+void
+NET_Sleep(int n)
 {
-	void *p;
+	netadr_t *a;
 
-	if((p = mallocz(n, 1)) == nil)
-		sysfatal("emalloc %r");
-	setmalloctag(p, getcallerpc(&n));
-	return p;
+	if(nbrecv(echan, nil) == 0){
+		for(a=cons; a<cons+nelem(cons); a++)
+			if(a->fd >= 0 && flen(a->fd) > 0)
+				break;
+		if(a == cons + nelem(cons))	
+			sleep(n);
+	}
 }
 
 static void
--- /dev/null
+++ b/code/unix/sys.c
@@ -1,0 +1,51 @@
+#include "../game/q_shared.h"
+#include "../qcommon/qcommon.h"
+
+int
+Sys_Milliseconds(void)
+{
+	static vlong T;
+
+	if(T == 0)
+		T = nsec();
+	return (nsec() - T) / 1000000;
+}
+
+int
+Sys_Mkdir(char *path)
+{
+	int fd;
+
+	if(access(path, AEXIST) == 0)
+		return 0;
+	if((fd = create(path, OREAD, DMDIR|0777)) < 0){
+		fprint(2, "mkdir: %r\n");
+		return -1;
+	}
+	close(fd);
+	return 0;
+}
+
+void *
+emalloc(ulong n)
+{
+	void *p;
+
+	if((p = mallocz(n, 1)) == nil)
+		sysfatal("emalloc %r");
+	setmalloctag(p, getcallerpc(&n));
+	return p;
+}
+
+vlong
+flen(int fd)
+{
+	vlong l;
+	Dir *d;
+
+	if((d = dirfstat(fd)) == nil)	/* file assumed extant and readable */ 
+		sysfatal("flen: %r");
+	l = d->length;
+	free(d);
+	return l;
+}
--- a/code/unix/unix_net.c
+++ b/code/unix/unix_net.c
@@ -24,476 +24,199 @@
 #include "../game/q_shared.h"
 #include "../qcommon/qcommon.h"
 
-static cvar_t	*noudp;
+#include <thread.h>
 
-int			ip_socket;
-int			ipx_socket;
+Channel *echan, *lchan;
+netadr_t *net_from, cons[2*MAX_CLIENTS];
 
-#define	MAX_IPS		16
-static	int		numIP;
-static	byte	localIP[MAX_IPS][4];
+static char *netmtpt = "/net";
+static int afd = -1, lpid;
 
-int NET_Socket (char *net_interface, int port);
-char *NET_ErrorString (void);
-
-//=============================================================================
-
-void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s)
+char	*NET_BaseAdrToString (netadr_t *a)
 {
-	memset (s, 0, sizeof(*s));
-
-	if (a->type == NA_BROADCAST)
-	{
-		s->sin_family = AF_INET;
-
-		s->sin_port = a->port;
-		*(int *)&s->sin_addr = -1;
-	}
-	else if (a->type == NA_IP)
-	{
-		s->sin_family = AF_INET;
-
-		*(int *)&s->sin_addr = *(int *)&a->ip;
-		s->sin_port = a->port;
-	}
+	return a->addr;
 }
 
-void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a)
+qboolean
+Sys_StringToAdr(char *s, netadr_t *a)
 {
-	*(int *)&a->ip = *(int *)&s->sin_addr;
-	a->port = s->sin_port;
-	a->type = NA_IP;
-}
+	int fd, n;
+	char buf[128], *f[4], *p;
 
-char	*NET_BaseAdrToString (netadr_t a)
-{
-	static	char	s[64];
-	
-	Com_sprintf (s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
-
-	return s;
-}
-
-/*
-=============
-Sys_StringToAdr
-
-idnewt
-192.246.40.70
-=============
-*/
-qboolean	Sys_StringToSockaddr (const char *s, struct sockaddr *sadr)
-{
-	struct hostent	*h;
-	//char	*colon; // bk001204 - unused
-	
-	memset (sadr, 0, sizeof(*sadr));
-	((struct sockaddr_in *)sadr)->sin_family = AF_INET;
-	
-	((struct sockaddr_in *)sadr)->sin_port = 0;
-	
-	if ( s[0] >= '0' && s[0] <= '9')
-	{
-		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(s);
-	}
+	snprint(buf, sizeof buf, "%s/cs", netmtpt);
+	if((fd = open(buf, ORDWR)) < 0)
+		sysfatal("open: %r");
+	if((p = strrchr(s, '!')) == nil && (p = strrchr(s, ':')) == nil)
+		p = "27960";
 	else
-	{
-		if (! (h = gethostbyname(s)) )
-			return qfalse;
-		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
+		p++;
+	snprint(buf, sizeof buf, "udp!%s!%s", s, p);
+	n = strlen(buf);
+	if(write(fd, buf, n) != n){
+		fprint(2, "translating %s: %r\n", s);
+		return -1;
 	}
-	
-	return qtrue;
-}
-
-/*
-=============
-Sys_StringToAdr
-
-localhost
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-=============
-*/
-qboolean	Sys_StringToAdr (const char *s, netadr_t *a)
-{
-	struct sockaddr_in sadr;
-	
-	if (!Sys_StringToSockaddr (s, (struct sockaddr *)&sadr))
-		return qfalse;
-	
-	SockadrToNetadr (&sadr, a);
-
-	return qtrue;
-}
-
-
-//=============================================================================
-
-qboolean	Sys_GetPacket (netadr_t *net_from, msg_t *net_message)
-{
-	int 	ret;
-	struct sockaddr_in	from;
-	int		fromlen;
-	int		net_socket;
-	int		protocol;
-	int		err;
-
-	for (protocol = 0 ; protocol < 2 ; protocol++)
-	{
-		if (protocol == 0)
-			net_socket = ip_socket;
-		else
-			net_socket = ipx_socket;
-
-		if (!net_socket)
-			continue;
-
-		fromlen = sizeof(from);
-		ret = recvfrom (net_socket, net_message->data, net_message->maxsize
-			, 0, (struct sockaddr *)&from, &fromlen);
-
-		SockadrToNetadr (&from, net_from);
-		// bk000305: was missing
-		net_message->readcount = 0;
-
-		if (ret == -1)
-		{
-			err = errno;
-
-			if (err == EWOULDBLOCK || err == ECONNREFUSED)
-				continue;
-			Com_Printf ("NET_GetPacket: %s from %s\n", NET_ErrorString(),
-						NET_AdrToString(*net_from));
-			continue;
-		}
-
-		if (ret == net_message->maxsize)
-		{
-			Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
-			continue;
-		}
-
-		net_message->cursize = ret;
-		return qtrue;
+	seek(fd, 0, 0);
+	if((n = read(fd, buf, sizeof(buf)-1)) <= 0){
+		fprint(2, "reading cs tables: %r");
+		return -1;
 	}
-
+	buf[n] = 0;
+	close(fd);
+	if(getfields(buf, f, 4, 0, " !") < 2)
+		goto err;
+	memset(a, 0, sizeof *a);
+	strncpy(a->addr, f[1], sizeof(a->addr)-1);
+	strncpy(a->srv, f[2], sizeof(a->srv)-1);
+	snprint(a->sys, sizeof a->sys, "%s!%s", f[1], f[2]);
+	return qtrue;
+err:
+	fprint(2, "bad cs entry %s", buf);
 	return qfalse;
 }
 
-//=============================================================================
-
-void	Sys_SendPacket( int length, const void *data, netadr_t to )
+static void
+getinfo(netadr_t *a)
 {
-	int		ret;
-	struct sockaddr_in	addr;
-	int		net_socket;
+	NetConnInfo *nc;
 
-	if (to.type == NA_BROADCAST)
-	{
-		net_socket = ip_socket;
-	}
-	else if (to.type == NA_IP)
-	{
-		net_socket = ip_socket;
-	}
-	else if (to.type == NA_IPX)
-	{
-		net_socket = ipx_socket;
-	}
-	else if (to.type == NA_BROADCAST_IPX)
-	{
-		net_socket = ipx_socket;
-	}
-	else {
-		Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
+	if((nc = getnetconninfo(nil, a->fd)) == nil){
+		fprint(2, "getnetconninfo: %r\n");
 		return;
 	}
-
-	if (!net_socket)
-		return;
-
-	NetadrToSockadr (&to, &addr);
-
-	ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) );
-	if (ret == -1)
-	{
-		Com_Printf ("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(),
-				NET_AdrToString (to));
-	}
+	strncpy(a->addr, nc->raddr, sizeof(a->addr)-1);
+	strncpy(a->srv, nc->rserv, sizeof(a->srv)-1);
+	snprint(a->sys, sizeof a->sys, "%s!%s", a->addr, a->srv);
+	free(nc);
 }
 
+qboolean
+Sys_GetPacket(msg_t *net_message)
+{
+	int n, fd;
+	netadr_t *a;
 
-//=============================================================================
-
-/*
-==================
-Sys_IsLANAddress
-
-LAN clients will have their rate var ignored
-==================
-*/
-qboolean	Sys_IsLANAddress (netadr_t adr) {
-	int		i;
-
-	if( adr.type == NA_LOOPBACK ) {
-		return qtrue;
+	if(svonly && nbrecv(lchan, &fd) > 0){
+		for(a=cons; a<cons+nelem(cons); a++)
+			if(a->fd < 0)
+				break;
+		if(a == cons + nelem(cons)){
+			close(fd);
+			return qfalse;
+		}
+		a->fd = fd;
+		getinfo(a);
+	}else{
+		for(a=cons; a<cons+nelem(cons); a++)
+			if(a->fd >= 0 && flen(a->fd) > 0)
+				break;
+		if(a == cons + nelem(cons))
+			return qfalse;
 	}
-
-	if( adr.type == NA_IPX ) {
-		return qtrue;
-	}
-
-	if( adr.type != NA_IP ) {
+	net_message->readcount = 0;
+	if((n = read(a->fd, net_message->data, net_message->maxsize)) <= 0){
+		fprint(2, "read: %r\n");
 		return qfalse;
 	}
-
-	// choose which comparison to use based on the class of the address being tested
-	// any local adresses of a different class than the address being tested will fail based on the first byte
-
-	// Class A
-	if( (adr.ip[0] & 0x80) == 0x00 ) {
-		for ( i = 0 ; i < numIP ; i++ ) {
-			if( adr.ip[0] == localIP[i][0] ) {
-				return qtrue;
-			}
-		}
-		// the RFC1918 class a block will pass the above test
+	if(n == net_message->maxsize){
+		Com_Printf("Oversize packet from %s\n", a->sys);
 		return qfalse;
 	}
-
-	// Class B
-	if( (adr.ip[0] & 0xc0) == 0x80 ) {
-		for ( i = 0 ; i < numIP ; i++ ) {
-			if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] ) {
-				return qtrue;
-			}
-			// also check against the RFC1918 class b blocks
-			if( adr.ip[0] == 172 && localIP[i][0] == 172 && (adr.ip[1] & 0xf0) == 16 && (localIP[i][1] & 0xf0) == 16 ) {
-				return qtrue;
-			}
-		}
-		return qfalse;
-	}
-
-	// Class C
-	for ( i = 0 ; i < numIP ; i++ ) {
-		if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] && adr.ip[2] == localIP[i][2] ) {
-			return qtrue;
-		}
-		// also check against the RFC1918 class c blocks
-		if( adr.ip[0] == 192 && localIP[i][0] == 192 && adr.ip[1] == 168 && localIP[i][1] == 168 ) {
-			return qtrue;
-		}
-	}
-	return qfalse;
+	net_message->cursize = n;
+	net_from = a;
+	return qtrue;
 }
 
-/*
-==================
-Sys_ShowIP
-==================
-*/
-void Sys_ShowIP(void) {
-	int i;
+void
+Sys_SendPacket(int length, void *data, netadr_t *to)
+{
+	netadr_t *a;
 
-	for (i = 0; i < numIP; i++) {
-		Com_Printf( "IP: %i.%i.%i.%i\n", localIP[i][0], localIP[i][1], localIP[i][2], localIP[i][3] );
-	}
-}
-
-/*
-=====================
-NET_GetLocalAddress
-=====================
-*/
-void NET_GetLocalAddress( void ) {
-	char				hostname[256];
-	struct hostent		*hostInfo;
-	// int					error; // bk001204 - unused
-	char				*p;
-	int					ip;
-	int					n;
-
-	if ( gethostname( hostname, 256 ) == -1 ) {
+	if(to->type != NA_IP && to->type != NA_BROADCAST){
+		Com_Error(ERR_FATAL, "NET_SendPacket: bad address type");
 		return;
 	}
-
-	hostInfo = gethostbyname( hostname );
-	if ( !hostInfo ) {
+	for(a=cons; a<cons+nelem(cons); a++)
+		if(strcmp(a->sys, to->sys) == 0 || a->fd < 0)
+			break;
+	if(a == cons + nelem(cons))
 		return;
+	else if(a->fd < 0){
+		memcpy(a, to, sizeof *a);
+		if((a->fd = dial(netmkaddr(a->addr, "udp", a->srv), nil, nil, nil)) < 0){
+			fprint(2, "dial: %r\n");
+			return;
+		}
 	}
-
-	Com_Printf( "Hostname: %s\n", hostInfo->h_name );
-	n = 0;
-	while( ( p = hostInfo->h_aliases[n++] ) != NULL ) {
-		Com_Printf( "Alias: %s\n", p );
+	if(write(a->fd, data, length) != length){
+		fprint(2, "write: %r\n");
+		Com_Printf("NET_SendPacket %s: ERROR\n", to->sys);
 	}
-
-	if ( hostInfo->h_addrtype != AF_INET ) {
-		return;
-	}
-
-	numIP = 0;
-	while( ( p = hostInfo->h_addr_list[numIP++] ) != NULL && numIP < MAX_IPS ) {
-		ip = ntohl( *(int *)p );
-		localIP[ numIP ][0] = p[0];
-		localIP[ numIP ][1] = p[1];
-		localIP[ numIP ][2] = p[2];
-		localIP[ numIP ][3] = p[3];
-		Com_Printf( "IP: %i.%i.%i.%i\n", ( ip >> 24 ) & 0xff, ( ip >> 16 ) & 0xff, ( ip >> 8 ) & 0xff, ip & 0xff );
-	}
 }
 
-/*
-====================
-NET_OpenIP
-====================
-*/
-// bk001204 - prototype needed
-int NET_IPSocket (char *net_interface, int port);
-void NET_OpenIP (void)
+qboolean
+Sys_IsLANAddress(netadr_t *a)
 {
-	cvar_t	*ip;
-	int		port;
-	int		i;
-
-	ip = Cvar_Get ("net_ip", "localhost", 0);
-
-	port = Cvar_Get("net_port", va("%i", PORT_SERVER), 0)->value;
-
-	for ( i = 0 ; i < 10 ; i++ ) {
-		ip_socket = NET_IPSocket (ip->string, port + i);
-		if ( ip_socket ) {
-			Cvar_SetValue( "net_port", port + i );
-			NET_GetLocalAddress();
-			return;
-		}
-	}
-	Com_Error (ERR_FATAL, "Couldn't allocate IP port");
+	if(a->type == NA_LOOPBACK)
+		return qtrue;
+	return qfalse;
 }
 
-
-/*
-====================
-NET_Init
-====================
-*/
-void NET_Init (void)
+void
+Sys_ShowIP(void)
 {
-	noudp = Cvar_Get ("net_noudp", "0", 0);
-	// open sockets
-	if (! noudp->value) {
-		NET_OpenIP ();
-	}
 }
 
-
-/*
-====================
-NET_IPSocket
-====================
-*/
-int NET_IPSocket (char *net_interface, int port)
+void
+NET_Shutdown(void)
 {
-	int newsocket;
-	struct sockaddr_in address;
-	qboolean _qtrue = qtrue;
-	int	i = 1;
+	netadr_t *a;
 
-	if ( net_interface ) {
-		Com_Printf("Opening IP socket: %s:%i\n", net_interface, port );
-	} else {
-		Com_Printf("Opening IP socket: localhost:%i\n", port );
-	}
-
-	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
-	{
-		Com_Printf ("ERROR: UDP_OpenSocket: socket: %s", NET_ErrorString());
-		return 0;
-	}
-
-	// make it non-blocking
-	if (ioctl (newsocket, FIONBIO, &_qtrue) == -1)
-	{
-		Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString());
-		return 0;
-	}
-
-	// make it broadcast capable
-	if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
-	{
-		Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString());
-		return 0;
-	}
-
-	if (!net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost"))
-		address.sin_addr.s_addr = INADDR_ANY;
-	else
-		Sys_StringToSockaddr (net_interface, (struct sockaddr *)&address);
-
-	if (port == PORT_ANY)
-		address.sin_port = 0;
-	else
-		address.sin_port = htons((short)port);
-
-	address.sin_family = AF_INET;
-
-	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
-	{
-		Com_Printf ("ERROR: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
-		close (newsocket);
-		return 0;
-	}
-
-	return newsocket;
+	for(a=cons; a<cons+nelem(cons); a++)
+		if(a->fd >= 0){
+			close(a->fd);
+			a->fd = -1;
+		}
+	if(afd < 0)
+		return;
+	close(afd);
+	threadkill(lpid);
+	afd = -1;
 }
 
-/*
-====================
-NET_Shutdown
-====================
-*/
-void	NET_Shutdown (void)
+static void
+lproc(void *)
 {
-	if (ip_socket) {
-		close(ip_socket);
-		ip_socket = 0;
+	int fd, lfd;
+	char adir[40], ldir[40], data[100];
+	cvar_t *port;
+
+	port = Cvar_Get("net_port", "27960", 0);
+	snprint(data, sizeof data, "%s/udp!*!%d", netmtpt, (int)port->value);
+	if((afd = announce(data, adir)) < 0)
+		sysfatal("announce: %r");
+	for(;;){
+		if((lfd = listen(adir, ldir)) < 0
+		|| (fd = accept(lfd, ldir)) < 0)
+			break;
+		close(lfd);
+		send(echan, nil);
+		send(lchan, &fd);
 	}
 }
 
-
-/*
-====================
-NET_ErrorString
-====================
-*/
-char *NET_ErrorString (void)
+void NET_Init (void)
 {
-	int		code;
+	netadr_t *a;
 
-	code = errno;
-	return strerror (code);
-}
+	/* FIXME: configure netmtpt */
 
-// sleeps msec or until net socket is ready
-void NET_Sleep(int msec)
-{
-    struct timeval timeout;
-	fd_set	fdset;
-	extern qboolean stdin_active;
-
-	if (!ip_socket || !com_dedicated->integer)
-		return; // we're not a server, just run full speed
-
-	FD_ZERO(&fdset);
-	if (stdin_active)
-		FD_SET(0, &fdset); // stdin is processed too
-	FD_SET(ip_socket, &fdset); // network socket
-	timeout.tv_sec = msec/1000;
-	timeout.tv_usec = (msec%1000)*1000;
-	select(ip_socket+1, &fdset, NULL, NULL, &timeout);
+	if(svonly && afd < 0){
+		if((lchan = chancreate(sizeof(int), 0)) == nil)
+			sysfatal("chancreate: %r");
+		if((lpid = proccreate(lproc, nil, 8192)) < 0)
+			sysfatal("proccreate lproc: %r");
+	}
+	for(a=cons; a<cons+nelem(cons); a++)
+		a->fd = -1;
 }
-
--- a/code/unix/unix_shared.c
+++ b/code/unix/unix_shared.c
@@ -19,15 +19,6 @@
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 ===========================================================================
 */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <pwd.h>
 
 #include "../game/q_shared.h"
 #include "../qcommon/qcommon.h"
@@ -43,211 +34,57 @@
 // Used to determine where to store user-specific files
 static char homePath[MAX_OSPATH];
 
-/*
-================
-Sys_Milliseconds
-================
-*/
-/* base time in seconds, that's our origin
-   timeval:tv_sec is an int: 
-   assuming this wraps every 0x7fffffff - ~68 years since the Epoch (1970) - we're safe till 2038
-   using unsigned long data type to work right with Sys_XTimeToSysTime */
-unsigned long sys_timeBase = 0;
-/* current time in ms, using sys_timeBase as origin
-   NOTE: sys_timeBase*1000 + curtime -> ms since the Epoch
-     0x7fffffff ms - ~24 days
-   although timeval:tv_usec is an int, I'm not sure wether it is actually used as an unsigned int
-     (which would affect the wrap period) */
-int curtime;
-int Sys_Milliseconds (void)
-{
-	struct timeval tp;
-
-	gettimeofday(&tp, NULL);
-	
-	if (!sys_timeBase)
-	{
-		sys_timeBase = tp.tv_sec;
-		return tp.tv_usec/1000;
-	}
-
-	curtime = (tp.tv_sec - sys_timeBase)*1000 + tp.tv_usec/1000;
-	
-	return curtime;
-}
-
-#if defined(__linux__) && !defined(DEDICATED)
-/*
-================
-Sys_XTimeToSysTime
-sub-frame timing of events returned by X
-X uses the Time typedef - unsigned long
-disable with in_subframe 0
-
- sys_timeBase*1000 is the number of ms since the Epoch of our origin
- xtime is in ms and uses the Epoch as origin
-   Time data type is an unsigned long: 0xffffffff ms - ~49 days period
- I didn't find much info in the XWindow documentation about the wrapping
-   we clamp sys_timeBase*1000 to unsigned long, that gives us the current origin for xtime
-   the computation will still work if xtime wraps (at ~49 days period since the Epoch) after we set sys_timeBase
-
-================
-*/
-extern cvar_t *in_subframe;
-int Sys_XTimeToSysTime (unsigned long xtime)
-{
-	int ret, time, test;
-	
-	if (!in_subframe->value)
-	{
-		// if you don't want to do any event times corrections
-		return Sys_Milliseconds();
-	}
-
-	// test the wrap issue
-#if 0	
-	// reference values for test: sys_timeBase 0x3dc7b5e9 xtime 0x541ea451 (read these from a test run)
-	// xtime will wrap in 0xabe15bae ms >~ 0x2c0056 s (33 days from Nov 5 2002 -> 8 Dec)
-	//   NOTE: date -d '1970-01-01 UTC 1039384002 seconds' +%c
-	// use sys_timeBase 0x3dc7b5e9+0x2c0056 = 0x3df3b63f
-	// after around 5s, xtime would have wrapped around
-	// we get 7132, the formula handles the wrap safely
-	unsigned long xtime_aux,base_aux;
-	int test;
-//	Com_Printf("sys_timeBase: %p\n", sys_timeBase);
-//	Com_Printf("xtime: %p\n", xtime);
-	xtime_aux = 500; // 500 ms after wrap
-	base_aux = 0x3df3b63f; // the base a few seconds before wrap
-	test = xtime_aux - (unsigned long)(base_aux*1000);
-	Com_Printf("xtime wrap test: %d\n", test);
-#endif
-
-  // some X servers (like suse 8.1's) report weird event times
-  // if the game is loading, resolving DNS, etc. we are also getting old events
-  // so we only deal with subframe corrections that look 'normal'
-  ret = xtime - (unsigned long)(sys_timeBase*1000);
-  time = Sys_Milliseconds();
-  test = time - ret;
-  //printf("delta: %d\n", test);
-  if (test < 0 || test > 30) // in normal conditions I've never seen this go above
-  {
-    return time;
-  }
-
-	return ret;
-}
-#endif
-
-//#if 0 // bk001215 - see snapvector.nasm for replacement
-#if (defined __APPLE__) // rcg010206 - using this for PPC builds...
-long fastftol( float f ) { // bk001213 - from win32/win_shared.c
-  //static int tmp;
-  //	__asm fld f
-  //__asm fistp tmp
-  //__asm mov eax, tmp
-  return (long)f;
-}
-
-void Sys_SnapVector( float *v ) { // bk001213 - see win32/win_shared.c
-  // bk001213 - old linux
-  v[0] = rint(v[0]);
-  v[1] = rint(v[1]);
-  v[2] = rint(v[2]);
-}
-#endif
-
-
-void	Sys_Mkdir( const char *path )
+//============================================
+
+#define	MAX_FOUND_FILES	0x1000
+
+static void
+Sys_ListFilteredFiles(char *basedir, char *subdirs, char *filter, char **list, int *numfiles)
 {
-    mkdir (path, 0777);
-}
+	char search[MAX_OSPATH], newsubdirs[MAX_OSPATH], filename[MAX_OSPATH];
+	int fd, i, n;
+	Dir *d;
 
-char *strlwr (char *s) {
-  if ( s==NULL ) { // bk001204 - paranoia
-    assert(0);
-    return s;
-  }
-  while (*s) {
-    *s = tolower(*s);
-    s++;
-  }
-  return s; // bk001204 - duh
-}
-
-//============================================
-
-#define	MAX_FOUND_FILES	0x1000
-
-// bk001129 - new in 1.26
-void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles ) {
-	char		search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
-	char		filename[MAX_OSPATH];
-	DIR			*fdir;
-	struct dirent *d;
-	struct stat st;
-
-	if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
+	if(*numfiles >= MAX_FOUND_FILES - 1)
 		return;
-	}
-
-	if (strlen(subdirs)) {
-		Com_sprintf( search, sizeof(search), "%s/%s", basedir, subdirs );
-	}
-	else {
-		Com_sprintf( search, sizeof(search), "%s", basedir );
-	}
-
-	if ((fdir = opendir(search)) == NULL) {
+	if(strlen(subdirs))
+		Com_sprintf(search, sizeof search, "%s/%s", basedir, subdirs);
+	else
+		Com_sprintf(search, sizeof search, "%s", basedir);
+	if((fd = open(search, OREAD)) < 0)
 		return;
-	}
-
-	while ((d = readdir(fdir)) != NULL) {
-		Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name);
-		if (stat(filename, &st) == -1)
-			continue;
-
-		if (st.st_mode & S_IFDIR) {
-			if (Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..")) {
-				if (strlen(subdirs)) {
-					Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s/%s", subdirs, d->d_name);
-				}
-				else {
-					Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", d->d_name);
-				}
-				Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
-			}
+	n = dirreadall(fd, &d);
+	close(fd);
+	if(n < 0)
+		return;
+	for(i=0; i<n; i++){
+		if(d[i].mode & DMDIR){
+			if(strlen(subdirs) != 0)
+				Com_sprintf(newsubdirs, sizeof newsubdirs, "%s/%s", subdirs, d[i].name);
+			else
+				Com_sprintf(newsubdirs, sizeof newsubdirs, "%s", d[i].name);
+			Sys_ListFilteredFiles(basedir, newsubdirs, filter, list, numfiles);
 		}
-		if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
+		if(*numfiles >= MAX_FOUND_FILES-1)
 			break;
-		}
-		Com_sprintf( filename, sizeof(filename), "%s/%s", subdirs, d->d_name );
-		if (!Com_FilterPath( filter, filename, qfalse ))
+		Com_sprintf(filename, sizeof filename, "%s/%s", subdirs, d[i].name);
+		if(!Com_FilterPath(filter, filename, qfalse))
 			continue;
-		list[ *numfiles ] = CopyString( filename );
+		list[*numfiles] = CopyString(filename);
 		(*numfiles)++;
 	}
-
-	closedir(fdir);
 }
 
-// bk001129 - in 1.17 this used to be
-// char **Sys_ListFiles( const char *directory, const char *extension, int *numfiles, qboolean wantsubs )
-char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs )
+char **
+Sys_ListFiles(char *directory, char *extension, char *filter, int *numfiles, qboolean wantsubs)
 {
-	struct dirent *d;
-	// char *p; // bk001204 - unused
-	DIR		*fdir;
 	qboolean dironly = wantsubs;
-	char		search[MAX_OSPATH];
 	int			nfiles;
 	char		**listCopy;
 	char		*list[MAX_FOUND_FILES];
-	//int			flag; // bk001204 - unused
-	int			i;
-	struct stat st;
+	int fd, i, n, extLen;
+	Dir *d;
 
-	int			extLen;
-
 	if (filter) {
 
 		nfiles = 0;
@@ -281,38 +118,30 @@
 	// search
 	nfiles = 0;
 
-	if ((fdir = opendir(directory)) == NULL) {
-		*numfiles = 0;
-		return NULL;
-	}
-
-	while ((d = readdir(fdir)) != NULL) {
-		Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name);
-		if (stat(search, &st) == -1)
+	if((fd = open(directory, OREAD)) < 0)
+		goto err;
+	n = dirreadall(fd, &d);
+	close(fd);
+	if(n < 0)
+		goto err;
+	for(i=0; i<n; i++){
+		if(dironly ^ d[i].mode & DMDIR)
 			continue;
-		if ((dironly && !(st.st_mode & S_IFDIR)) ||
-			(!dironly && (st.st_mode & S_IFDIR)))
-			continue;
 
 		if (*extension) {
-			if ( strlen( d->d_name ) < strlen( extension ) ||
-				Q_stricmp( 
-					d->d_name + strlen( d->d_name ) - strlen( extension ),
-					extension ) ) {
+			if(strlen(d[i].name) < strlen(extension)
+			|| Q_stricmp(d[i].name + strlen(d[i].name) - strlen(extension), extension))
 				continue; // didn't match
-			}
 		}
 
 		if ( nfiles == MAX_FOUND_FILES - 1 )
 			break;
-		list[ nfiles ] = CopyString( d->d_name );
+		list[ nfiles ] = CopyString( d[i].name );
 		nfiles++;
 	}
 
 	list[ nfiles ] = 0;
 
-	closedir(fdir);
-
 	// return a copy of the list
 	*numfiles = nfiles;
 
@@ -327,6 +156,9 @@
 	listCopy[i] = NULL;
 
 	return listCopy;
+err:
+	*numfiles = 0;
+	return NULL;
 }
 
 void	Sys_FreeFileList( char **list ) {
@@ -347,7 +179,7 @@
 {
 	static char cwd[MAX_OSPATH];
 
-	getcwd( cwd, sizeof( cwd ) - 1 );
+	getwd(cwd, sizeof(cwd) - 1);
 	cwd[MAX_OSPATH-1] = 0;
 
 	return cwd;
@@ -388,17 +220,12 @@
         if (*homePath)
             return homePath;
             
-	if ((p = getenv("HOME")) != NULL) {
+	if ((p = getenv("home")) != NULL) {
 		Q_strncpyz(homePath, p, sizeof(homePath));
-#ifdef MACOS_X
-		Q_strcat(homePath, sizeof(homePath), "/Library/Application Support/Quake3");
-#else
+		free(p);
 		Q_strcat(homePath, sizeof(homePath), "/.q3a");
-#endif
-		if (mkdir(homePath, 0777)) {
-			if (errno != EEXIST) 
-				Sys_Error("Unable to create directory \"%s\", error is %s(%d)\n", homePath, strerror(errno), errno);
-		}
+		if(Sys_Mkdir(homePath) < 0)
+			Sys_Error("Unable to create directory \"%s\"\n", homePath);
 		return homePath;
 	}
 	return ""; // assume current dir
@@ -417,19 +244,10 @@
 
 char *Sys_GetCurrentUser( void )
 {
-	struct passwd *p;
-
-	if ( (p = getpwuid( getuid() )) == NULL ) {
-		return "player";
-	}
-	return p->pw_name;
+	return getuser();
 }
 
-#if defined(__linux__)
-// TTimo 
-// sysconf() in libc, POSIX.1 compliant
 unsigned int Sys_ProcessorCount()
 {
-  return sysconf(_SC_NPROCESSORS_ONLN);
+	return 1;
 }
-#endif