shithub: qk1

ref: 4c1435a0346ab111b5d9fec0abf5910952b7950e
dir: /net_udp.c/

View raw version
#include "quakedef.h"
#include <ip.h>
#include <thread.h>

Addr myip;

static int lpid = -1, afd;
static Channel *lchan;

int
UDP_Init(void)
{
	char *s;
	uchar ip[IPaddrlen];

	fmtinstall('I', eipfmt);
	if(strcmp(hostname.string, "UNNAMED") == 0)
		if((s = getenv("sysname")) != nil){
			setcvar("hostname", s);
			free(s);
		}
	myipaddr(ip, nil);
	snprint(myip.ip, sizeof myip.ip, "%I", ip);
	snprint(myip.srv, sizeof myip.srv, "%hud", Udpport);
	return 0;
}

void
UDP_Shutdown(void)
{
	UDP_Listen(false);
}

static void
lproc(void *)
{
	int fd, lfd;
	char adir[40], ldir[40], data[100];

	snprint(data, sizeof data, "%s/udp!*!%s", netmtpt, myip.srv);
	if((afd = announce(data, adir)) < 0)
		sysfatal("announce: %r");
	for(;;){
		if((lfd = listen(adir, ldir)) < 0
			|| (fd = accept(lfd, ldir)) < 0
			|| close(lfd) < 0
			|| send(lchan, &fd) < 0)
			break;
	}
}

static void
udpname(void)
{
	if((lchan = chancreate(sizeof(int), 0)) == nil)
		sysfatal("chancreate: %r");
	if((lpid = proccreate(lproc, nil, 8192)) < 0)
		sysfatal("proccreate lproc: %r");
}

void
UDP_Listen(bool on)
{
	if(lpid < 0){
		if(on)
			udpname();
		return;
	}
	if(on)
		return;
	close(afd);
	chanclose(lchan);
	threadint(lpid);
	chanfree(lchan);
	lpid = -1;
}

void
udpinfo(Addr *a)
{
	NetConnInfo *nc;

	if((nc = getnetconninfo(nil, a->fd)) == nil){
		Con_DPrintf("getnetconninfo: %r\n");
		return;
	}
	strncpy(a->ip, nc->raddr, sizeof(a->ip)-1);
	strncpy(a->srv, nc->rserv, sizeof(a->srv)-1);
	strncpy(a->sys, nc->rsys, sizeof(a->sys)-1);
	free(nc);
}

int
UDP_Connect(Addr *a)
{
	if((a->fd = dial(netmkaddr(a->ip, "udp", a->srv), myip.srv, nil, nil)) < 0){
		Con_DPrintf("dial: %r\n");
		return -1;
	}
	return 0;
}

int
getnewcon(Addr *a)
{
	if(lpid < 0)
		return 0;
	if(nbrecv(lchan, &a->fd) == 0)
		return 0;
	udpinfo(a);
	return 1;
}

int
udpread(byte *buf, int len, Addr *a)
{
	int n;

	if(flen(a->fd) < 1)
		return 0;
	if((n = read(a->fd, buf, len)) <= 0){
		Con_DPrintf("udpread: %r\n");
		return -1;
	}
	return n;
}

int
udpwrite(uchar *buf, int len, Addr *a)
{
	if(write(a->fd, buf, len) != len){
		Con_DPrintf("udpwrite: %r\n");
		return -1;
	}
	return len;
}

char *
UDP_AddrToString(Addr *a)
{
	char *p;
	static char buf[52];

	strncpy(buf, a->sys, sizeof(buf)-1);
	if((p = strrchr(buf, '!')) != nil)
		*p = ':';
	return buf;
}

int
UDP_Broadcast(uchar *buf, int len)
{
	int fd;
	char ip[46];

	snprint(ip, sizeof ip, "%I", IPv4bcast);
	if((fd = dial(netmkaddr(ip, "udp", myip.srv), myip.srv, nil, nil)) < 0){
		Con_DPrintf("UDP_Broadcast: %r\n");
		return -1;
	}
	if(write(fd, buf, len) != len)
		Con_DPrintf("write: %r\n");
	close(fd);
	return 0;
}

int
getip(char *s, Addr *a)
{
	int fd, n;
	char buf[128], *f[4], *p;

	snprint(buf, sizeof buf, "%s/cs", netmtpt);
	if((fd = open(buf, ORDWR)) < 0)
		sysfatal("open: %r");

	if((p = strrchr(s, '!')) == nil)
		p = myip.srv;
	else
		p++;
	snprint(buf, sizeof buf, "udp!%s!%s", s, p);
	n = strlen(buf);
	if(write(fd, buf, n) != n){
		Con_DPrintf("translating %s: %r\n", s);
		return -1;
	}
	seek(fd, 0, 0);
	if((n = read(fd, buf, sizeof(buf)-1)) <= 0){
		Con_DPrintf("reading cs tables: %r");
		return -1;
	}
	buf[n] = 0;
	close(fd);
	if(getfields(buf, f, 4, 0, " !") < 2)
		goto err;
	strncpy(a->ip, f[1], sizeof(a->ip)-1);
	a->ip[sizeof(a->ip)-1] = 0;
	strncpy(a->srv, f[2], sizeof(a->srv)-1);
	a->srv[sizeof(a->srv)-1] = 0;
	snprint(a->sys, sizeof a->sys, "%s!%s", a->ip, a->srv);
	return 0;
err:
	Con_DPrintf("bad cs entry %s", buf);
	return -1;
}

int
UDP_AddrCompare(Addr *a1, Addr *a2)
{
	if(strcmp(a1->ip, a2->ip) != 0)
		return -1;
	if(strcmp(a1->srv, a2->srv) != 0)
		return 1;
	return 0;
}

ushort
UDP_GetSocketPort(Addr *a)
{
	ushort p;

	p = atoi(a->srv);
	return p;
}

void
UDP_SetSocketPort(Addr *a, ushort port)
{
	snprint(a->srv, sizeof a->srv, "%hud", port);	/* was htons'ed */
}