Esempio n. 1
0
File: ipif.c Progetto: 8l/inferno
int
so_accept(int fd, uchar *raddr, ushort *rport)
{
	int nfd;
	socklen_t len;
	struct sockaddr sa;
	struct sockaddr_in *sin;

	sin = (struct sockaddr_in*)&sa;

	len = sizeof(sa);
	osenter();
	if(doselect(fd) < 0) {
		osleave();
		return -1;
	}
	nfd = accept(fd, &sa, &len);
	osleave();
	if(nfd < 0)
		oserror();

	if(sin->sin_family != AF_INET || len != sizeof(*sin))
		error(Enotv4);

	ipw6(raddr, sin->sin_addr.s_addr);
	*rport = nhgets(&sin->sin_port);
	return nfd;
}
Esempio n. 2
0
File: devfs.c Progetto: 8l/inferno
static long
fsdirread(Chan *c, void *va, long count, vlong offset)
{
	long n, r;
	static char slop[16384];

	if(FS(c)->offset != offset){
		seek(FS(c)->fd, 0, 0);
		for(n=0; n<offset;) {
			r = offset - n;
			if(r > sizeof(slop))
				r = sizeof(slop);
			osenter();
			r = read(FS(c)->fd, slop, r);
			osleave();
			if(r <= 0){
				FS(c)->offset = n;
				return 0;
			}
			n += r;
		}
		FS(c)->offset = offset;
	}
	osenter();
	r = read(FS(c)->fd, va, count);
	osleave();
	if(r < 0)
		return r;
	FS(c)->offset = offset+r;
	return r;
}
Esempio n. 3
0
int
so_accept(int fd, unsigned long *raddr, unsigned short *rport)
{
	int nfd, len;
	struct sockaddr sa;
	struct sockaddr_in *sin;

	sin = (struct sockaddr_in*)&sa;

	len = sizeof(sa);
	osenter();
	if(doselect(fd) < 0) {
		osleave();
		return -1;
	}
	nfd = accept(fd, &sa, &len);
	osleave();
	if(nfd < 0)
		oserror();

	if(sin->sin_family != AF_INET || len != sizeof(*sin))
		error("not AF_INET");

	*raddr = nhgetl(&sin->sin_addr.s_addr);
	*rport = nhgets(&sin->sin_port);
	return nfd;
}
Esempio n. 4
0
int
so_recv(int sock, void *va, int len, void *hdr, int hdrlen)
{
	int r, l;
	struct sockaddr sa;
	struct sockaddr_in *sin;
	char h[Udphdrlen];

	osenter();
	if(doselect(sock) < 0) {
		osleave();
		return -1;
	}
	if(hdr == 0)
		r = recv(sock, va, len, 0);
	else {
		sin = (struct sockaddr_in*)&sa;
		l = sizeof(sa);
		r = recvfrom(sock, va, len, 0, &sa, &l);
		if(r >= 0) {
			memset(h, sizeof h, 0);
			switch(hdrlen){
			case OUdphdrlenv4:
				memmove(h, &sin->sin_addr, 4);
				memmove(h+2*IPv4addrlen, &sin->sin_port, 2);
				break;
			case OUdphdrlen:
				v4tov6(h, (uchar*)&sin->sin_addr);
				memmove(h+2*IPaddrlen, &sin->sin_port, 2);
				break;
			default:
				v4tov6(h, (uchar*)&sin->sin_addr);
				memmove(h+3*IPaddrlen, &sin->sin_port, 2);
				break;
			}

			/* alas there's no way to get the local addr/port correctly.  Pretend. */
			getsockname(sock, &sa, &l);
			switch(hdrlen){
			case OUdphdrlenv4:
				memmove(h+IPv4addrlen, &sin->sin_addr, IPv4addrlen);
				memmove(h+2*IPv4addrlen+2, &sin->sin_port, 2);
				break;
			case OUdphdrlen:
				v4tov6(h+IPaddrlen, (uchar*)&sin->sin_addr);
				memmove(h+2*IPaddrlen+2, &sin->sin_port, 2);
				break;
			default:
				v4tov6(h+IPaddrlen, (uchar*)&sin->sin_addr);
				v4tov6(h+2*IPaddrlen, (uchar*)&sin->sin_addr);	/* ifcaddr */
				memmove(h+3*IPaddrlen+2, &sin->sin_port, 2);
				break;
			}
			memmove(hdr, h, hdrlen);
		}
	}
	osleave();
	return r;
}
Esempio n. 5
0
static Chan*
eiaopen(Chan *c, int mode)
{
	int port = NETID(c->qid.path);
	struct termios ts;
	int r;

	c = devopen(c, mode, eiadir, ndir, devgen);

	switch(NETTYPE(c->qid.path)) {
	case Nctlqid:
	case Ndataqid:
	case Nstatqid:
		if(incref(&eia[port].r) != 1)
			break;

		osenter();
		eia[port].fd = open(sysdev[port], O_RDWR);
		osleave();
		if(eia[port].fd < 0)
			oserror();

		/* make port settings sane */
		if(tcgetattr(eia[port].fd, &ts) < 0)
			oserror();
		ts.c_iflag = ts.c_oflag = ts.c_lflag = 0;
		if(eia[port].restore)
		        ts = eia[port].ts;
		else {
			cfsetispeed(&ts, B9600);
			cfsetospeed(&ts, B9600);
			ts.c_iflag |= IGNPAR;
			ts.c_cflag &= ~CSIZE;
			ts.c_cflag |= CS8|CREAD;
			ts.c_cflag &= ~(PARENB|PARODD);
			ts.c_cc[VMIN] = 1;
			ts.c_cc[VTIME] = 0;
		}
		osenter();
		r = tcsetattr(eia[port].fd, TCSANOW, &ts);
		osleave();
		if(r < 0)
			oserror();

		if(eia[port].restore)
		        resxtra(port, &ts);
		break;
	}
	return c;
}
Esempio n. 6
0
static long
eiawrite(Chan *c, void *buf, long n, vlong offset)
{
	ssize_t cnt;
	char cmd[Maxctl];
	int port = NETID(c->qid.path);

	USED(offset);

	if(c->qid.type & QTDIR)
		error(Eperm);

	switch(NETTYPE(c->qid.path)) {
	case Ndataqid:
	  	osenter(); 
		cnt = write(eia[port].fd, buf, n);
		osleave(); 
		if(cnt == -1)
			oserror();
		return cnt;
	case Nctlqid:
		if(n >= (long)sizeof(cmd))
			n = sizeof(cmd)-1;
		memmove(cmd, buf, n);
		cmd[n] = 0;
		wrctl(port, cmd);
		return n;
	}
	return 0;
}
Esempio n. 7
0
File: devfs.c Progetto: 8l/inferno
void
fscreate(Chan *c, char *name, int mode, ulong perm)
{
	Dir *d;
	Cname *n;

	if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
		error(Efilename);
	n = addelem(newcname(FS(c)->name->s), name);
	osenter();
	FS(c)->fd = create(n->s, mode, perm);
	osleave();
	if(FS(c)->fd < 0) {
		cnameclose(n);
		fserr(FS(c));
	}
	d = dirfstat(FS(c)->fd);
	if(d == nil) {
		cnameclose(n);
		close(FS(c)->fd);
		FS(c)->fd = -1;
		fserr(FS(c));
	}
	c->qid = d->qid;
	free(d);

	cnameclose(FS(c)->name);
	FS(c)->name = n;

	c->mode = openmode(mode);
	c->offset = 0;
	FS(c)->offset = 0;
	c->flag |= COPEN;
}
Esempio n. 8
0
static long
eiaread(Chan *c, void *buf, long n, vlong offset)
{
	ssize_t cnt;
	int port = NETID(c->qid.path);

	if(c->qid.type & QTDIR)
		return devdirread(c, buf, n, eiadir, ndir, devgen);

	switch(NETTYPE(c->qid.path)) {
	case Ndataqid:
	  	osenter(); 
		cnt = read(eia[port].fd, buf, n);
		osleave(); 
		if(cnt == -1)
			oserror();
		return cnt;
	case Nctlqid:
		return readnum(offset, buf, n, port, NUMSIZE);
	case Nstatqid:
		return rdstat(port, buf, n, offset);
	}

	return 0;
}
Esempio n. 9
0
int
so_send(int sock, void *va, int len, void *hdr, int hdrlen)
{
	int r;
	struct sockaddr_storage sa;
	struct sockaddr_in6 *sin6;
	char *h = hdr;

	osenter();
	if(hdr == 0)
		r = write(sock, va, len);
	else {
		memset(&sa, 0, sizeof(sa));
		sin6 = (struct sockaddr_in6*)&sa;
		sin6->sin6_family = AF_INET6;
		switch(hdrlen){
		case OUdphdrlenv4:
			v4tov6((uchar*)&sin6->sin6_addr, h);
			memmove(&sin6->sin6_port, h+8, 2);
			break;
		case OUdphdrlen:
			memmove((uchar*)&sin6->sin6_addr, h, IPaddrlen);
			memmove(&sin6->sin6_port, h+2*IPaddrlen, 2);	/* rport */
			break;
		default:
			memmove((uchar*)&sin6->sin6_addr, h, IPaddrlen);
			memmove(&sin6->sin6_port, h+3*IPaddrlen, 2);
			break;
		}
		r = sendto(sock, va, len, 0, (struct sockaddr*)sin6, sizeof(*sin6));
	}
	osleave();
	return r;
}
Esempio n. 10
0
File: ipif.c Progetto: 8l/inferno
int
so_send(int sock, void *va, int len, void *hdr, int hdrlen)
{
	int r;
	struct sockaddr sa;
	struct sockaddr_in *sin;
	uchar *h = hdr;


	osenter();
	if(hdr == 0)
		r = send(sock, va, len, 0);
	else {
		memset(&sa, 0, sizeof(sa));
		sin = (struct sockaddr_in*)&sa;
		sin->sin_family = AF_INET;
		switch(hdrlen){
		case OUdphdrlenv4:
			memmove(&sin->sin_addr, h,  4);
			memmove(&sin->sin_port, h+8, 2);
			break;
		case OUdphdrlen:
			v6tov4((uchar*)&sin->sin_addr, h);
			memmove(&sin->sin_port, h+2*IPaddrlen, 2);	/* rport */
			break;
		default:
			v6tov4((uchar*)&sin->sin_addr, h);
			memmove(&sin->sin_port, h+3*IPaddrlen, 2);
			break;
		}
		r = sendto(sock, va, len, 0, &sa, sizeof(sa));
	}
	osleave();
	return r;
}
Esempio n. 11
0
static long
eiaread(Chan *c, void *buf, long n, vlong offset)
{
	DWORD cnt;
	int port = NETID(c->qid.path);
	BOOL good;

	if(c->qid.type & QTDIR)
		return devdirread(c, buf, n, eiadir, ndir, devgen);

	switch(NETTYPE(c->qid.path)) {
	case Ndataqid:
		cnt = 0;
		// if ReadFile timeouts and cnt==0 then just re-read
		// this will give osleave() a chance to detect an
		// interruption (i.e. killprog)
		while(cnt==0) {
  			osenter(); 
			good = ReadFile(eia[port].comfh, buf, n, &cnt, NULL);
			SleepEx(0,FALSE);  //allow another thread access to port
			osleave();
			if(!good)
				oserror();
		}
		return cnt;
	case Nctlqid:
		return readnum(offset, buf, n, eia[port].id, NUMSIZE);
	case Nstatqid:
		return rdstat(port, buf, n, offset);
	}

	return 0;
}
Esempio n. 12
0
File: devcmd.c Progetto: 8l/inferno
static void
cmdproc(void *a)
{
	Conv *c;
	int n;
	char status[ERRMAX];
	void *t;

	c = a;
	qlock(&c->l);
	if(Debug)
		print("f[0]=%q f[1]=%q\n", c->cmd->f[0], c->cmd->f[1]);
	if(waserror()){
		if(Debug)
			print("failed: %q\n", up->env->errstr);
		kstrdup(&c->error, up->env->errstr);
		c->state = "Done";
		qunlock(&c->l);
		Wakeup(&c->startr);
		pexit("cmdproc", 0);
	}
	t = oscmd(c->cmd->f+1, c->nice, c->dir, c->fd);
	if(t == nil)
		oserror();
	c->child = t;	/* to allow oscmdkill */
	poperror();
	qunlock(&c->l);
	Wakeup(&c->startr);
	if(Debug)
		print("started\n");
	while(waserror())
		oscmdkill(t);
	osenter();
	n = oscmdwait(t, status, sizeof(status));
	osleave();
	if(n < 0){
		oserrstr(up->genbuf, sizeof(up->genbuf));
		n = snprint(status, sizeof(status), "0 0 0 0 %q", up->genbuf);
	}
	qlock(&c->l);
	c->child = nil;
	oscmdfree(t);
	if(Debug){
		status[n]=0;
		print("done %d %d %d: %q\n", c->fd[0], c->fd[1], c->fd[2], status);
	}
	if(c->inuse > 0){
		c->state = "Done";
		if(c->waitq != nil)
			qproduce(c->waitq, status, n);
	}else
		closeconv(c);
	qunlock(&c->l);
	pexit("", 0);
}
Esempio n. 13
0
File: devfs.c Progetto: 8l/inferno
void
fsclose(Chan *c)
{
	if(c->flag & COPEN){
		osenter();
		close(FS(c)->fd);
		osleave();
	}
	/* don't need to check for CRCLOSE, because Plan 9 itself implements ORCLOSE */
	fsfree(c);
}
Esempio n. 14
0
void
so_listen(int fd)
{
	int r;

	osenter();
	r = listen(fd, 256);
	osleave();
	if(r < 0)
		oserror();
}
Esempio n. 15
0
File: devfs.c Progetto: 8l/inferno
long
fswrite(Chan *c, void *va, long n, vlong offset)
{
	int r;

	osenter();
	r = pwrite(FS(c)->fd, va, n, offset);
	osleave();
	if(r < 0)
		fserr(FS(c));
	return r;
}
Esempio n. 16
0
File: devfs.c Progetto: 8l/inferno
int
fswstat(Chan *c, uchar *dp, int n)
{
	osenter();
	if(FS(c)->fd >= 0)
		n = fwstat(FS(c)->fd, dp, n);
	else
		n = wstat(FS(c)->name->s, dp, n);
	osleave();
	if(n < 0)
		fserr(FS(c));
	return n;
}
Esempio n. 17
0
File: ipif.c Progetto: 8l/inferno
int
so_hangup(int fd, int nolinger)
{
	int r;
	static struct linger l = {1, 0};

	osenter();
	if(nolinger)
		setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof(l));
	r = closesocket(fd);
	osleave();
	return r;
}
Esempio n. 18
0
File: devcmd.c Progetto: 8l/inferno
static long
cmdread(Chan *ch, void *a, long n, vlong offset)
{
	Conv *c;
	char *p, *cmds;
	int fd;

	USED(offset);

	p = a;
	switch(TYPE(ch->qid)) {
	default:
		error(Eperm);
	case Qcmd:
	case Qtopdir:
	case Qconvdir:
		return devdirread(ch, a, n, 0, 0, cmdgen);
	case Qctl:
		sprint(up->genbuf, "%ld", CONV(ch->qid));
		return readstr(offset, p, n, up->genbuf);
	case Qstatus:
		c = cmd.conv[CONV(ch->qid)];
		cmds = "";
		if(c->cmd != nil)
			cmds = c->cmd->f[1];
		snprint(up->genbuf, sizeof(up->genbuf), "cmd/%d %d %s %q %q\n",
			c->x, c->inuse, c->state, c->dir, cmds);
		return readstr(offset, p, n, up->genbuf);
	case Qdata:
	case Qstderr:
		fd = 1;
		if(TYPE(ch->qid) == Qstderr)
			fd = 2;
		c = cmd.conv[CONV(ch->qid)];
		qlock(&c->l);
		if(c->fd[fd] == -1){
			qunlock(&c->l);
			return 0;
		}
		qunlock(&c->l);
		osenter();
		n = read(c->fd[fd], a, n);
		osleave();
		if(n < 0)
			oserror();
		return n;
	case Qwait:
		c = cmd.conv[CONV(ch->qid)];
		return qread(c->waitq, a, n);
	}
}
Esempio n. 19
0
File: devfs.c Progetto: 8l/inferno
Chan*
fsopen(Chan *c, int mode)
{
	osenter();
	FS(c)->fd = open(FS(c)->name->s, mode);
	osleave();
	if(FS(c)->fd < 0)
		fserr(FS(c));
	c->mode = openmode(mode);
	c->offset = 0;
	FS(c)->offset = 0;
	c->flag |= COPEN;
	return c;
}
Esempio n. 20
0
void
so_setsockopt(int fd, int opt, int value)
{
	int r;
	struct linger l;

	if(opt == SO_LINGER){
		l.l_onoff = 1;
		l.l_linger = (short) value;
		osenter();
		r = setsockopt(fd, SOL_SOCKET, opt, (char *)&l, sizeof(l));
		osleave();
	}else
		error(Ebadctl);
	if(r < 0)
		oserror();
}
Esempio n. 21
0
File: devfs.c Progetto: 8l/inferno
void
fsremove(Chan *c)
{
	int r;

	if(waserror()){
		fsfree(c);
		nexterror();
	}
	osenter();
	r = remove(FS(c)->name->s);
	osleave();
	if(r < 0)
		fserr(FS(c));
	poperror();
	fsfree(c);
}
Esempio n. 22
0
void
so_connect(int fd, uchar *raddr, ushort rport)
{
	int r;
	struct sockaddr_storage sa;
	struct sockaddr_in6 *sin6;

	memset(&sa, 0, sizeof(sa));
	sin6 = (struct sockaddr_in6*)&sa;
	sin6->sin6_family = AF_INET6;
	hnputs(&sin6->sin6_port, rport);
	memmove((uchar*)&sin6->sin6_addr, raddr, IPaddrlen);

	osenter();
	r = connect(fd, (struct sockaddr*)sin6, sizeof(*sin6));
	osleave();
	if(r < 0)
		oserror();
}
Esempio n. 23
0
void
so_connect(int fd, unsigned long raddr, unsigned short rport)
{
	int r;
	struct sockaddr sa;
	struct sockaddr_in *sin;

	memset(&sa, 0, sizeof(sa));
	sin = (struct sockaddr_in*)&sa;
	sin->sin_family = AF_INET;
	hnputs(&sin->sin_port, rport);
	hnputl(&sin->sin_addr.s_addr, raddr);

	osenter();
	r = connect(fd, &sa, sizeof(sa));
	osleave();
	if(r < 0)
		oserror();
}
Esempio n. 24
0
static void
eiaclose(Chan *c)
{
	int port = NETID(c->qid.path);

	if((c->flag & COPEN) == 0)
		return;

	switch(NETTYPE(c->qid.path)) {
	case Nctlqid:
	case Ndataqid:
	case Nstatqid:
		if(decref(&eia[port].r) == 0) {
			osenter();
			CloseHandle(eia[port].comfh);
			osleave();
		}
		break;
	}

}
Esempio n. 25
0
File: ipif.c Progetto: 8l/inferno
void
so_connect(int fd, uchar *raddr, ushort rport)
{
	int r;
	struct sockaddr sa;
	struct sockaddr_in *sin;

	if(!isv4(raddr))
		error(Enotv4);

	memset(&sa, 0, sizeof(sa));
	sin = (struct sockaddr_in*)&sa;
	sin->sin_family = AF_INET;
	hnputs(&sin->sin_port, rport);
	memmove(&sin->sin_addr.s_addr, raddr+IPv4off, IPv4addrlen);

	osenter();
	r = connect(fd, &sa, sizeof(sa));
	osleave();
	if(r < 0)
		oserror();
}
Esempio n. 26
0
static long
eiawrite(Chan *c, void *buf, long n, vlong offset)
{
	DWORD cnt;
	char cmd[Maxctl];
	int port = NETID(c->qid.path);
	BOOL good;
	uchar *data;

	if(c->qid.type & QTDIR)
		error(Eperm);

	switch(NETTYPE(c->qid.path)) {
	case Ndataqid:
		cnt = 0;
		data = (uchar*)buf;
		// if WriteFile times out (i.e. return true; cnt<n) then
		// allow osleave() to check for an interrupt otherwise try
		// to send the unsent data.
		while(n>0) {
	  		osenter(); 
			good = WriteFile(eia[port].comfh, data, n, &cnt, NULL);
			osleave(); 
			if(!good)
				oserror();
			data += cnt;
			n -= cnt;
		}
		return (data-(uchar*)buf);
	case Nctlqid:
		if(n >= sizeof(cmd))
			n = sizeof(cmd)-1;
		memmove(cmd, buf, n);
		cmd[n] = 0;
		wrctl(port, cmd);
		return n;
	}
	return 0;
}
Esempio n. 27
0
int
so_accept(int fd, uchar *raddr, ushort *rport)
{
	int nfd, len;
	struct sockaddr_storage sa;
	struct sockaddr_in6 *sin6;

	sin6 = (struct sockaddr_in6*)&sa;

	len = sizeof(*sin6);
	osenter();
	nfd = accept(fd, (struct sockaddr*)&sa, &len);
	osleave();
	if(nfd < 0)
		oserror();

	if(sin6->sin6_family != AF_INET6 || len != sizeof(*sin6))
		error("not AF_INET6");

	memmove(raddr, &sin6->sin6_addr, IPaddrlen);
	*rport = nhgets(&sin6->sin6_port);
	return nfd;
}
Esempio n. 28
0
File: devfs.c Progetto: 8l/inferno
long
fsread(Chan *c, void *va, long n, vlong offset)
{
	int r;

	if(c->qid.type & QTDIR){	/* need to maintain offset only for directories */
		qlock(FS(c));
		if(waserror()){
			qunlock(FS(c));
			nexterror();
		}
		r = fsdirread(c, va, n, offset);
		poperror();
		qunlock(FS(c));
	}else{
		osenter();
		r = pread(FS(c)->fd, va, n, offset);
		osleave();
	}
	if(r < 0)
		fserr(FS(c));
	return r;
}
Esempio n. 29
0
File: devcmd.c Progetto: 8l/inferno
static long
cmdwrite(Chan *ch, void *a, long n, vlong offset)
{
	int i, r;
	Conv *c;
	Cmdbuf *cb;
	Cmdtab *ct;

	USED(offset);

	switch(TYPE(ch->qid)) {
	default:
		error(Eperm);
	case Qctl:
		c = cmd.conv[CONV(ch->qid)];
		cb = parsecmd(a, n);
		if(waserror()){
			free(cb);
			nexterror();
		}
		ct = lookupcmd(cb, cmdtab, nelem(cmdtab));
		switch(ct->index){
		case CMdir:
			kstrdup(&c->dir, cb->f[1]);
			break;
		case CMexec:
			poperror();	/* cb */
			qlock(&c->l);
			if(waserror()){
				qunlock(&c->l);
				free(cb);
				nexterror();
			}
			if(c->child != nil || c->cmd != nil)
				error(Einuse);
			for(i = 0; i < nelem(c->fd); i++)
				if(c->fd[i] != -1)
					error(Einuse);
			if(cb->nf < 1)
				error(Etoosmall);
			kproc("cmdproc", cmdproc, c, 0);	/* cmdproc held back until unlock below */
			free(c->cmd);
			c->cmd = cb;	/* don't free cb */
			c->state = "Execute";
			poperror();
			qunlock(&c->l);
			while(waserror())
				;
			Sleep(&c->startr, cmdstarted, c);
			poperror();
			if(c->error)
				error(c->error);
			return n;	/* avoid free(cb) below */
		case CMkill:
			qlock(&c->l);
			if(waserror()){
				qunlock(&c->l);
				nexterror();
			}
			if(c->child == nil)
				error("not started");
			if(oscmdkill(c->child) < 0)
				oserror();
			poperror();
			qunlock(&c->l);
			break;
		case CMnice:
			c->nice = cb->nf > 1? atoi(cb->f[1]): 1;
			break;
		case CMkillonclose:
			c->killonclose = 1;
			break;
		}
		poperror();
		free(cb);
		break;
	case Qdata:
		c = cmd.conv[CONV(ch->qid)];
		qlock(&c->l);
		if(c->fd[0] == -1){
			qunlock(&c->l);
			error(Ehungup);
		}
		qunlock(&c->l);
		osenter();
		r = write(c->fd[0], a, n);
		osleave();
		if(r == 0)
			error(Ehungup);
		if(r < 0) {
			/* XXX perhaps should kill writer "write on closed pipe" here, 2nd time around? */
			oserror();
		}
		return r;
	}
	return n;
}
Esempio n. 30
0
int
so_recv(int sock, void *va, int len, void *hdr, int hdrlen)
{
	int r, l;
	struct sockaddr_storage sa;
	struct sockaddr_in6 *sin6;
	char h[Udphdrlen];

	osenter();
	if(hdr == 0)
		r = read(sock, va, len);
	else {
		sin6 = (struct sockaddr_in6*)&sa;
		l = sizeof(sa);
		r = recvfrom(sock, va, len, 0, (struct sockaddr*)&sa, &l);
		if(r >= 0) {
			memset(h, 0, sizeof(h));
			switch(hdrlen){
			case OUdphdrlenv4:
				if(v6tov4(h, (uchar*)&sin6->sin6_addr) < 0) {
					osleave();
					error("OUdphdrlenv4 with IPv6 address");
				}
				memmove(h+2*IPv4addrlen, &sin6->sin6_port, 2);
				break;
			case OUdphdrlen:
				memmove(h, (uchar*)&sin6->sin6_addr, IPaddrlen);
				memmove(h+2*IPaddrlen, &sin6->sin6_port, 2);
				break;
			default:
				memmove(h, (uchar*)&sin6->sin6_addr, IPaddrlen);
				memmove(h+3*IPaddrlen, &sin6->sin6_port, 2);
				break;
			}

			/* alas there's no way to get the local addr/port correctly.  Pretend. */
			memset(&sa, 0, sizeof(sa));
			l = sizeof(sa);
			getsockname(sock, (struct sockaddr*)&sa, &l);
			switch(hdrlen){
			case OUdphdrlenv4:
				/*
				 * we get v6Unspecified/noaddr if local address cannot be determined.
				 * that's reasonable for ipv4 too.
				 */
				if(ipcmp(v6Unspecified, (uchar*)&sin6->sin6_addr) != 0
				&& v6tov4(h+IPv4addrlen, (uchar*)&sin6->sin6_addr) < 0) {
					osleave();
					error("OUdphdrlenv4 with IPv6 address");
				}
				memmove(h+2*IPv4addrlen+2, &sin6->sin6_port, 2);
				break;
			case OUdphdrlen:
				memmove(h+IPaddrlen, (uchar*)&sin6->sin6_addr, IPaddrlen);
				memmove(h+2*IPaddrlen+2, &sin6->sin6_port, 2);
				break;
			default:
				memmove(h+IPaddrlen, (uchar*)&sin6->sin6_addr, IPaddrlen);
				memmove(h+2*IPaddrlen, (uchar*)&sin6->sin6_addr, IPaddrlen);	/* ifcaddr */
				memmove(h+3*IPaddrlen+2, &sin6->sin6_port, 2);
				break;
			}
			memmove(hdr, h, hdrlen);
		}
	}
	osleave();
	return r;
}