/* * DNET.C * * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved * * Handles action on all active file descriptors and dispatches * to the proper function in FILES.C * */ #include "dnet.h" #include #include handle_child() { union wait stat; struct rusage rus; while (wait3(&stat, WNOHANG, &rus) > 0); } char * showselect(ptr) fd_set *ptr; { static char buf[FD_SETSIZE+32]; short i; for (i = 0; i < FD_SETSIZE; ++i) { buf[i] = (FD_ISSET(i, ptr)) ? '1' : '0'; } buf[i] = 0; return(buf); } loganddie() { fflush(stderr); fprintf(stderr, "\nHUPSIGNAL\n"); perror("HUP, last error:"); fprintf(stderr, "Last select return: "); fprintf(stderr, " %s\n", showselect(&Fdread)); fprintf(stderr, " %s\n", showselect(&Fdwrite)); fprintf(stderr, " %s\n", showselect(&Fdexcept)); fprintf(stderr, "RcvData = %ld\n", RcvData); fprintf(stderr, "RChan/WChan = %ld/%ld\n", RChan, WChan); fprintf(stderr, "RPStart = %ld\n", RPStart); fprintf(stderr, "WPStart = %ld\n", WPStart); fprintf(stderr, "WPUsed = %ld\n", WPUsed); fprintf(stderr, "RState = %ld\n", RState); fflush(stderr); kill(0, SIGILL); exit(1); } #define SASIZE(sa) (sizeof(sa)-sizeof((sa).sa_data)+strlen((sa).sa_data)) main(ac,av) char *av[]; { long sink_mask, dnet_mask; long mark = 0; ubyte notdone; extern void RcvInt(); if (getenv("DNETDIR")) chdir(getenv("DNETDIR")); freopen("DNET.LOG", "w", stderr); signal(SIGINT, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGCHLD, handle_child); signal(SIGHUP, loganddie); bzero(Pkts,sizeof(Pkts)); setlistenport(""); if (ac > 1) { DDebug = 1; fprintf(stderr, "Debugger running\n"); } NewList(&TxList); Fdperm[0] = 1; Fdstate[0] = RcvInt; FD_SET(0, &Fdread); FD_SET(0, &Fdexcept); fprintf(stderr, "DNET RUNNING, Listenfd=%ld\n", DNet_fd); NetOpen(); /* initialize network and interrupt driven read */ TimerOpen(); /* initialize timers */ do_netreset(); do_restart(); notdone = 1; while (notdone) { /* * MAIN LOOP. select() on all the file descriptors. Set the * timeout to infinity (NULL) normally. However, if there is * a pending read or write timeout, set the select timeout * to 2 seconds in case they timeout before we call select(). * (i.e. a timing window). OR, if we are in the middle of a * read, don't use descriptor 0 and timeout according to * the expected read length, then set the descriptor as ready. */ fd_set fd_rd; fd_set fd_wr; fd_set fd_ex; struct timeval tv, *ptv; int err; fd_rd = Fdread; fd_wr = Fdwrite; fd_ex = Fdexcept; tv.tv_sec = 0; /* normally wait forever for an event */ tv.tv_usec= 0; ptv = NULL; if ((Rto_act || Wto_act)) { /* unless timeout pending */ ptv = &tv; tv.tv_sec = 2; } /* ... or expecting data (don't just wait for one byte). * * This is an attempt to reduce the CPU usage for the process. * If we are expecting data over the serial line, then don't * return from the select() even if data is available, but * wait for the timeout period indicated before reading the * data. Don't wait more than 64 byte times or we may loose * some data (the silo's are only so big.. like 128 bytes). * * Currently, USecPerByte is not set properly (set for 9600 baud) */ if (RExpect) { ptv = &tv; tv.tv_usec= USecPerByte * ((RExpect < 64) ? RExpect : 64); tv.tv_sec = 0; FD_CLR(0, &fd_rd); } err = select(FD_SETSIZE, &fd_rd, &fd_wr, &fd_ex, ptv); if (RExpect) { FD_SET(0, &fd_rd); /* pretend data ready */ } if (DDebug) fprintf(stderr, "SERR %ld %ld %08lx %08lx\n", err, errno, RExpect, ptv ); if (RTimedout) { RTimedout = 0; do_rto(); mark = 0; } if (WTimedout) { WTimedout = 0; do_wto(); } if (err < 0) { if (errno == EBADF) { perror("select"); dneterror(NULL); } continue; } { register short i; register short j; register long mask; for (i = 0; i < FD_SETSIZE/NFDBITS; ++i) { if (mask = fd_ex.fds_bits[i]) { for (j = i * NFDBITS; mask; (mask >>= 1),(++j)) { if (mask & 1) (*Fdstate[j])(2,j); } } if (mask = fd_wr.fds_bits[i]) { for (j = i * NFDBITS; mask; (mask >>= 1),(++j)) { if (mask & 1) (*Fdstate[j])(1,j); } } if (mask = fd_rd.fds_bits[i]) { for (j = i * NFDBITS; mask; (mask >>= 1),(++j)) { if (mask & 1) (*Fdstate[j])(0,j); } } } } if (RcvData != mark) mark = do_rnet(); do_wnet(); } dneterror(NULL); } void nop() { } do_netreset() { register short i; register CHAN *ch; for (i = 0; i < FD_SETSIZE; ++i) { if (!Fdperm[i]) Fdstate[i] = nop; } for (i = 0, ch = Chan; i < MAXCHAN; ++i, ++ch) { switch(ch->state) { case CHAN_OPEN: case CHAN_LOPEN: /* pending on network */ case CHAN_CLOSE: if (ch->fd >= 0) { FD_CLR(ch->fd, &Fdread); FD_CLR(ch->fd, &Fdexcept); Fdstate[ch->fd] = nop; close(ch->fd); ch->fd = -1; ch->state = CHAN_FREE; ch->flags = 0; --NumCon; } ClearChan(&TxList, i, 1); break; } } RPStart = 0; WPStart = 0; WPUsed = 0; RState = 0; RChan = 0; WChan = 0; } do_restart() { static ubyte buf[3] = { SYNC, PKCMD_RESTART, (SYNC<<1)^PKCMD_RESTART }; Restart = 1; NetWrite(buf, sizeof(buf)); WTimeout(WTIME); } setlistenport(remotehost) char *remotehost; { static struct sockaddr sa[2]; int s; extern void do_localopen(); if (DNet_fd >= 0) { unlink(sa[0].sa_data); Fdstate[DNet_fd] = nop; Fdperm[DNet_fd] = 0; FD_CLR(DNet_fd, &Fdread); FD_CLR(DNet_fd, &Fdexcept); close(DNet_fd); } setenv("DNETHOST=", remotehost); sprintf(sa[0].sa_data, "DNET.%s", remotehost); unlink(sa[0].sa_data); sa[0].sa_family = AF_UNIX; s = socket(PF_UNIX, SOCK_STREAM, 0); fcntl(s, F_SETOWN, getpid()); fcntl(s, F_SETFL, FNDELAY); if (bind(s, &sa[0], SASIZE(sa[0])) < 0) { perror("bind"); exit(1); } if (listen(s, 5) < 0) { unlink(sa[0].sa_data); perror("listen"); exit(1); } DNet_fd = s; Fdstate[DNet_fd] = do_localopen; Fdperm[DNet_fd] = 1; FD_SET(DNet_fd, &Fdread); FD_SET(DNet_fd, &Fdexcept); }