shithub: qk1

Download patch

ref: 373a5aadf3814e5c433787d419a218a9061f5c3d
parent: a4474be05dd2196175875f7333185e7b6c9bd449
author: qwx <>
date: Mon Dec 10 20:40:45 EST 2018

qw: fix networking

- better networking implementation, still a few quirks left to fix
- fix NET_StringToAdr
- announce only when necessary, clean up connections on disconnect
- main loop: poll connections and input or sleep

--- a/qw/cl_main.c
+++ b/qw/cl_main.c
@@ -171,15 +171,12 @@
 
 	t1 = Sys_DoubleTime ();
 
-	if (!NET_StringToAdr (cls.servername, &adr))
+	if (!NET_StringToAdr (cls.servername, &adr, nil))
 	{
 		Con_Printf ("Bad server address\n");
 		connect_time = -1;
 		return;
 	}
-
-	if (adr.port == 0)
-		adr.port = BigShort (27500);
 	t2 = Sys_DoubleTime ();
 
 	connect_time = realtime+t2-t1;	// for retransmit requests
@@ -186,12 +183,12 @@
 
 	cls.qport = Cvar_VariableValue("qport");
 
-	Info_SetValueForStarKey (cls.userinfo, "*ip", NET_AdrToString(adr), MAX_INFO_STRING);
+	Info_SetValueForStarKey (cls.userinfo, "*ip", adr.addr, MAX_INFO_STRING);
 
 //	Con_Printf ("Connecting to %s...\n", cls.servername);
 	sprintf (data, "%c%c%c%cconnect %i %i %i \"%s\"\n",
 		255, 255, 255, 255,	PROTOCOL_VERSION, cls.qport, cls.challenge, cls.userinfo);
