/* * DNET.C * * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved. */ #include "dnet.h" #include #include short Deemu[] = { DMSTRT, 0, 0, DMNW , 0,10, 50, 50, 320, 100, 0xFFFF, DMEND , 0, 0 }; extern int Enable_Abort; long DResBase; char PortName[sizeof(DNETPORTNAME)+32]; main(ac,av) char *av[]; { long sink_mask, dnet_mask, ipc_mask; long baud = 0; char *netdevice = "serial.device"; long netunit = 0; char *autoclient = "FTERM"; unlink("ENV:DNET_NORUNCLIENT"); Enable_Abort = 0; bzero(Pkts,sizeof(Pkts)); if ((DResBase = (long)OpenLibrary("dres.library", 0)) == NULL) { puts("Unable to open DRES.LIBRARY"); exit(1); } ac = DoOption(ac, av, "p,b%ld,d%d,n%s,s%s,a,h%d,U%ld,D%s,N%d,8X%d,B%ld", &PDebug, &baud, &DDebug, &HostName, &autoclient, &AutoAnswer, &AutoHangup, &netunit, &netdevice, &NetworkNum, &Master8, &DialOut, &TOBaud ); if (ac < 0) { puts("Unknown option, valid options:\n"); puts("dnet -pb#B#d#nsaU#DN8"); dneterror("Unknown switch"); } if (AutoAnswer) { AutoHangup = 1; DialOut = 0; } sprintf(PortName, "%s%d", DNETPORTNAME, NetworkNum); { PORT *port; if (port = (PORT *)FindPort(PortName)) { puts("DNET: Network number in use"); CloseLibrary(DResBase); exit(1); } } DNetPort = (PORT *)CreatePort(PortName, 0); IOSink = (PORT *)CreatePort(NULL,0); IPCPort = (PORT *)OpenIPC("dnet.CMD", 0); if (!DNetPort || !IOSink) dneterror("CreatePort"); NewList(&TxList); NewList(&SvList); Rto_act = Wto_act = Cto_act = 0; NetOpen(IOSink, netdevice, netunit, &baud); TimerOpen(&Rto, IOSink); TimerOpen(&Wto, IOSink); TimerOpen(&Cto, IOSink); if (TOBaud) SetTimeouts(TOBaud); else SetTimeouts(Baud); NetStartRead(&Raux->sync, 3); do_dnetwindow(baud); if (Quit) dneterror(NULL); Rto.tr_node.io_Message.mn_Node.ln_Name = (char *)RTO_REQ; Wto.tr_node.io_Message.mn_Node.ln_Name = (char *)WTO_REQ; Cto.tr_node.io_Message.mn_Node.ln_Name = (char *)CTO_REQ; sink_mask = 1 << IOSink->mp_SigBit; dnet_mask = 1 << DNetPort->mp_SigBit; ipc_mask = 1 << IPCPort->mp_SigBit; do_netreset(); loop: if (strcmp(autoclient, "-") != 0) { char buf[64]; char *tmp; if ((tmp = GetDEnv("DNET_NORUNCLIENT")) == NULL) { sprintf(buf, "RUN NIL: %s -N%ld", autoclient, NetworkNum); if (Execute(buf, NULL, NULL) == 0) { puts("Unable to RUN FTERM (path not setup?)"); puts("You can do it yourself"); } } else { free(tmp); } } NetWrite(RestartPkt, 3, 1); Restart = 1; OnLine = 1; /* * NOTE: Routines must be particularly careful not to clear the * signal mask unless it doesn't matter. Specifically, * routines in the dnet_mask section cannot arbitrarily * clear the signal associated with the sink_mask section. * * If you look at NetWrite(), you will note that the signal * is restored if it must do a WaitIO(). */ /* * Immediate return from initial Wait() ... due to looping it is * possible one or more requests is ready but the signal bit has * already been cleared. */ Signal(FindTask(NULL), ipc_mask|sink_mask|dnet_mask); while (!Quit && OnLine) { long mask = Wait(ipc_mask|sink_mask|dnet_mask|SIGBREAKF_CTRL_C); if (mask & ipc_mask) handle_ipc(); if (mask & sink_mask) { /* IOSink returns */ register IOR *ior; while (ior = (IOR *)GetMsg(IOSink)) { switch((long)ior->io_Message.mn_Node.ln_Name) { case PKT_REQ: --NumCon; if (ior->io_Length) FreeMem(ior->io_Data, ior->io_Length); FreeMem(ior, sizeof(IOR)); break; case CTO_REQ: /* Only when line idle */ Cto_act = 0; do_cto(ior); if (Cd == 0 && AutoHangup) OnLine = 0; break; case RTO_REQ: /* Read timeout, reset READ state */ Rto_act = 0; do_rto(ior); break; case WTO_REQ: /* Write-Ack timeout, send CHECK */ Wto_act = 0; do_wto(ior); break; case RNET_REQ: /* Receive data ready, interpret */ NetReadReturned(); do_rnet(ior); if (Cd == 0 && AutoHangup) OnLine = 0; break; case WNET_REQ: /* Write data sent, start WTO */ NetClWrite(ior); do_wnet(ior); break; case IGWNET_REQ: NetClWrite(ior); break; } } } if (mask & dnet_mask) { /* Receive commands */ register IOR *ior; while (ior = (IOR *)GetMsg(DNetPort)) { ior->io_Actual = 0; switch(ior->io_Command) { case DNCMD_WRITE: /* write data to net */ { uword chan = (ulong)ior->io_Unit; if (Chan[chan].state != CHAN_OPEN) { ior->io_Error = 1; break; } ior->io_Error = 0; ior->io_Command = SCMD_DATA; ior->io_Message.mn_Node.ln_Pri = Chan[chan].pri; Enqueue(&TxList, ior); ior = NULL; } break; case DNCMD_SOPEN: /* Reply from server port on remote */ /* open request */ { CACKCMD ack; uword chan = (ulong)ior->io_Unit; ack.chanh = chan >> 8; ack.chanl = chan; ack.error = ior->io_Error; WriteStream(SCMD_ACKCMD, &ack, sizeof(ack), chan); if (ack.error) { Chan[chan].state = CHAN_FREE; --NumCon; } else { if (Chan[chan].state == CHAN_CLOSE && !ack.error) { WritePort(Chan[chan].port, DNCMD_CLOSE, NULL, 0, PKT_REQ, chan); goto sopenbrk; } Chan[chan].state = CHAN_OPEN; Chan[chan].port = (PORT *)ior->io_Offset; Chan[chan].flags = CHANF_ROK|CHANF_WOK; } sopenbrk: if (ior->io_Length) FreeMem(ior->io_Data, ior->io_Length); FreeMem(ior, sizeof(IOR)); ior = NULL; } break; case DNCMD_EOF: { CEOFCMD eof; uword chan = (ulong)ior->io_Unit; ior->io_Error = 0; eof.chanh = chan >> 8; eof.chanl = chan; eof.flags = CHANF_ROK; WriteStream(SCMD_EOFCMD, &eof, sizeof(CEOFCMD), chan); Chan[chan].flags &= ~CHANF_WOK; } break; case DNCMD_IOCTL: { CIOCTL cio; uword chan = (ulong)ior->io_Unit; ior->io_Error = 0; cio.chanh = chan >> 8; cio.chanl = chan; cio.valh = (ubyte)((ulong)ior->io_Data >> 24); cio.vall = (ubyte)((ulong)ior->io_Data >> 16); cio.valaux = (ubyte)((ulong)ior->io_Data >> 8); cio.cmd = (ubyte)(ulong)ior->io_Data; WriteStream(SCMD_IOCTL, &cio, sizeof(CIOCTL), chan); } break; case DNCMD_QUIT: { char dummy; WriteStream(SCMD_QUIT, &dummy, 1, -1); } break; case DNCMD_INFO: { char *ptr = (char *)ior->io_Data; sprintf(ptr, " Bytes Packets Errors\n"); ptr += strlen(ptr); sprintf(ptr, "OUT: %8ld %8ld %8ld\n", BytesOut, PacketsOut, PacketsResent); ptr += strlen(ptr); sprintf(ptr, "IN : %8ld %8ld %8ld\n", BytesIn, PacketsIn, PacketsNakd); ptr += strlen(ptr); sprintf(ptr, "Garbage Bytes In: %ld\n", GarbageIn); } break; case DNCMD_OPEN: ior->io_Error = 0; { uword chan = alloc_channel(); COPEN co; if (chan >= MAXCHAN) { ior->io_Error = 1; break; } co.chanh = chan >> 8; co.chanl = chan; co.porth = (ulong)ior->io_Unit >> 8; /* port # */ co.portl = (ulong)ior->io_Unit; co.error= 0; co.pri = (char)(long)ior->io_Message.mn_Node.ln_Name; Chan[chan].ior = ior; Chan[chan].port= (PORT *)ior->io_Offset; Chan[chan].state = CHAN_LOPEN; Chan[chan].flags = 0; Chan[chan].pri = ior->io_Message.mn_Node.ln_Pri; WriteStream(SCMD_OPEN, &co, sizeof(COPEN), chan); ior = NULL; } break; case DNCMD_CLOSE: /* same io_Command for CCTL_? */ ior->io_Error = 0; { CCLOSE cc; uword chan = (ulong)ior->io_Unit; cc.chanh = chan >> 8; cc.chanl = chan; WriteStream(SCMD_CLOSE, &cc, sizeof(CCLOSE), chan); Chan[chan].ior = ior; Chan[chan].state = CHAN_CLOSE; Chan[chan].flags |= CHANF_LCLOSE; if (Chan[chan].flags & CHANF_RCLOSE) { Chan[chan].state = CHAN_FREE; Chan[chan].ior = NULL; } else { ior = NULL; } } break; } if (ior) ReplyMsg(ior); } } if (mask & SIGBREAKF_CTRL_C) OnLine = 0; do_wupdate(); } do_netreset(); if (!Cd) { ResetConnect(); ResetIdle(); } if (!Quit) do_dnetwindow(baud); if (!Cd) { ResetConnect(); ResetIdle(); } if (!Quit) goto loop; dneterror(NULL); } do_netreset() { register short i; register CHAN *ch; register IOR *ior; while (ior = RemHead(&TxList)) { ior->io_Error = 1; ReplyMsg(ior); } for (i = 0, ch = Chan; i < MAXCHAN; ++i, ++ch) { switch(ch->state) { case CHAN_OPEN: WritePort(Chan[i].port, DNCMD_CLOSE, NULL, 0, PKT_REQ, i); case CHAN_ROPEN: /* pending on listen port */ ch->state = CHAN_CLOSE; ch->flags = CHANF_RCLOSE; ch->ior = NULL; break; case CHAN_LOPEN: /* pending on network */ ch->ior->io_Error = 1; ReplyMsg(ch->ior); ch->ior = NULL; ch->state = CHAN_FREE; ch->flags = 0; --NumCon; break; case CHAN_CLOSE: if (!(ch->flags & CHANF_LCLOSE)) break; ch->ior->io_Error = 1; ReplyMsg(ch->ior); ch->ior = NULL; ch->state = CHAN_FREE; ch->flags = 0; --NumCon; } } RPStart = 0; WPStart = 0; WPUsed = 0; RState = 0; RChan = 0; WChan = 0; if (!Cto_act) { Cto.tr_time.tv_secs = 1; Cto.tr_time.tv_micro= 0; SendIO(&Cto); Cto_act = 1; } }