ref: a96f72a41fed2a20c363865b5860fcbfeec7c90d
parent: 24746fcce9c0733764a9d256884f0bfbe4a808f2
author: Konstantinn Bonnet <qu7uux@gmail.com>
date: Sun Apr 19 14:54:44 EDT 2015
port udp/ip networking it's pretty ugly, but should/will be rewritten anyway once cl/sv code uses plan9 semantics only.
--- a/README
+++ b/README
@@ -1,19 +1,20 @@
qk2 - (9) quake 2
=================
- - game data is stored in $home/lib/quake2/
+ - game data dirs are stored in $home/lib/quake2/, e.g. $home/lib/quake2/dicks/
- 386 and amd64 only
horrors
-------
- - fault read when warping screen underwater
- - rendering glitches on screen borders
- - rendering glitches underwater
- - #pragma pack on set globally
+ - #pragma pack on set globally!!!
+ - rendering glitches and fault reads on resolutions not originally supported
+ (4:3 and SXGA)
- edict_t definitions merged without much looking
- q_sh9: stupid posixish glob stuff
- - portme: net_udp, cd_9
- - garbled stdout: Sys_ConsoleOutput
+ - net_udp mostly horrid
+ - portme: cd_9
+ - garbled stdout (Sys_ConsoleOutput): \r instead of \n
+ - dedicated 1: input not working (Sys_ConsoleInput)
- race between mproc and IN_Commands
- cinematic palette is fucked up if you resize during playback
- sound only works thanks to shitty workarounds
--- a/plan9/net_udp.c
+++ b/plan9/net_udp.c
@@ -1,21 +1,32 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
-#include <ctype.h>
+#include <thread.h>
#include <bio.h>
#include <ndb.h>
+#include <ip.h>
#include "../q_shared.h"
-/* FIXME: only loopback works, the rest is complete bullshit */
+/* FIXME: this shit SUCKS, and ipv4 only because of other code */
+cvar_t *svport; /* server port and copy of string value */
+char srv[6];
+cvar_t *clport; /* "client" port and copy */
+char clsrv[6];
+
typedef struct Loopmsg Loopmsg;
typedef struct Loopback Loopback;
+typedef struct Conmsg Conmsg;
+typedef struct Conlist Conlist;
enum{
- LOOPBACK = 0x7f000001,
- MAX_LOOPBACK = 4
+ MAX_LOOPBACK = 4,
+ HDRSZ = 16+16+16+2+2, /* sizeof Udphdr w/o padding */
+ BUFSZ = MAX_MSGLEN,
+ NBUF = 64,
+ DTHGRP = 1,
+ CLPORT = 27909
};
-
struct Loopmsg{
byte data[MAX_MSGLEN];
int datalen;
@@ -27,10 +38,29 @@
};
Loopback loopbacks[2];
-int ipfd[2], ipxfd[2];
-netadr_t laddr;
+struct Conlist{
+ Conlist *p;
+ uchar u[IPaddrlen+2];
+ char addr[IPaddrlen*2+8+6]; /* ipv6 + separators + port in decimal */
+ int dfd;
+ Udphdr h;
+ int src; /* q2 assumes broadcast replies are received on NS_CLIENT */
+};
+Conlist *cnroot;
+struct Conmsg{
+ Conlist *p;
+ int n;
+ uchar buf[BUFSZ];
+};
+Channel *udpchan;
+Channel *clchan;
+netadr_t laddr; /* 0.0.0.0:0 */
+int cfd = -1, ufd = -1, clfd = -1, cldfd = -1;
+QLock cnlock;
+
+
qboolean 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);
@@ -55,17 +85,17 @@
char *NET_AdrToString (netadr_t a)
{
- static char s[64];
-
- Com_sprintf(s, sizeof(s), "%i.%i.%i.%i:%hi", a.ip[0], a.ip[1], a.ip[2], a.ip[3], a.port << 8 | a.port >> 8);
+ 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[64];
-
- Com_sprintf(s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
+ 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;
}
@@ -80,249 +110,414 @@
192.246.40.70:28000
=============
*/
-qboolean NET_StringToAdr (char *s, netadr_t *a)
+qboolean NET_StringToAdr (char *addr, netadr_t *a) /* assumes IPv4 */
{
int i;
- char *e, *p, *ss;
+ char s[256], *p, *pp;
Ndb *db;
Ndbtuple *nt;
- if(!strcmp(s, "localhost")){
- memset(a, 0, sizeof(*a));
+ if(!strcmp(addr, "localhost")){
+ memset(a, 0, sizeof *a);
a->type = NA_LOOPBACK;
return true;
}
- /* FIXMEGASHIT */
- if((ss = smprint("%s", s)) == nil) /* don't fuck with someone else's s */
- sysfatal("NET_StringToAdr:smprint: %r");
- p = ss;
- if((e = strchr(p, ':')) != nil){
- *e++ = '\0';
- a->port = atoi(e);
+ strncpy(s, addr, sizeof s);
+ s[sizeof(s)-1] = 0;
+
+ if((p = strrchr(s, ':')) != nil){
+ *p++ = '\0';
+ a->port = BigShort(atoi(p));
}
- db = ndbopen(nil);
- if((nt = ndbgetipaddr(db, ss)) == nil){
+
+ if((db = ndbopen(nil)) == nil){
+ fprint(2, "NET_StringToAdr:ndbopen: %r\n");
+ return false;
+ }
+ if((nt = ndbgetipaddr(db, s)) == nil){
ndbclose(db);
+ fprint(2, "NET_StringToAdr:ndbgetipaddr: %r\n");
return false;
}
- if((ss = smprint("%s", nt->val)) == nil) /* get copy of first value found */
- sysfatal("NET_StringToAdr:smprint: %r");
- p = ss;
- for(i = 0; i < 4; i++){
- if((e = strchr(p, '.')) != nil)
- *e++ = '\0';
- a->ip[i] = atoi(p);
- p = e;
- }
- a->type = NA_IP;
-
- free(ss);
+ strncpy(s, nt->val, sizeof(s)-1); /* just look at first value found */
ndbfree(nt);
ndbclose(db);
+
+ for(i = 0, pp = s; i < IPv4addrlen; i++){
+ if((p = strchr(pp, '.')) != nil)
+ *p++ = '\0';
+ a->ip[i] = atoi(pp);
+ pp = p;
+ }
+ a->type = NA_IP;
return true;
}
qboolean NET_IsLocalAddress (netadr_t adr)
{
- return NET_CompareAdr (adr, laddr);
+ return NET_CompareAdr(adr, laddr);
}
-qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
+qboolean looprecv (netsrc_t sock, netadr_t *net_from, sizebuf_t *d)
{
int i;
- Loopback *loop;
+ Loopback *l;
- loop = &loopbacks[sock];
-
- if(loop->send - loop->get > MAX_LOOPBACK)
- loop->get = loop->send - MAX_LOOPBACK;
-
- if (loop->get >= loop->send)
+ l = &loopbacks[sock];
+ if(l->send - l->get > MAX_LOOPBACK)
+ l->get = l->send - MAX_LOOPBACK;
+ if(l->get >= l->send)
return false;
+ i = l->get & (MAX_LOOPBACK-1);
+ l->get++;
- i = loop->get & (MAX_LOOPBACK-1);
- loop->get++;
-
- memcpy(net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
- net_message->cursize = loop->msgs[i].datalen;
+ memcpy(d->data, l->msgs[i].data, l->msgs[i].datalen);
+ d->cursize = l->msgs[i].datalen;
*net_from = laddr;
return true;
}
-void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t /*to*/)
+void loopsend (netsrc_t sock, int length, void *data, netadr_t /*to*/)
{
- Loopback *loop;
+ Loopback *l;
int i;
- loop = &loopbacks[sock^1];
- i = loop->send & (MAX_LOOPBACK-1);
- loop->send++;
- memcpy(loop->msgs[i].data, data, length);
- loop->msgs[i].datalen = length;
+ l = &loopbacks[sock^1];
+ i = l->send & (MAX_LOOPBACK-1);
+ l->send++;
+ memcpy(l->msgs[i].data, data, length);
+ l->msgs[i].datalen = length;
}
-qboolean NET_GetPacket (netsrc_t src, netadr_t *from, sizebuf_t *d)
+void cninit (void)
{
- int n, protocol, fd;
- NetConnInfo *nci;
- char addr[21];
+ 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;
+}
- if(NET_GetLoopPacket(src, from, d))
- return true;
+Conlist *cnins (int fd, char *addr, uchar *u, Udphdr *h, int src)
+{
+ Conlist *p, *l;
- for(protocol = 0 ; protocol < 2 ; protocol++){
- if(protocol == 0)
- fd = ipfd[src];
- else
- fd = ipxfd[src];
- if(!fd)
- continue;
+ l = cnroot;
+ if((p = malloc(sizeof *p)) == nil)
+ sysfatal("cnins:malloc: %r");
- if((n = read(fd, d->data, d->maxsize)) < 0){
- fprint(2, "NET_GetPacket:read: %r\n");
- Com_Printf("NET_GetPacket: error reading packet\n");
- continue;
- }
- if(n == d->maxsize){
- Com_Printf("Oversize packet from %s\n", NET_AdrToString(*from));
- continue;
- }
- d->cursize = n;
+ 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->src = src;
+ p->p = l->p;
+ l->p = p;
+ return p;
+}
- /* FIXME */
- if((nci = getnetconninfo(nil, fd)) == nil){
- fprint(2, "NET_GetPacket:getnetconninfo: %r\n");
- return true;
+Conlist *cnfind (char *raddr)
+{
+ Conlist *p = cnroot->p;
+
+ while(p != cnroot){
+ if(!strncmp(p->addr, raddr, strlen(p->addr)))
+ return p;
+ p = p->p;
+ }
+ return nil;
+}
+
+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 != cldfd && p->dfd != -1)
+ close(p->dfd);
+ free(p);
+}
+
+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;
+}
+
+void dproc (void *me)
+{
+ int n, fd;
+ Conmsg m;
+ Conlist *p;
+ Channel *c;
+
+ if(threadsetgrp(DTHGRP) < 0)
+ sysfatal("dproc:threadsetgrp: %r");
+
+ m.p = p = me;
+ c = p->src == NS_CLIENT ? clchan : udpchan;
+ fd = p->dfd;
+
+ for(;;){
+ if((n = read(fd, m.buf, sizeof m.buf)) <= 0)
+ break;
+ m.n = n;
+ if(send(c, &m) < 0)
+ sysfatal("uproc:send: %r\n");
+ }
+ fprint(2, "dproc %d: %r\n", threadpid(threadid()));
+ cndel(me);
+}
+
+void uproc (void *c)
+{
+ int n, fd;
+ uchar udpbuf[BUFSZ+HDRSZ], u[IPaddrlen+2];
+ char a[IPaddrlen*2+8+6];
+ Udphdr h;
+ Conmsg m;
+ Conlist *p;
+
+ if(threadsetgrp(DTHGRP) < 0)
+ sysfatal("uproc:threadsetgrp: %r");
+
+ fd = ufd;
+ if(c == clchan)
+ fd = cldfd;
+ for(;;){
+ if((n = read(fd, udpbuf, sizeof udpbuf)) <= 0)
+ sysfatal("uproc:read: %r\n");
+ 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(fd, a, u, &h, 0);
+ 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);
}
- seprint(addr, addr+sizeof(addr), "%s:%s", nci->rsys, nci->rserv);
- NET_StringToAdr(addr, from);
+ if(send(c, &m) < 0)
+ sysfatal("uproc:send: %r\n");
+ }
+}
+
+qboolean NET_GetPacket (netsrc_t src, netadr_t *from, sizebuf_t *d)
+{
+ int n;
+ Conmsg m;
+
+ if(looprecv(src, from, d))
return true;
+ if(cfd == -1)
+ return false;
+
+ if((n = nbrecv(src == NS_SERVER ? udpchan : clchan, &m)) < 0)
+ sysfatal("NET_GetPacket:nbrecv: %r");
+ if(n == 0)
+ return false;
+
+ memcpy(from->ip, m.p->u+12, 4);
+ from->port = m.p->u[17] << 8 | m.p->u[16];
+ if(m.n == d->maxsize){
+ Com_Printf("Oversize packet from %s\n", NET_AdrToString(*from));
+ return false;
}
- return false;
+ from->type = NA_IP;
+ d->cursize = m.n;
+ memcpy(d->data, m.buf, m.n);
+ return true;
}
void NET_SendPacket (netsrc_t src, int length, void *data, netadr_t to)
{
- int fd = 0;
+ int fd;
+ char *addr, *s, *lport;
+ uchar b[BUFSZ+HDRSZ], u[IPaddrlen+2];
+ Conlist *p;
switch(to.type){
case NA_LOOPBACK:
- NET_SendLoopPacket(src, length, data, to);
- return;
- case NA_BROADCAST:
- case NA_IP:
- fd = ipfd[src];
- if(!fd)
- return;
+ loopsend(src, length, data, to);
break;
- case NA_IPX:
case NA_BROADCAST_IPX:
- fd = ipxfd[src];
- if(!fd)
- return;
+ case NA_IPX:
break;
+ case NA_BROADCAST:
+ memset(to.ip, 0xff, 4);
+ addr = NET_AdrToString(to); /* port is PORT_SERVER */
+ s = strrchr(addr, ':');
+ *s++ = '\0';
+ if((fd = dial(netmkaddr(addr, "udp", s), clsrv, nil, nil)) < 0)
+ sysfatal("NET_SendPacket:dial bcast: %r");
+ if(write(fd, data, length) != length)
+ sysfatal("NET_SendPacket:write bcast: %r");
+ close(fd);
+ break;
+ case NA_IP:
+ if(cfd == -1)
+ break;
+
+ addr = NET_AdrToString(to);
+ qlock(&cnlock);
+ p = cnfind(addr);
+ qunlock(&cnlock);
+ if(p != nil){
+ fd = p->dfd;
+ if(fd == ufd || fd == cldfd){
+ memcpy(b, &p->h, HDRSZ);
+ memcpy(b+HDRSZ, data, length);
+ write(fd, b, length+HDRSZ);
+ break;
+ }
+ }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, src);
+ qunlock(&cnlock);
+
+ if(proccreate(dproc, p, 8196) < 0)
+ sysfatal("NET_SendPacket:proccreate: %r");
+ }
+ if(write(fd, data, length) != length)
+ sysfatal("NET_SendPacket:write: %r");
+ break;
default:
Com_Error(ERR_FATAL, "NET_SendPacket: bad address type");
}
- if(write(fd, data, length) != length){
- fprint(2, "NET_SendPacket:write: %r\n");
- Com_Printf("NET_SendPacket: bad write\n");
- }
}
-int NET_Socket (char *ifc, int port)
+/* sleeps msec or until data is read from dfd */
+void NET_Sleep (int msec)
{
- int fd;
- char addr[21], dir[40], *p;
+ if(cfd == -1 || dedicated != nil && !dedicated->value)
+ return; // we're not a server, just run full speed
- /* FIXMEGAFUCKEDUPSHIT */
- p = seprint(addr, addr+sizeof(addr), "udp!*");
- if(ifc != nil || Q_strcasecmp(ifc, "localhost"))
- p = seprint(p-1, addr+sizeof(addr), "%s", ifc);
- if(port == PORT_ANY)
- seprint(p, addr+sizeof(addr), "!%hud", (ushort)port);
-
- if((fd = announce(addr, dir)) < 0){
- fprint(2, "NET_Socket:announce: %r\n");
- Com_Printf("Net_Socket: announce failed!\n");
- return false;
- }
- return fd; /* FIXME: NO! */
+ /* FIXME */
+ print("NET_Sleep %d: PORTME\n", msec);
}
-void NET_OpenIP (void)
+int openname (char *port, int *dfd, Channel **c)
{
- cvar_t *port, *ip;
+ int fd;
+ char data[64], adir[40];
- port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET);
- ip = Cvar_Get("ip", "localhost", CVAR_NOSET);
-
- /* FIXME: those are ctl fd's! */
- if(!ipfd[NS_SERVER])
- ipfd[NS_SERVER] = NET_Socket(ip->string, port->value);
- if(!ipfd[NS_CLIENT])
- ipfd[NS_CLIENT] = NET_Socket(ip->string, PORT_ANY);
+ if((fd = announce(netmkaddr("*", "udp", port), adir)) < 0)
+ sysfatal("openname:announce udp!*!%s: %r", port);
+ if(fprint(fd, "headers") < 0)
+ sysfatal("openname: failed to set header mode: %r");
+ snprint(data, sizeof data, "%s/data", adir);
+ if((*dfd = open(data, ORDWR)) < 0)
+ sysfatal("openname:open %r");
+ if((*c = chancreate(sizeof(Conmsg), NBUF)) == nil)
+ sysfatal("openname:chancreate: %r");
+ if(proccreate(uproc, *c, 8196) < 0)
+ sysfatal("openname:proccreate: %r");
+ return fd;
}
-void NET_OpenIPX (void)
+void openudp (void)
{
+ if(cfd != -1)
+ return;
+
+ /* svport value can be changed at any time */
+ if(svport->value == PORT_ANY || svport->value > 32767)
+ /* FIXME */
+ strncpy(srv, "*", sizeof(srv)-1);
+ else
+ strncpy(srv, svport->string, sizeof(srv)-1);
+ cfd = openname(srv, &ufd, &udpchan);
+
+ /* broadcast kluge */
+ if(clport->value == PORT_ANY || clport->value > 32767)
+ strncpy(clsrv, "*", sizeof(clsrv)-1);
+ else
+ strncpy(clsrv, clport->string, sizeof(clsrv)-1);
+ clfd = openname(clsrv, &cldfd, &clchan);
}
/* a single player game will only use the loopback code */
void NET_Config (qboolean multiplayer)
{
- int i;
-
- if(!multiplayer){ /* shut down any existing sockets */
- for(i=0 ; i<2 ; i++){
- if(ipfd[i]){
- close(ipfd[i]);
- ipfd[i] = 0;
- }
- if(ipxfd[i]){
- close(ipxfd[i]);
- ipxfd[i] = 0;
- }
+ if(!multiplayer){ /* shut down existing udp connections */
+ threadkillgrp(DTHGRP);
+ cnnuke();
+ if(udpchan != nil){
+ chanfree(udpchan);
+ udpchan = nil;
}
+ if(clchan != nil){
+ chanfree(clchan);
+ clchan = nil;
+ }
+ if(cfd != -1){
+ close(cfd);
+ cfd = -1;
+ }
+ if(clfd != -1){
+ close(clfd);
+ clfd = -1;
+ }
+ if(ufd != -1){
+ close(ufd);
+ ufd = -1;
+ }
+ if(cldfd != -1){
+ close(cldfd);
+ cldfd = -1;
+ }
+ }else{ /* announce open line and get cfd for it */
+ cninit();
+ openudp();
}
- else{ /* open sockets */
- NET_OpenIP();
- NET_OpenIPX();
- }
}
-void NET_Init (void)
-{
-}
-
void NET_Shutdown (void)
{
- NET_Config(false); // close sockets
+ NET_Config(false);
}
-/* sleeps msec or until net socket is ready */
-void NET_Sleep(int /*msec*/)
+void NET_Init (void)
{
- /* PORTME */
-
- /*
- struct timeval timeout;
- fd_set fdset;
- extern cvar_t *dedicated;
- extern qboolean stdin_active;
- */
-
- if(!ipfd[NS_SERVER] || dedicated && !dedicated->value)
- 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(ipfd[NS_SERVER], &fdset); // network socket
- timeout.tv_sec = msec/1000;
- timeout.tv_usec = (msec%1000)*1000;
- select(ipfd[NS_SERVER]+1, &fdset, NULL, NULL, &timeout);
- */
+ svport = Cvar_Get("port", va("%d", PORT_SERVER), CVAR_NOSET);
+ clport = Cvar_Get("clport", va("%hud", CLPORT), CVAR_NOSET);
}
--- a/plan9/sys_9.c
+++ b/plan9/sys_9.c
@@ -106,6 +106,7 @@
if(!strncmp(note, "sys:", 4)){
IN_Shutdown();
SNDDMA_Shutdown();
+ NET_Shutdown();
}
noted(NDFLT);
}