-	NET_SendPacket (strlen(data), data, adr);
+	NET_SendPacket (strlen(data), data, &adr);
 }
 
 /*
@@ -216,15 +213,12 @@
 		return;
 
 	t1 = Sys_DoubleTime ();
-	if (!NET_StringToAdr (cls.servername, &adr))
+	if (!NET_StringToAdr (cls.servername, &adr, nil))
 	{
 		Con_Printf ("Bad server address\n");
 		connect_time = -1;
 		return;
 	}
-
-	if (adr.port == 0)
-		adr.port = BigShort (27500);
 	t2 = Sys_DoubleTime ();
 
 	connect_time = realtime+t2-t1;	// for retransmit requests
@@ -231,7 +225,7 @@
 
 	Con_Printf ("Connecting to %s...\n", cls.servername);
 	sprintf (data, "%c%c%c%cgetchallenge\n", 255, 255, 255, 255);
-	NET_SendPacket (strlen(data), data, adr);
+	NET_SendPacket (strlen(data), data, &adr);
 }
 
 void CL_BeginServerConnect(void)
@@ -315,11 +309,10 @@
 
 			return;
 		}
-		NET_StringToAdr (rcon_address.string, &to);
+		NET_StringToAdr (rcon_address.string, &to, nil);
 	}
 	
-	NET_SendPacket (strlen(message)+1, message
-		, to);
+	NET_SendPacket (strlen(message)+1, message, &to);
 }
 
 
@@ -392,6 +385,7 @@
 		Netchan_Transmit (&cls.netchan, 6, final);
 		Netchan_Transmit (&cls.netchan, 6, final);
 		Netchan_Transmit (&cls.netchan, 6, final);
+		NET_Close(&cls.netchan.remote_address);
 
 		cls.state = ca_disconnected;
 
@@ -644,7 +638,7 @@
 		return;
 	}
 
-	if (!NET_StringToAdr (Cmd_Argv(1), &adr))
+	if (!NET_StringToAdr (Cmd_Argv(1), &adr, nil))
 	{
 		Con_Printf ("Bad address\n");
 		return;
@@ -667,7 +661,7 @@
 	}
 	*out = 0;
 
-	NET_SendPacket (out-send, send, adr);
+	NET_SendPacket (out-send, send, &adr);
 }
 
 
@@ -769,7 +763,7 @@
 
 	c = MSG_ReadByte ();
 	if (!cls.demoplayback)
-		Con_Printf ("%s: ", NET_AdrToString (net_from));
+		Con_Printf ("%s: ", net_from->sys);
 //	Con_DPrintf ("%s", net_message.data + 5);
 	if (c == S2C_CONNECTION)
 	{
@@ -794,13 +788,6 @@
 		char	cmdtext[2048];
 
 		Con_Printf ("client command\n");
-
-		if ((*(unsigned *)net_from.ip != *(unsigned *)laddr.ip
-			&& *(unsigned *)net_from.ip != Iploopback) )
-		{
-			Con_Printf ("Command packet from remote host.  Ignored.\n");
-			return;
-		}
 		s = MSG_ReadString ();
 
 		strncpy(cmdtext, s, sizeof(cmdtext) - 1);
@@ -907,7 +894,7 @@
 
 		if (net_message.cursize < 8)
 		{
-			Con_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
+			Con_Printf ("%s: Runt packet\n", net_from->sys);
 			continue;
 		}
 
@@ -915,10 +902,10 @@
 		// packet from server
 		//
 		if (!cls.demoplayback && 
-			!NET_CompareAdr (net_from, cls.netchan.remote_address))
+			!NET_CompareAdr (net_from, &cls.netchan.remote_address))
 		{
 			Con_DPrintf ("%s:sequenced packet without connection\n"
-				,NET_AdrToString(net_from));
+				, net_from->sys);
 			continue;
 		}
 		if (!Netchan_Process(&cls.netchan))
@@ -1353,8 +1340,6 @@
 */
 void Host_Init (quakeparms_t *parms)
 {
-	int p, port;
-
 	COM_InitArgv (parms->argc, parms->argv);
 	COM_AddParm ("-game");
 	COM_AddParm ("qw");
@@ -1376,14 +1361,7 @@
 
 	Host_FixupModelNames();
 
-	port = PORT_CLIENT;
-	p = COM_CheckParm ("-cport");
-	if (p && p < com_argc)
-	{
-		port = atoi(com_argv[p+1]);
-		Con_Printf ("Client port: %i\n", port);
-	}
-	NET_Init (port);
+	NET_Init(0);
 	Netchan_Init ();
 
 	W_LoadWadFile ("gfx.wad");
--- a/qw/in.c
+++ b/qw/in.c
@@ -7,8 +7,6 @@
 #include <keyboard.h>
 #include "quakedef.h"
 
-extern Channel *fuckchan;	/* main fuck receptor */
-
 /* vid_9.c */
 extern int resized;
 extern Point center;
--- a/qw/mkfile
+++ b/qw/mkfile
@@ -6,6 +6,8 @@
 	qwsv\
 
 CLOBJ=\
+	cd.$O\
+	cl_cam.$O\
 	cl_demo.$O\
 	cl_ents.$O\
 	cl_input.$O\
@@ -13,7 +15,6 @@
 	cl_parse.$O\
 	cl_pred.$O\
 	cl_tent.$O\
-	cl_cam.$O\
 	cmd.$O\
 	common.$O\
 	console.$O\
@@ -32,6 +33,7 @@
 	d_vars.$O\
 	d_zpoint.$O\
 	draw.$O\
+	in.$O\
 	keys.$O\
 	mathlib.$O\
 	md4.$O\
@@ -38,9 +40,11 @@
 	menu.$O\
 	model.$O\
 	net_chan.$O\
+	net_udp.$O\
 	nonintel.$O\
 	pmove.$O\
 	pmovetst.$O\
+	qwcl.$O\
 	r_aclip.$O\
 	r_alias.$O\
 	r_bsp.$O\
@@ -58,48 +62,44 @@
 	sbar.$O\
 	screen.$O\
 	skin.$O\
+	snd.$O\
 	snd_dma.$O\
 	snd_mem.$O\
 	snd_mix.$O\
+	sys.$O\
+	vid.$O\
 	view.$O\
 	wad.$O\
 	zone.$O\
-	cd.$O\
-	vid.$O\
-	snd.$O\
-	in.$O\
-	sys.$O\
-	net_udp.$O\
-	qwcl.$O\
 
 SVOBJ=\
+	cmd.$O\
+	common.$O\
+	crc.$O\
+	cvar.$O\
+	mathlib.$O\
+	md4.$O\
+	net_chan.$O\
+	net_udp.$O\
+	pmove.$O\
+	pmovetst.$O\
 	pr_cmds.$O\
 	pr_edict.$O\
 	pr_exec.$O\
+	qwsv.$O\
+	sv_ccmds.$O\
+	sv_ents.$O\
 	sv_init.$O\
 	sv_main.$O\
-	sv_nchan.$O\
-	sv_ents.$O\
-	sv_send.$O\
 	sv_move.$O\
+	sv_nchan.$O\
 	sv_phys.$O\
+	sv_send.$O\
 	sv_user.$O\
-	sv_ccmds.$O\
-	world.$O\
 	svmodel.$O\
-	cmd.$O\
-	common.$O\
-	crc.$O\
-	cvar.$O\
-	mathlib.$O\
-	md4.$O\
-	zone.$O\
-	pmove.$O\
-	pmovetst.$O\
-	net_chan.$O\
 	sys.$O\
-	net_udp.$O\
-	qwsv.$O\
+	world.$O\
+	zone.$O\
 
 HFILES=\
 	../adivtab.h\
--- a/qw/net.h
+++ b/qw/net.h
@@ -4,13 +4,13 @@
 
 typedef struct
 {
-	byte	ip[4];
-	unsigned short	port;
-	unsigned short	pad;
+	int fd;
+	char sys[72];
+	char addr[64];
+	char srv[8];
 } netadr_t;
 
-extern	netadr_t	laddr;
-extern	netadr_t	net_from;		// address of who sent the packet
+extern	netadr_t	*net_from;		// address of who sent the packet
 extern	sizebuf_t	net_message;
 
 extern	cvar_t	hostname;
@@ -20,13 +20,12 @@
 void		NET_Init (int port);
 void		NET_Shutdown (void);
 qboolean	NET_GetPacket (void);
-void		NET_SendPacket (int length, void *data, netadr_t to);
+void		NET_SendPacket (int length, void *data, netadr_t *to);
+void	NET_Close(netadr_t*);
 
-qboolean	NET_CompareAdr (netadr_t a, netadr_t b);
-qboolean	NET_CompareBaseAdr (netadr_t a, netadr_t b);
-char		*NET_AdrToString (netadr_t a);
-char		*NET_BaseAdrToString (netadr_t a);
-qboolean	NET_StringToAdr (char *s, netadr_t *a);
+qboolean	NET_CompareAdr (netadr_t *a, netadr_t *b);
+qboolean	NET_CompareBaseAdr (netadr_t *a, netadr_t *b);
+qboolean	NET_StringToAdr(char*, netadr_t*, char*);
 
 //============================================================================
 
@@ -82,10 +81,10 @@
 
 void Netchan_Init (void);
 void Netchan_Transmit (netchan_t *chan, int length, byte *data);
-void Netchan_OutOfBand (netadr_t adr, int length, byte *data);
-void Netchan_OutOfBandPrint (netadr_t adr, char *format, ...);
+void Netchan_OutOfBand (netadr_t *adr, int length, byte *data);
+void Netchan_OutOfBandPrint (netadr_t *adr, char *format, ...);
 qboolean Netchan_Process (netchan_t *chan);
-void Netchan_Setup (netchan_t *chan, netadr_t adr, int qport);
+void Netchan_Setup (netchan_t *chan, netadr_t *adr, int qport);
 
 qboolean Netchan_CanPacket (netchan_t *chan);
 qboolean Netchan_CanReliable (netchan_t *chan);
--- a/qw/net_chan.c
+++ b/qw/net_chan.c
@@ -85,7 +85,7 @@
 Sends an out-of-band datagram
 ================
 */
-void Netchan_OutOfBand (netadr_t adr, int length, byte *data)
+void Netchan_OutOfBand (netadr_t *adr, int length, byte *data)
 {
 	sizebuf_t	send;
 	byte		send_buf[MAX_MSGLEN + PACKET_HEADER];
@@ -111,7 +111,7 @@
 Sends a text message in an out-of-band datagram
 ================
 */
-void Netchan_OutOfBandPrint (netadr_t adr, char *format, ...)
+void Netchan_OutOfBandPrint (netadr_t *adr, char *format, ...)
 {
 	va_list		argptr;
 	static char		string[8192];		// ??? why static?
@@ -132,11 +132,12 @@
 called to open a channel to a remote system
 ==============
 */
-void Netchan_Setup (netchan_t *chan, netadr_t adr, int qport)
+void Netchan_Setup (netchan_t *chan, netadr_t *adr, int qport)
 {
 	memset (chan, 0, sizeof(*chan));
-	
-	chan->remote_address = adr;
+
+	if(adr != nil)
+		memcpy(&chan->remote_address, adr, sizeof *adr);
 	chan->last_received = realtime;
 	
 	chan->message.data = chan->message_buf;
@@ -202,7 +203,7 @@
 	{
 		chan->fatal_error = true;
 		Con_Printf ("%s:Outgoing message overflow\n"
-			, NET_AdrToString (chan->remote_address));
+			, chan->remote_address.addr);
 		return;
 	}
 
@@ -258,7 +259,7 @@
 
 	//zoid, no input in demo playback mode
 	if(svonly || !cls.demoplayback)
-		NET_SendPacket (send.cursize, send.data, chan->remote_address);
+		NET_SendPacket (send.cursize, send.data, &chan->remote_address);
 
 	if (chan->cleartime < realtime)
 		chan->cleartime = realtime + send.cursize*chan->rate;
@@ -291,7 +292,7 @@
 	unsigned		reliable_ack, reliable_message;
 	int			qport;
 
-	if((svonly || !cls.demoplayback) && !NET_CompareAdr(net_from, chan->remote_address))
+	if((svonly || !cls.demoplayback) && !NET_CompareAdr(net_from, &chan->remote_address))
 		return false;
 
 // get sequence numbers		
@@ -319,35 +320,6 @@
 			, reliable_ack
 			, net_message.cursize);
 
-/* get a rate estimation
-	if (chan->outgoing_sequence - sequence_ack < MAX_LATENT)
-	{
-		int				i;
-		double			time, rate;
-	
-		i = sequence_ack & (MAX_LATENT - 1);
-		time = realtime - chan->outgoing_time[i];
-		time -= 0.1;	// subtract 100 ms
-		if (time <= 0)
-		{	// gotta be a digital link for <100 ms ping
-			if (chan->rate > 1.0/5000)
-				chan->rate = 1.0/5000;
-		}
-		else
-		{
-			if (chan->outgoing_size[i] < 512)
-			{	// only deal with small messages
-				rate = chan->outgoing_size[i]/time;
-				if (rate > 5000)
-					rate = 5000;
-				rate = 1.0/rate;
-				if (chan->rate > rate)
-					chan->rate = rate;
-			}
-		}
-	}
-*/
-
 //
 // discard stale or duplicated packets
 //
@@ -355,7 +327,7 @@
 	{
 		if (showdrop.value)
 			Con_Printf ("%s:Out of order packet %i at %i\n"
-				, NET_AdrToString (chan->remote_address)
+				, chan->remote_address.addr
 				,  sequence
 				, chan->incoming_sequence);
 		return false;
@@ -371,7 +343,7 @@
 
 		if (showdrop.value)
 			Con_Printf ("%s:Dropped %i packets at %i\n"
-			, NET_AdrToString (chan->remote_address)
+			, chan->remote_address.addr
 			, sequence-(chan->incoming_sequence+1)
 			, sequence);
 	}
@@ -406,4 +378,3 @@
 
 	return true;
 }
-
--- a/qw/net_udp.c
+++ b/qw/net_udp.c
@@ -2,345 +2,163 @@
 #include <libc.h>
 #include <stdio.h>
 #include <thread.h>
-#include <bio.h>
-#include <ndb.h>
 #include <ip.h>
 #include "quakedef.h"
 
-extern Channel *fuckchan;	/* main fuck receptor */
-
+Channel *echan, *lchan;
+char *netmtpt = "/net";
 sizebuf_t net_message;
-netadr_t laddr = { .ip{ 192, 168, 1, 138} };		/* 0.0.0.0:0 */
-netadr_t net_from;
+netadr_t *net_from;
+netadr_t cons[2*MAX_CLIENTS];
+static uchar netbuf[8192];
+static int afd = -1, lpid;
 
-typedef struct Conmsg Conmsg;
-typedef struct Conlist Conlist;
-
-enum{
-	Nbuf	= 64,
-	Bufsz	= 8192,
-	Hdrsz	= 16+16+16+2+2,	/* sizeof Udphdr w/o padding */
-};
-static int cfd = -1, ufd = -1;
-static char srv[6];
-static uchar netbuf[Bufsz];
-static Channel *udpchan;
-static QLock cnlock;
-
-struct Conlist{
-	Conlist *p;
-	uchar	u[IPaddrlen+2];
-	char	addr[IPaddrlen*2+8+6];	/* ipv6 + separators + port in decimal */
-	int	dfd;
-	Udphdr	h;
-};
-Conlist *cnroot;
-
-struct Conmsg{
-	Conlist *p;
-	int	n;
-	uchar	buf[Bufsz];
-};
-
-static void	uproc(void *);
-static void	dproc(void *);
-static void	cninit(void);
-static Conlist*	cnins(int, char *, uchar *, Udphdr *);
-static Conlist*	cnfind(char *);
-static void	cndel(Conlist *);
-static void	cnnuke(void);
-
-
-netadr_t	net_from;
-int			net_socket;			// non blocking, for receives
-int			net_send_socket;	// blocking, for sends
-
-
 qboolean
-NET_CompareBaseAdr(netadr_t a, netadr_t b)
+NET_CompareBaseAdr(netadr_t *a, netadr_t *b)
 {
-	return a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3];
+	return strcmp(a->addr, b->addr) == 0;
 }
 
 qboolean
