/* * DNET.C * * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved. */ #include "dnet.h" #include void do_netreset(); char *GetDEnv(); 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]; #ifdef LATTICE int __stdargs CXBRK(void); /* get around a bug in lcr.lib : onbreak() */ int __stdargs CXBRK(void) { return(0); } #endif void main ARGS((int, char **)); void main(ac,av) int ac; char *av[]; { long sink_mask, dnet_mask/*, ipc_mask*/; long baud = 0; char *netdevice = "serial.device"; long netunit = 0; char *autoclient = "FTERM"; short i; unlink("ENV:DNET_NORUNCLIENT"); #ifndef LATTICE Enable_Abort = 0; #endif BZero(Pkts,sizeof(Pkts)); InitServers(); for (i = 1; i < ac; ++i) { if (strcmp(av[i], "-Getty") == 0) { Getty = 1; AutoHangup = 1; av[i] = ""; } if (strcmp(av[i], "-DEVICE") == 0) { netdevice = av[i + 1]; av[i] = ""; av[i+1] = ""; } if (strcmp(av[i], "-UNIT") == 0) { netunit = atoi(av[i+1]); av[i] = ""; av[i+1] = ""; } } ac = DoOption(ac, av, "p,m%d,b%ld,d%d,n%s,s%s,a,h%d,U%ld,D%s,N%d,8X%d,B%ld,P%d", &PDebug, &Mode7, &baud, &DDebug, &HostName, &autoclient, &AutoAnswer, &AutoHangup, &netunit, &netdevice, &NetworkNum, &Master8, &DialOut, &TOBaud, &Protocol ); 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((LIST *)&TxList); 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(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) { FILE *fi = fopen("T:dscr", "w"); if (fi) { fprintf(fi, "Wait 5\n"); fprintf(fi, "%s -N%ld\n", autoclient, NetworkNum); fclose(fi); Execute("RUN NIL: execute T:dscr", NULL, NULL); } } WriteRestart(); 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 */ IOSTD *ior; while (ior = (IOSTD *)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(IOSTD)); break; case CTO_REQ: /* Only when line idle */ Cto_act = 0; do_cto((IOT *)ior); if (Cd == 0 && AutoHangup) OnLine = 0; break; case RTO_REQ: /* Read timeout, reset READ state */ Rto_act = 0; do_rto((IOT *)ior); break; case WTO_REQ: /* Write-Ack timeout, send CHECK */ Wto_act = 0; do_wto((IOT *)ior); break; case RNET_REQ: /* Receive data ready, interpret */ { char *ptr; long bytes = NetReadReturned(&ptr); do_rnet(ptr, bytes); } if (Cd == 0 && AutoHangup) OnLine = 0; break; case WNET_REQ: NetClWrite((IOSER *)ior); break; } } } if (mask & dnet_mask) { /* Receive commands */ IOSTD *ior; while (ior = (IOSTD *)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, (NODE *)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(IOSTD)); 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, (uword)-1); } break; case DNCMD_INFO: { char *ptr = (char *)ior->io_Data; sprintf(ptr, " Bytes Packets Errors\n" "OUT: %8ld %8ld %8ld\n" "IN : %8ld %8ld %8ld\n" "Garbage Bytes In: %ld\n\n" " 6-expn 7-comp 8-bin\n" "Packet Breakdown Send: %8ld %8ld %8ld\n" "Packet Breakdown Recv: %8ld %8ld %8ld\n", BytesOut, PacketsOut, PacketsResent, BytesIn, PacketsIn, PacketsNakd, GarbageIn, Packets6Out, Packets7Out, Packets8Out, Packets6In, Packets7In, Packets8In ); } 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; case DNCMD_EXEC: Execute((char *)ior->io_Offset, NULL, NULL); break; } if (ior) ReplyMsg((MSG *)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); } void do_netreset() { short i; CHAN *ch; IOSTD *ior; while (ior = (IOSTD *)RemHead((LIST *)&TxList)) { ior->io_Error = 1; ReplyMsg((MSG *)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((MSG *)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((MSG *)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((IOR *)&Cto); Cto_act = 1; } }