V10/ipc/mgrs/ndkmgr/listen.c

Compare this file to the similar file:
Show the results in this format:

#include <sys/filio.h>
#include <sys/dkio.h>
#include <stdio.h>
#include <errno.h>
#include <libc.h>
#include <ipc.h>
#include "dk.h"
#include "dkwindow.h"
#include "defs.h"

/* imported */
extern int dkp_ld;
extern int unit;
extern char *dkfilename();

/* global to this module */
static int chan;
static long tstamp[256];
static int traffic;
static int listenfd;
static int newfd;		/* used to keep channel open until accept/reject */

void net_reject();

ipcinfo *
net_listen(fd)
	int fd;
{
	static char buf[256];
	static ipcinfo info;
	static char param[128];
	static stretch newipcname;
	char *fp, *tp, *physaddr;
	char *line[12];
	char *field[12];
	long ts, window;
	int n;

restart:
	physaddr="";
	listenfd = fd;

	/* get the request */
	if ((n = read(fd, buf, sizeof(buf)-1)) <= 0) {
		ABORT(errno, "bad read in listen", NULLINFO);
		return NULL;
	}
	buf[n] = '\0';

	/* initialize the info struct */
	info.rfd = info.cfd = -1;
	info.user = info.machine = NULL;
	info.uid = info.gid = -1;
	info.param = NULL;
	info.flags = IPC_OPEN;

	/* break into lines */
	setfields("\n");
	n = getfields(buf, line, 12);
	if (n < 2) {
		ABORT(EIO, "bad message from dk (1 line)", NULLINFO);
		return NULL;
	}

	/* line 0 is `chan.tstamp.traffic[.urpparms.window]' */
	setfields(".");
	window = 0;
	switch(getfields(line[0], field, 5)){
	case 5:
		/*
		 *  generic way of passing window
		 */
		traffic = atoi(field[4]);
		if(traffic > 0 && traffic <31)
			window = 1<<traffic;
		else
			window = 0;
		/*
		 *  intentional fall through
		 */
	case 3:
		chan = atoi(field[0]);
		ts = atoi(field[1]);
		if(ts == tstamp[chan]) {
			logevent("duplicate timestamp %ld ignored, ch %d\n", ts, chan);
			goto restart;
		}
		/*
		 *  1127 way of passing window
		 */
		traffic = atoi(field[2]);
		if(window == 0 && W_VALID(traffic))
			window = W_VALUE(W_ORIG(traffic));
		info.param = W_TRAF(traffic)==0 ? "light" : "heavy";
		break;
	default:
		ABORT(ENXIO, "bad message from dk(bad first line)", NULLINFO);
		return NULL;
		break;
	}

	/*
	 *  Line 1 is `my-dk-name.service[.more-things]'.
	 *  Special characters are escaped by '\'s.
	 */
	info.myname = line[1];
	info.name = "";
	for(tp=line[1]; tp && *tp; tp++) {
		if (*tp == '.') {
			if (*info.name) {
				*tp = '!';
				break;
			} else {
				*tp = '\0';
				info.name = tp+1;
			}
		} else if (*tp == '\\')
			strcpy(tp, tp+1);
	}

	/* the rest is variable length */
	switch(n) {
	case 2:
		/* no more lines */
		info.machine = NULL;
		info.user = NULL;
		info.param = NULL;
		break;
	case 3:
		/* line 2 is `source.user.param1.param2' */
		getfields(line[2], field, 3);
		info.machine = field[0];
		info.user = field[1];
		info.param = field[2];
		break;
	case 4:
		/* line 2 is `user.param1.param2' */
		getfields(line[2], field, 2);
		info.user = field[0];
		info.param = field[1];

		/* line 3 is `source.node.mod.chan' */
		info.machine = line[3];
		tp=strchr(line[3], '.');
		if(tp) {
			*tp='\0';
			physaddr=tp+1;
		}
		break;
	default:
		ABORT(ENXIO, "bad message from dk(>4 line)", NULLINFO);
		return NULL;
	}
	logevent("src(%s.%s)ch(%d)tr(%d)wo(%d)wd(%d)ts(%ld)w(%d)\n",
		info.machine, physaddr, chan, W_TRAF(traffic),
		W_VALID(traffic)?W_VALUE(W_ORIG(traffic)):0,
		W_VALID(traffic)?W_VALUE(W_DEST(traffic)):0, ts, window);

	/* open the channel */
	fp = dkfilename(traffic, unit, chan);
	tstamp[chan] = ts;
	if ((info.rfd = open(fp, 2))<0) {
		char reply[64];

		sprintf(reply, "%u.%u.%u", chan, tstamp[chan], utodkerr(errno));
		write(listenfd, reply, strlen(reply));
		logevent("can't open %s, errno %d\n", fp, errno);
		goto restart;
	}
	flabclr(info.rfd);
	set2stsrc(info.rfd, "dk!", info.machine);
	if (dkproto(info.rfd, dkp_ld) < 0) {
		close(info.rfd);
		ABORT(EBUSY, "can't push line discipline",NULLINFO);
		return NULL;
	}
	setwins(info.rfd, window);
	if (dkproto(info.rfd, dkp_ld) < 0) {
		logevent("can't push line dkp_ld errno = %d\n", errno);
		close(info.rfd);
		ABORT(EIO, "can't push line discipline",NULLINFO);
		net_reject(&info, errno, errstr);
		goto restart;
	}
	newfd = dup(info.rfd);
	fchown(info.rfd, 0, 0);
	fchmod(info.rfd, 0600);
	ioctl(info.rfd, DIOCNXCL, 0);

	if (info.user==NULL || info.user[0]=='\0')
		info.user = "_unknown_";
	if (info.machine==NULL || info.machine[0]=='\0')
		info.machine = "_unknown_";
	if (physaddr[0]!='\0'){
		strcpy(param, info.param ? info.param: "");
		strcat(param, " PSOURCE=");
		strcat(param, physaddr);
		info.param=param;
	}

	/* set the network name */
	_strcat(&newipcname, info.myname, "!", info.name);
	ipcname = newipcname.ptr;

	return (&info);
}

setwins(f, window)
	long window;
{
	char ws[5];

	if (window>0) {
		/* last possible sanity check */
		if(window<64)
			window = 64;

		/* try 3 X 1/4 */
		window >>= 2;
		ws[0] = window;
		ws[1] = window>>8;
		ws[2] = window>>16;
		ws[3] = window>>24;
		ws[4] = 3;
		ioctl(f, DIOCXWIN, ws);
	}
}

void
net_accept(ip)
	ipcinfo *ip;
{
	char reply[64];

	USE(ip);
	sprintf(reply, "%u.%u.%u", chan, tstamp[chan], 0);
	write(listenfd, reply, strlen(reply));
	close(newfd);
}

void
net_reject(ip, error, msg)
	ipcinfo *ip;
	int error;
	char *msg;
{
	char reply[64];

	sprintf(reply, "%u.%u.%u", chan, tstamp[chan], utodkerr(error));
	write(listenfd, reply, strlen(reply));
	close(ip->rfd);
	ip->rfd = -1;
	close(newfd);
	errno = error;
	errstr = msg;
}