-NET_CompareAdr(netadr_t a, netadr_t b)
+NET_CompareAdr(netadr_t *a, netadr_t *b)
 {
-	return 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;
+	return strcmp(a->sys, b->sys) == 0;
 }
 
-char *
-NET_AdrToString(netadr_t a)
-{
-	static char s[256];
-
-	seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud:%hud", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));
-	return s;
-}
-
-char *
-NET_BaseAdrToString(netadr_t a)
-{
-	static char s[256];
-
-	seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
-	return s;
-}
-
-/*
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-*/
 qboolean
-NET_StringToAdr(char *addr, netadr_t *a)	/* assumes IPv4 */
+NET_StringToAdr(char *s, netadr_t *a, char *port)
 {
-	int i;
-	char s[256], *p, *pp;
-	Ndbtuple *t, *nt;
+	int fd, n;
+	char buf[128], *f[4], *p;
 
-	strncpy(s, addr, sizeof s);
-	s[sizeof(s)-1] = 0;
-
-	/* FIXME: arbitrary length strings: ip.h limit? */
-	if((p = strrchr(s, ':')) != nil){
-		*p++ = '\0';
-		a->port = BigShort(atoi(p));
+	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 = port == nil ? "27500" : port;
+	else
+		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;
 	}
-
-	/* FIXME: sys */
-	if(strcmp(ipattr(s), "dom") == 0){
-		if((t = dnsquery(nil, s, "ip")) == nil){
-			fprint(2, "NET_StringToAdr:dnsquery %s: %r\n", s);
-			return 0;
-		}
-
-		for(nt = t; nt != nil; nt = nt->entry)
-			if(!strcmp(nt->attr, "ip")){
-				strncpy(s, nt->val, sizeof(s)-1);
-				break;
-			}	
-		ndbfree(t);
+	seek(fd, 0, 0);
+	if((n = read(fd, buf, sizeof(buf)-1)) <= 0){
+		fprint(2, "reading cs tables: %r");
+		return -1;
 	}
-
-	/* FIXMEGASHIT */
-	for(i = 0, pp = s; i < IPv4addrlen; i++){
-		if((p = strchr(pp, '.')) != nil)
-			*p++ = 0;
-		a->ip[i] = atoi(pp);
-		pp = p;
-	}
+	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 true;
+err:
+	fprint(2, "bad cs entry %s", buf);
+	return false;
 }
 
 static void
-cninit(void)
+getinfo(netadr_t *a)
 {
-	if(cnroot != nil)
-		return;
-	if((cnroot = malloc(sizeof *cnroot)) == nil)
-		sysfatal("cninit:malloc: %r");
-	cnroot->p = cnroot;
-	memset(cnroot->u, 0, sizeof cnroot->u);
-	memset(cnroot->addr, 0, sizeof cnroot->addr);
-	cnroot->dfd = -1;
-}
+	NetConnInfo *nc;
 
-static Conlist *
-cnins(int fd, char *addr, uchar *u, Udphdr *h)
-{
-	Conlist *p, *l;
-
-	l = cnroot;
-	if((p = malloc(sizeof *p)) == nil)
-		sysfatal("cnins:malloc: %r");
-
-	strncpy(p->addr, addr, sizeof p->addr);
-	memcpy(p->u, u, sizeof p->u);
-	p->dfd = fd;
-	if(h != nil)
-		memcpy(&p->h, h, sizeof p->h);
-	p->p = l->p;
-	l->p = p;
-	return p;
-}
-
-static Conlist *
-cnfind(char *raddr)
-{
-	Conlist *p = cnroot->p;
-
-	while(p != cnroot){
-		if(!strncmp(p->addr, raddr, strlen(p->addr)))
-			return p;
-		p = p->p;
+	if((nc = getnetconninfo(nil, a->fd)) == nil){
+		fprint(2, "getnetconninfo: %r\n");
+		return;
 	}
-	return nil;
+	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);
 }
 
-static void
-cndel(Conlist *p)
-{
-	Conlist *l = cnroot;
-
-	while(l->p != p){
-		l = l->p;
-		if(l == cnroot)
-			sysfatal("cndel: bad unlink: cnroot 0x%p node 0x%p\n", cnroot, p);
-	}
-	l->p = p->p;
-	if(p->dfd != ufd && p->dfd != -1)
-		close(p->dfd);
-	free(p);
-}
-
-static void
-cnnuke(void)
-{
-	Conlist *p, *l = cnroot;
-
-	if(cnroot == nil)
-		return;
-	do{
-		p = l;
-		l = l->p;
-		if(p->dfd != -1)
-			close(p->dfd);
-		free(p);
-	}while(l != cnroot);
-	cnroot = nil;
-}
-
 qboolean
 NET_GetPacket(void)
 {
-	int n;
-	Conmsg m;
+	int n, fd;
+	netadr_t *a;
 
-	if(cfd == -1)
+	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 false;
+		}
+		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 false;
+	}
+	if((n = read(a->fd, netbuf, sizeof netbuf)) <= 0){
+		fprint(2, "read: %r\n");
 		return false;
-
-	if((n = nbrecv(udpchan, &m)) < 0)
-		sysfatal("NET_GetPacket:nbrecv: %r");
-	if(n == 0)
-		return false;
-	memcpy(net_from.ip, m.p->u+12, 4);
-	net_from.port = m.p->u[17] << 8 | m.p->u[16];
-	net_message.cursize = m.n;
-	memcpy(netbuf, m.buf, m.n);
-
+	}
+	net_message.cursize = n;
+	net_from = a;
 	return true;
 }
 
 void
