#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; }