/* * SUBS.C * * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved * * Support subroutines * */ #include "dnet.h" /* * WRITESTREAM() * * Queues new SCMD_?? level commands to be sent */ WriteStream(sdcmd, buf, len, chan) ubyte *buf; uword chan; { register XIOR *ior = (XIOR *)malloc(sizeof(XIOR)); if (DDebug) printf("-writestr cmd %ld (%ld bytes chan %ld)\n", sdcmd, len, chan); ior->io_Data = (ubyte *)malloc(len); ior->io_Length = len; ior->io_Actual = 0; ior->io_Command = sdcmd; ior->io_Error = 0; ior->io_Channel = chan; ior->io_Pri = (chan > MAXCHAN) ? 126 : Chan[chan].pri; bcopy(buf, ior->io_Data, len); Enqueue(&TxList, ior); /* * REMOVED 21 SEPT 1988 * do_wupdate(); */ } /* * ALLOC_CHANNEL() * * Allocate a free channel. Used in SCMD_OPEN and SCMD_ACKCMD */ alloc_channel() { static ulong ran = 13; register uword i; ran = ((ran * 13) + 1) ^ (ran >> 9) + time(0); for (i = ran % MAXCHAN; i < MAXCHAN; ++i) { if (Chan[i].state == 0) return(i); } for (i = ran % MAXCHAN; i < MAXCHAN; --i) { if (Chan[i].state == 0) return(i); } return(-1); } /* * Remove all nodes with the given channel ID. */ ClearChan(list, chan, all) LIST *list; uword chan; { register XIOR *io, *in; for (io = (XIOR *)list->lh_Head; io != (XIOR *)&list->lh_Tail; io = in) { in = (XIOR *)io->io_Node.ln_Succ; if (io->io_Channel == chan) { if (all || io->io_Command == SCMD_DATA) { io->io_Node.ln_Succ->ln_Pred = io->io_Node.ln_Pred; io->io_Node.ln_Pred->ln_Succ = io->io_Node.ln_Succ; free(io->io_Data); free(io); } } } } /* * Queue a packet into a prioritized list. FIFO is retained for packets * of the same priority. This implements one level of channel priorities, * before the packets actually get queued to the network. Since up to * 4 packets might be queued (200 * 4 = 800 bytes of data or 4 seconds @ * 2400 baud), a second level of prioritization will also reduce the * physical packet size when two channels at relatively large differing * priorities are in use. * * These and other list routines compatible with Amiga list routines. */ Enqueue(list, ior) LIST *list; XIOR *ior; { register XIOR *io; char pri = ior->io_Pri; io = (XIOR *)list->lh_Head; while (io != (XIOR *)&list->lh_Tail) { if (pri > io->io_Pri) break; io = (XIOR *)io->io_Node.ln_Succ; } ior->io_Node.ln_Succ = (NODE *)io; ior->io_Node.ln_Pred = io->io_Node.ln_Pred; ior->io_Node.ln_Succ->ln_Pred = (NODE *)ior; ior->io_Node.ln_Pred->ln_Succ = (NODE *)ior; } AddTail(list, node) LIST *list; NODE *node; { node->ln_Succ = (NODE *)&list->lh_Tail; node->ln_Pred = list->lh_TailPred; node->ln_Succ->ln_Pred = node; node->ln_Pred->ln_Succ = node; } AddHead(list, node) LIST *list; NODE *node; { node->ln_Succ = list->lh_Head; node->ln_Pred = (NODE *)list; node->ln_Succ->ln_Pred = node; node->ln_Pred->ln_Succ = node; } ubyte * RemHead(list) LIST *list; { NODE *node; node = list->lh_Head; if (node->ln_Succ == NULL) return(NULL); node->ln_Succ->ln_Pred = node->ln_Pred; node->ln_Pred->ln_Succ = node->ln_Succ; return((ubyte *)node); } NewList(list) LIST *list; { list->lh_Head = (NODE *)&list->lh_Tail; list->lh_Tail = NULL; list->lh_TailPred = (NODE *)&list->lh_Head; } GetNext(node) NODE *node; { register NODE *next = node->ln_Succ; if (*(long *)next) return((long)next); return(NULL); } /* * CHKBUF * * Checksum a buffer. Uses a simple, but supposedly very good * scheme. */ chkbuf(buf, bytes) register ubyte *buf; register uword bytes; { register uword i; register ubyte c1,c2; for (i = c1 = c2 = 0; i < bytes; ++i) { c1 += buf[i]; c2 += c1; } c1 = -(c1 + c2); return((c1<<8)|c2); } /* * Write timeout signal handler. */ sigwto() { WTimedout = 1; } TimerOpen() { static struct sigvec SA = { sigwto, 0, 0 }; sigvec(SIGALRM, &SA, NULL); } TimerClose() { signal(SIGALRM, SIG_IGN); } WTimeout(secs) { static struct itimerval itv; struct itimerval ov; long mask; itv.it_value.tv_sec = secs; itv.it_value.tv_usec= 0; mask = sigblock(sigmask(SIGALRM)); setitimer(ITIMER_REAL, &itv, &ov); Wto_act = 1; WTimedout = 0; sigsetmask(mask); if (DDebug) fprintf(stderr, "WTimeout set\n"); } dneterror(str) char *str; { extern int errno; register short i; int er = errno; NetClose(); TimerClose(); if (str) fprintf(stderr, "%s %d\n", str, er); else fprintf(stderr, "-end-\n"); exit(1); } /* * setenv(name, str). name must be of the form "NAME=" */ setenv(name, str) char *name; char *str; { extern char **environ; static char **elist; static int elen; char *ptr; int i, len; len = strlen(name); if (elist == NULL) { for (i = 0; environ[i]; ++i); elist = (char **)malloc((i+3)*sizeof(char *)); elen = i + 3; bcopy(environ, elist, i*sizeof(char *)); environ = elist; } for (i = 0; elist[i]; ++i) { if (strncmp(elist[i], name, len) == 0) break; } if (i == elen) { elen += 4; elist = environ = (char **)realloc(elist, elen*sizeof(char *)); } ptr = (char *)malloc(len + strlen(str) + 1); sprintf(ptr, "%s%s", name, str); if (elist[i]) { elist[i] = ptr; } else { elist[i] = ptr; elist[i+1] = NULL; elen = i + 1; } } void startserver(port) uword port; { char dir[MAXPATHLEN]; struct passwd pw_info; FILE *fi; if (!port) return; if (getenv("DNETDIR")) { strcpy(dir, getenv("DNETDIR")); strcat(dir, "dnet.servers"); if (fi = fopen(dir, "r")) { if (scan_for_server(fi, port)) return; } } pw_info = *getpwuid(getuid()); strcpy(dir, pw_info.pw_dir); strcat(dir, "/.dnet/dnet.servers"); if (fi = fopen(dir, "r")) { if (scan_for_server(fi, port)) return; } /* * LAST TRY */ if (fi = fopen(LASTTRYDNETSERVERS, "r")) { if (scan_for_server(fi, port)) return; } fprintf(stderr, "Unable to find one of (1) dnet.servers or (2) server\n"); fprintf(stderr, "entry for port %d\n", port); fflush(stderr); return; } scan_for_server(fi, port) FILE *fi; short port; { char buf[256]; char path[MAXPATHLEN]; char cdir[MAXPATHLEN]; long portno; short found = 0; void checktilda(); while (fgets(buf, 256, fi)) { if (sscanf(buf, "%ld %s %s", &portno, path, cdir) == 3) { checktilda(path); checktilda(cdir); if (portno == port) { if (!fork()) { int i; fclose(fi); setuid(getuid()); signal(SIGHUP, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGCHLD, SIG_DFL); signal(SIGTSTP, SIG_IGN); ioctl(open("/dev/tty", 2), TIOCNOTTY, NULL); i = open("/dev/null", O_RDWR, 0); dup2(i, 0); dup2(i, 1); for (i = 3; i < 256; ++i) close(i); sprintf(buf, "server.%ld.%ld", port, getuid()); execl(path, buf, cdir, NULL); fprintf(stderr, "Unable to exec server: %s\n", path); fflush(stderr); _exit(1); } sleep(4); /* is a hack */ found = 1; break; } } } fclose(fi); return(found); } void checktilda(buf) char *buf; { if (buf[0] == '~') { short bindex = 1; short pathlen; struct passwd pw_info, *pw; pw_info.pw_dir = getenv("HOME"); if (buf[1] && buf[1] != '/') { char username[128]; while (buf[bindex] && buf[bindex] != '/') ++bindex; bcopy(buf+1, username, bindex-1); username[bindex-1] = 0; if (pw = getpwnam(username)) { pw_info = *pw; } else { fprintf(stderr, "Unable to find password entry for %s\n", username ); fprintf(stderr, "passing /tmp as dir for server"); fflush(stderr); pw_info.pw_dir = "/tmp"; } } /* * ~[username] -> */ pathlen = strlen(pw_info.pw_dir); bcopy(buf + bindex, buf + pathlen, strlen(buf + bindex) + 1); bcopy(pw_info.pw_dir, buf, pathlen); } fflush(stderr); }