-NET_SendPacket(int length, void *data, netadr_t to)
+NET_SendPacket(int length, void *data, netadr_t *to)
 {
-	int fd;
-	char *addr, *s, *lport;
-	uchar b[Bufsz+Hdrsz], u[IPaddrlen+2];
-	Conlist *p;
+	netadr_t *a;
 
-	if(cfd == -1)
+	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;
-
-	addr = NET_AdrToString(to);
-	qlock(&cnlock);
-	p = cnfind(addr);
-	qunlock(&cnlock);
-	if(p != nil){
-		fd = p->dfd;
-		if(fd == ufd){
-			memcpy(b, &p->h, Hdrsz);
-			memcpy(b+Hdrsz, data, length);
-			write(fd, b, length+Hdrsz);
+	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;
-		}else if(write(fd, data, length) != length)
-			sysfatal("NET_SendPacket:write: %r");
-	}else{
-		lport = strrchr(addr, ':');
-		*lport++ = '\0';
-		s = netmkaddr(addr, "udp", lport);
-		if((fd = dial(s, srv, nil, nil)) < 0)
-			sysfatal("NET_SendPacket:dial: %r");
-
-		memcpy(u, v4prefix, sizeof v4prefix);
-		memcpy(u+IPv4off, to.ip, IPv4addrlen);
-		u[16] = to.port;
-		u[17] = to.port >> 8;
-		*(lport-1) = ':';
-		qlock(&cnlock);
-		p = cnins(fd, addr, u, nil);
-		qunlock(&cnlock);
-
-		if(proccreate(dproc, p, 8196*4) < 0)
-			sysfatal("NET_SendPacket:proccreate: %r");
+		}
 	}
-	if(write(fd, data, length) != length)
-		sysfatal("NET_SendPacket:write: %r");
+	if(write(a->fd, data, length) != length)
+		fprint(2, "write: %r\n");
 }
 
-static void
-dproc(void *me)
+void
+NET_Close(netadr_t *to)
 {
-	int n, fd;
-	Conmsg m;
-	Conlist *p;
+	netadr_t *a;
 
-	threadsetgrp(THnet);
-
-	m.p = p = me;
-	fd = p->dfd;
-
-	for(;;){
-		if((n = read(fd, m.buf, sizeof m.buf)) <= 0)
-			break;
-		m.n = n;
-		if(send(udpchan, &m) < 0)
-			sysfatal("uproc:send: %r\n");
-		if(svonly && nbsend(fuckchan, nil) < 0)
-			sysfatal("fuckchan %r\n");
-	}
-	fprint(2, "dproc %d: %r\n", threadpid(threadid()));
-	cndel(me);
+	for(a=cons; a<cons+nelem(cons); a++)
+		if(strcmp(a->sys, to->sys) == 0){
+			close(a->fd);
+			a->fd = -1;
+		}
 }
 
 static void
-uproc(void *)
+lproc(void *port)
 {
-	int n;
-	uchar udpbuf[Bufsz+Hdrsz], u[IPaddrlen+2];
-	char a[IPaddrlen*2+8+6];
-	Udphdr h;
-	Conmsg m;
-	Conlist *p;
+	int fd, lfd;
+	char adir[40], ldir[40], data[100];
 
-	threadsetgrp(THnet);
-
+	snprint(data, sizeof data, "%s/udp!*!%d", netmtpt, *(int *)port);
+	if((afd = announce(data, adir)) < 0)
+		sysfatal("announce: %r");
 	for(;;){
-		if((n = read(ufd, udpbuf, sizeof udpbuf)) <= 0)
-			sysfatal("uproc:read: %r");
-
-		memcpy(&h, udpbuf, Hdrsz);
-		memcpy(u, h.raddr, IPaddrlen);
-		memcpy(u+IPaddrlen, h.rport, 2);
-		snprint(a, sizeof a, "%ud.%ud.%ud.%ud:%hud", u[12], u[13], u[14], u[15], u[16]<<8 | u[17]);
-		qlock(&cnlock);
-		if((p = cnfind(a)) == nil)
-			p = cnins(ufd, a, u, &h);
-		qunlock(&cnlock);
-		m.p = p;
-
-		if(n - Hdrsz < 0){	/* FIXME */
-			m.n = n;
-			memcpy(m.buf, udpbuf, m.n);
-		}else{
-			m.n = n - Hdrsz;
-			memcpy(m.buf, udpbuf+Hdrsz, m.n);
-		}
-		if(send(udpchan, &m) < 0)
-			sysfatal("uproc:send: %r\n");
-		if(svonly && nbsend(fuckchan, nil) < 0)
-			sysfatal("fucking chan refused the fuck: %r\n");
+		if((lfd = listen(adir, ldir)) < 0
+		|| (fd = accept(lfd, ldir)) < 0)
+			break;
+		close(lfd);
+		send(echan, nil);
+		send(lchan, &fd);
 	}
 }
 
@@ -347,25 +165,21 @@
 void
 NET_Init(int port)
 {
-	char data[64], adir[40];
+	int n;
+	netadr_t *a;
 
-	if(cfd != -1)
-		return;
-
-	cninit();
-	snprint(srv, sizeof srv, "%hud", port);
-	if((cfd = announce(netmkaddr("*", "udp", srv), adir)) < 0)
-		sysfatal("announce udp!*!%s: %r", srv);
-	if(fprint(cfd, "headers") < 0)
-		sysfatal("NET_Init: failed to set header mode: %r");
-	snprint(data, sizeof data, "%s/data", adir);
-	if((ufd = open(data, ORDWR)) < 0)
-		sysfatal("open: %r");
-	if((udpchan = chancreate(sizeof(Conmsg), Nbuf)) == nil)
-		sysfatal("chancreate udpchan: %r");
-	if(proccreate(uproc, udpchan, 8192*4) < 0)
-		sysfatal("proccreate: %r");
-
+	n = COM_CheckParm("-net");
+	if(n && n < com_argc-1)
+		if((netmtpt = strdup(com_argv[n+1])) == nil)
+			sysfatal("strdup: %r");
+	if(svonly && afd < 0){
+		if((lchan = chancreate(sizeof(int), 0)) == nil)
+			sysfatal("chancreate: %r");
+		if((lpid = proccreate(lproc, &port, 8192)) < 0)
+			sysfatal("proccreate lproc: %r");
+	}
+	for(a=cons; a<cons+nelem(cons); a++)
+		a->fd = -1;	
 	net_message.maxsize = sizeof netbuf;
 	net_message.data = netbuf;
 }
@@ -373,18 +187,16 @@
 void
 NET_Shutdown(void)
 {
-	threadkillgrp(THnet);
-	cnnuke();
-	if(udpchan != nil){
-		chanfree(udpchan);
-		udpchan = nil;
-	}
-	if(cfd != -1){
-		close(cfd);
-		cfd = -1;
-	}
-	if(ufd != -1){
-		close(ufd);
-		ufd = -1;
-	}
+	netadr_t *a;
+
+	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;
 }
--- a/qw/pr_cmds.c
+++ b/qw/pr_cmds.c
@@ -1544,7 +1544,7 @@
 			value = Info_ValueForKey(localinfo, key);
 	} else if (e1 <= MAX_CLIENTS) {
 		if (!strcmp(key, "ip"))
-			value = strcpy(ov, NET_BaseAdrToString (svs.clients[e1-1].netchan.remote_address));
+			value = strcpy(ov, svs.clients[e1-1].netchan.remote_address.addr);
 		else if (!strcmp(key, "ping")) {
 			int ping = SV_CalcPing (&svs.clients[e1-1]);
 			sprintf(ov, "%d", ping);
--- a/qw/protocol.h
+++ b/qw/protocol.h
@@ -6,8 +6,6 @@
 
 //=========================================
 
-#define	PORT_CLIENT	27001
-#define	PORT_MASTER	27000
 #define	PORT_SERVER	27500
 
 //=========================================
--- a/qw/qwcl.c
+++ b/qw/qwcl.c
@@ -5,14 +5,16 @@
 #include "quakedef.h"
 
 mainstacksize = 512*1024;
-Channel *fuckchan;
 
-
 /* FIXME: stupid-ass linking kludges */
 server_static_t	svs;
-qboolean ServerPaused(void){return 0;}
-void SV_SendServerInfoChange(char *, char *){}
-
+qboolean ServerPaused(void)
+{
+	return 0;
+}
+void SV_SendServerInfoChange(char *, char *)
+{
+}
 
 static void
 croak(void *, char *note)
--- a/qw/qwsv.c
+++ b/qw/qwsv.c
@@ -4,14 +4,15 @@
 #include <thread.h>
 #include "quakedef.h"
 
-mainstacksize = 512*1024;
-Channel *fuckchan;
+mainstacksize = 256*1024;
+
+extern Channel *echan;
+extern netadr_t cons[MAX_CLIENTS];
+
 quakeparms_t q;
 
-static cvar_t extrasleep = {"extrasleep", "0"};	/* in ms */
 static int iop = -1, pfd[2];
 
-
 /* FIXME: stupid-ass linking kludges */
 client_static_t	cls;
 void Draw_BeginDisc(void){}
@@ -18,7 +19,6 @@
 void Draw_EndDisc(void){}
 void Host_Shutdown(void){}
 
-
 char *
 Sys_ConsoleInput(void)
 {
@@ -36,6 +36,8 @@
 void
 killiop(void)
 {
+	if(iop < 0)
+		return;
 	threadkillgrp(THin);
 	close(pfd[0]);
 	close(pfd[1]);
@@ -58,52 +60,38 @@
 		s[n-1] = 0;
 		if((write(pfd[0], s, n)) != n)
 			break;
-		if(nbsend(fuckchan, nil) < 0)
-			sysfatal("chan really wanted to, but it's just too tired. %r");
+		send(echan, nil);
 	}
-	fprint(2, "iproc %d: %r\n", threadpid(threadid()));
 	iop = -1;
 }
 
-static void
-croak(void *, char *note)
-{
-	if(!strncmp(note, "sys:", 4)){
-		killiop();
-		NET_Shutdown();
-	}
-	noted(NDFLT);
-}
-
 void
 threadmain(int argc, char *argv[])
 {
 	double time, oldtime, newtime;
+	netadr_t *a;
 
 	svonly = 1;
 	COM_InitArgv (argc, argv);
 	initparm(&q);
-	notify(croak);
-	if((fuckchan = chancreate(sizeof(int), 1)) == nil)
-		sysfatal("chancreate fuckchan: %r");
+	if((echan = chancreate(sizeof(int), 1)) == nil)
+		sysfatal("chancreate: %r");
 	SV_Init(&q);
-	Cvar_RegisterVariable(&extrasleep);
 	if(proccreate(iproc, nil, 8192) < 0)
 		sysfatal("proccreate iproc: %r");
-
 	SV_Frame(0.1);	/* run one frame immediately for first heartbeat */
-
 	oldtime = Sys_DoubleTime() - 0.1;
 	for(;;){
-		recv(fuckchan, nil);	/* we just don't give any for free */
-
-		newtime = Sys_DoubleTime();	/* time since last docking */
+		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(1);
+		}
+		newtime = Sys_DoubleTime();
 		time = newtime - oldtime;
 		oldtime = newtime;
-		SV_Frame(time);		
-
-		/* just a way to screw up fucking conformation on purpose */
-		if(extrasleep.value)
-			sleep(extrasleep.value);
+		SV_Frame(time);
 	}	
 }
--- a/qw/sv_ccmds.c
+++ b/qw/sv_ccmds.c
@@ -36,21 +36,18 @@
 
 	for (i=1 ; i<Cmd_Argc() ; i++)
 	{
-		if (!strcmp(Cmd_Argv(i), "none") || !NET_StringToAdr (Cmd_Argv(i), &master_adr[i-1]))
+		if (!strcmp(Cmd_Argv(i), "none") || !NET_StringToAdr (Cmd_Argv(i), &master_adr[i-1], "27000"))
 		{
 			Con_Printf ("Setting nomaster mode.\n");
 			return;
 		}
-		if (master_adr[i-1].port == 0)
-			master_adr[i-1].port = BigShort (27000);
+		Con_Printf ("Master server at %s\n", master_adr[i-1].sys);
 
-		Con_Printf ("Master server at %s\n", NET_AdrToString (master_adr[i-1]));
-
 		Con_Printf ("Sending a ping.\n");
 
 		data[0] = A2A_PING;
 		data[1] = 0;
-		NET_SendPacket (2, data, master_adr[i-1]);
+		NET_SendPacket (2, data, &master_adr[i-1]);
 	}
 
 	svs.last_heartbeat = -99999;
@@ -375,7 +372,6 @@
 	avg = 1000*svs.stats.latched_active / STATFRAMES;
 	pak = (float)svs.stats.latched_packets/ STATFRAMES;
 
-	Con_Printf ("net address      : %s\n",NET_AdrToString (laddr));
 	Con_Printf ("cpu utilization  : %3i%%\n",(int)cpu);
 	Con_Printf ("avg response time: %i ms\n",(int)avg);
 	Con_Printf ("packets/frame    : %5.2f (%d)\n", pak, num_prstr);
@@ -400,7 +396,7 @@
 			else			
 				Con_Printf("\n");
 
-			s = NET_BaseAdrToString ( cl->netchan.remote_address);
+			s = cl->netchan.remote_address.addr;
 			Con_Printf ("  %-16.16s", s);
 			if (cl->state == cs_connected)
 			{
@@ -426,7 +422,7 @@
 				continue;
 			Con_Printf ("%5i %6i ", (int)cl->edict->v.frags,  cl->userid);
 
-			s = NET_BaseAdrToString ( cl->netchan.remote_address);
+			s = cl->netchan.remote_address.addr;
 			Con_Printf ("%s", s);
 			l = 16 - strlen(s);
 			for (j=0 ; j<l ; j++)
--- a/qw/sv_main.c
+++ b/qw/sv_main.c
@@ -404,7 +404,7 @@
 		return;
 	}
 
-	Con_DPrintf ("sending log %i to %s\n", svs.logsequence-1, NET_AdrToString(net_from));
+	Con_DPrintf ("sending log %i to %s\n", svs.logsequence-1, net_from->sys);
 
 	sprintf (data, "stdlog %i\n", svs.logsequence-1);
 	strcat (data, (char *)svs.log_buf[((svs.logsequence-1)&1)]);
@@ -451,7 +451,7 @@
 	// see if we already have a challenge for this ip
 	for (i = 0 ; i < MAX_CHALLENGES ; i++)
 	{
-		if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
+		if (NET_CompareBaseAdr (net_from, &svs.challenges[i].adr))
 			break;
 		if (svs.challenges[i].time < oldestTime)
 		{
@@ -464,7 +464,7 @@
 	{
 		// overwrite the oldest
 		svs.challenges[oldest].challenge = (rand() << 16) ^ rand();
-		svs.challenges[oldest].adr = net_from;
+		svs.challenges[oldest].adr = *net_from;
 		svs.challenges[oldest].time = realtime;
 		i = oldest;
 	}
@@ -517,7 +517,7 @@
 	// see if the challenge is valid
 	for (i=0 ; i<MAX_CHALLENGES ; i++)
 	{
-		if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
+		if (NET_CompareBaseAdr (net_from, &svs.challenges[i].adr))
 		{
 			if (challenge == svs.challenges[i].challenge)
 				break;		// good
@@ -539,7 +539,7 @@
 			cistrcmp(spectator_password.string, "none") &&
 			strcmp(spectator_password.string, s) )
 		{	// failed
-			Con_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from));
+			Con_Printf ("%s:spectator password failed\n", net_from->sys);
 			Netchan_OutOfBandPrint (net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT);
 			return;
 		}
@@ -554,7 +554,7 @@
 			cistrcmp(password.string, "none") &&
 			strcmp(password.string, s) )
 		{
-			Con_Printf ("%s:password failed\n", NET_AdrToString (net_from));
+			Con_Printf ("%s:password failed\n", net_from->sys);
 			Netchan_OutOfBandPrint (net_from, "%c\nserver requires a password\n\n", A2C_PRINT);
 			return;
 		}
@@ -562,7 +562,7 @@
 		Info_RemoveKey (userinfo, "password"); // remove passwd
 	}
 
-	adr = net_from;
+	adr = *net_from;
 	userid++;	// so every client gets a unique id
 
 	newcl = &temp;
@@ -586,17 +586,17 @@
 	{
 		if (cl->state == cs_free)
 			continue;
-		if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
+		if (NET_CompareBaseAdr (&adr, &cl->netchan.remote_address)
 			&& ( cl->netchan.qport == qport 
-			|| adr.port == cl->netchan.remote_address.port ))
+			|| strcmp(adr.srv, cl->netchan.remote_address.srv) == 0))
 		{
 			if (cl->state == cs_connected) {
-				Con_Printf("%s:dup connect\n", NET_AdrToString (adr));
+				Con_Printf("%s:dup connect\n", adr.sys);
 				userid--;
 				return;
 			}
 
-			Con_Printf ("%s:reconnect\n", NET_AdrToString (adr));
+			Con_Printf ("%s:reconnect\n", adr.sys);
 			SV_DropClient (cl);
 			break;
 		}
@@ -625,8 +625,8 @@
 	if ( (spectator && spectators >= (int)maxspectators.value)
 		|| (!spectator && clients >= (int)maxclients.value) )
 	{
-		Con_Printf ("%s:full connect\n", NET_AdrToString (adr));
-		Netchan_OutOfBandPrint (adr, "%c\nserver is full\n\n", A2C_PRINT);
+		Con_Printf ("%s:full connect\n", adr.sys);
+		Netchan_OutOfBandPrint (&adr, "%c\nserver is full\n\n", A2C_PRINT);
 		return;
 	}
 
@@ -652,11 +652,11 @@
 	// this is the only place a client_t is ever initialized
 	*newcl = temp;
 
-	Netchan_OutOfBandPrint (adr, "%c", S2C_CONNECTION );
+	Netchan_OutOfBandPrint (&adr, "%c", S2C_CONNECTION );
 
 	edictnum = (newcl-svs.clients)+1;
 	
-	Netchan_Setup (&newcl->netchan , adr, qport);
+	Netchan_Setup (&newcl->netchan , &adr, qport);
 
 	newcl->state = cs_connected;
 
@@ -719,7 +719,7 @@
 
 	if (!Rcon_Validate ()) {
 		Con_Printf ("Bad rcon from %s:\n%s\n"
-			, NET_AdrToString (net_from), net_message.data+4);
+			, net_from->sys, net_message.data+4);
 
 		SV_BeginRedirect (RD_PACKET);
 
@@ -728,7 +728,7 @@
 	} else {
 
 		Con_Printf ("Rcon from %s:\n%s\n"
-			, NET_AdrToString (net_from), net_message.data+4);
+			, net_from->sys, net_message.data+4);
 
 		SV_BeginRedirect (RD_PACKET);
 
@@ -779,7 +779,7 @@
 	}
 	if (c[0] == A2A_ACK && (c[1] == 0 || c[1] == '\n') )
 	{
-		Con_Printf ("A2A_ACK from %s\n", NET_AdrToString (net_from));
+		Con_Printf ("A2A_ACK from %s\n", net_from->sys);
 		return;
 	}
 	else if (!strcmp(c,"status"))
@@ -806,7 +806,7 @@
 		SVC_RemoteCommand ();
 	else
 		Con_Printf ("bad connectionless packet from %s:\n%s\n"
-		, NET_AdrToString (net_from), s);
+		, net_from->sys, s);
 }
 
 /*
@@ -840,16 +840,9 @@
 ==============================================================================
 */
 
-
-typedef struct
-{
-	unsigned	mask;
-	unsigned	compare;
-} ipfilter_t;
-
 #define	MAX_IPFILTERS	1024
 
-ipfilter_t	ipfilters[MAX_IPFILTERS];
+netadr_t ipfilters[MAX_IPFILTERS];
 int			numipfilters;
 
 cvar_t	filterban = {"filterban", "1"};
@@ -856,53 +849,6 @@
 
 /*
 =================
-StringToFilter
-=================
-*/
-qboolean StringToFilter (char *s, ipfilter_t *f)
-{
-	char	num[128];
-	int		i, j;
-	byte	b[4];
-	byte	m[4];
-	
-	for (i=0 ; i<4 ; i++)
-	{
-		b[i] = 0;
-		m[i] = 0;
-	}
-	
-	for (i=0 ; i<4 ; i++)
-	{
-		if (*s < '0' || *s > '9')
-		{
-			Con_Printf ("Bad filter address: %s\n", s);
-			return false;
-		}
-		
-		j = 0;
-		while (*s >= '0' && *s <= '9')
-		{
-			num[j++] = *s++;
-		}
-		num[j] = 0;
-		b[i] = atoi(num);
-		if (b[i] != 0)
-			m[i] = 255;
-
-		if (!*s)
-			break;
-		s++;
-	}
-	
-	f->mask = *(unsigned *)m;
-	f->compare = *(unsigned *)b;
-	
-	return true;
-}
-
-/*
-=================
 SV_AddIP_f
 =================
 */
@@ -909,22 +855,14 @@
 void SV_AddIP_f (void)
 {
 	int		i;
-	
-	for (i=0 ; i<numipfilters ; i++)
-		if (ipfilters[i].compare == 0xffffffff)
-			break;		// free spot
-	if (i == numipfilters)
-	{
-		if (numipfilters == MAX_IPFILTERS)
-		{
-			Con_Printf ("IP filter list is full\n");
-			return;
-		}
-		numipfilters++;
+
+	i = numipfilters;
+	if(i == MAX_IPFILTERS){
+		Con_Printf("IP filter list is full\n");
+		return;
 	}
-	
-	if (!StringToFilter (Cmd_Argv(1), &ipfilters[i]))
-		ipfilters[i].compare = 0xffffffff;
+	numipfilters++;
+	NET_StringToAdr(Cmd_Argv(1), &ipfilters[i], nil);
 }
 
 /*
@@ -934,15 +872,13 @@
 */
 void SV_RemoveIP_f (void)
 {
-	ipfilter_t	f;
+	netadr_t a;
 	int			i, j;
 
-	if (!StringToFilter (Cmd_Argv(1), &f))
+	if(!NET_StringToAdr(Cmd_Argv(1), &a, nil))
 		return;
 	for (i=0 ; i<numipfilters ; i++)
-		if (ipfilters[i].mask == f.mask
-		&& ipfilters[i].compare == f.compare)
-		{
+		if(strcmp(a.addr, ipfilters[i].addr) == 0){
 			for (j=i+1 ; j<numipfilters ; j++)
 				ipfilters[j-1] = ipfilters[j];
 			numipfilters--;
@@ -960,14 +896,10 @@
 void SV_ListIP_f (void)
 {
 	int		i;
-	byte	b[4];
 
 	Con_Printf ("Filter list:\n");
 	for (i=0 ; i<numipfilters ; i++)
-	{
-		*(unsigned *)b = ipfilters[i].compare;
-		Con_Printf ("%3i.%3i.%3i.%3i\n", b[0], b[1], b[2], b[3]);
-	}
+		Con_Printf ("%s\n", ipfilters[i].addr);
 }
 
 /*
@@ -979,7 +911,6 @@
 {
 	FILE	*f;
 	char	name[MAX_OSPATH];
-	byte	b[4];
 	int		i;
 
 	sprintf (name, "%s/listip.cfg", com_gamedir);
@@ -994,10 +925,7 @@
 	}
 	
 	for (i=0 ; i<numipfilters ; i++)
-	{
-		*(unsigned *)b = ipfilters[i].compare;
-		fprintf (f, "addip %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]);
-	}
+		fprintf (f, "addip %s\n", ipfilters[i].addr);
 	
 	fclose (f);
 }
@@ -1027,12 +955,9 @@
 qboolean SV_FilterPacket (void)
 {
 	int		i;
-	unsigned	in;
-	
-	in = *(unsigned *)net_from.ip;
 
 	for (i=0 ; i<numipfilters ; i++)
-		if ( (in & ipfilters[i].mask) == ipfilters[i].compare)
+		if(strcmp(net_from->addr, ipfilters[i].addr) == 0)
 			return filterban.value;
 
 	return !filterban.value;
@@ -1078,14 +1003,14 @@
 		{
 			if (cl->state == cs_free)
 				continue;
-			if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
+			if (!NET_CompareBaseAdr (net_from, &cl->netchan.remote_address))
 				continue;
 			if (cl->netchan.qport != qport)
 				continue;
-			if (cl->netchan.remote_address.port != net_from.port)
+			if(strcmp(cl->netchan.remote_address.srv, net_from->srv) != 0)
 			{
 				Con_DPrintf ("SV_ReadPackets: fixing up a translated port\n");
-				cl->netchan.remote_address.port = net_from.port;
+				strcpy(cl->netchan.remote_address.srv, net_from->srv);
 			}
 			if (Netchan_Process(&cl->netchan))
 			{	// this is a valid, sequenced packet, so process it
@@ -1143,6 +1068,7 @@
 			realtime - cl->connection_started > zombietime.value)
 		{
 			cl->state = cs_free;	// can now be reused
+			NET_Close(&cl->netchan.remote_address);
 		}
 	}
 	if (sv.paused && !nclients) {
@@ -1398,10 +1324,10 @@
 
 	// send to group master
 	for (i=0 ; i<MAX_MASTERS ; i++)
-		if (master_adr[i].port)
+		if (strlen(master_adr[i].srv) > 0)
 		{
-			Con_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
-			NET_SendPacket (strlen(string), string, master_adr[i]);
+			Con_Printf ("Sending heartbeat to %s\n", master_adr[i].sys);
+			NET_SendPacket (strlen(string), string, &master_adr[i]);
 		}
 }
 
@@ -1421,10 +1347,10 @@
 
 	// send to group master
 	for (i=0 ; i<MAX_MASTERS ; i++)
-		if (master_adr[i].port)
+		if(strlen(master_adr[i].srv) > 0)
 		{
-			Con_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
-			NET_SendPacket (strlen(string), string, master_adr[i]);
+			Con_Printf ("Sending heartbeat to %s\n", master_adr[i].sys);
+			NET_SendPacket (strlen(string), string, &master_adr[i]);
 		}
 }
 
@@ -1573,7 +1499,6 @@
 
 	// heartbeats will allways be sent to the id master
 	svs.last_heartbeat = -99999;		// send immediately
-//	NET_StringToAdr ("192.246.40.70:27000", &idmaster_adr);
 }
 
 
--- a/qw/sv_user.c
+++ b/qw/sv_user.c
@@ -546,7 +546,7 @@
 	vsprintf (send+5, fmt, argptr);
 	va_end (argptr);
 
-	NET_SendPacket (strlen(send)+1, send, where);
+	NET_SendPacket (strlen(send)+1, send, &where);
 }
 
 /*