/* * SUBS.C * * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved. * */ #include "dnet.h" #include #ifdef LATTICE #include #endif #ifndef LATTICE char *FakeArgs; long FakeLen; long FakeGo; long FakeCLI; extern char *malloc(); #endif void dneterror(); typedef struct CommandLineInterface CLI; /* * Add the high-level command to the queue of commands to be sent to * the remote DNET. */ void WriteStream(sdcmd, buf, len, chan) int sdcmd; void *buf; int len; uword chan; { IOSTD *ior = AllocMem(sizeof(IOSTD), MEMF_PUBLIC); if (DDebug) printf("WriteStream: cmd %ld buflen %ld chan %ld\n", sdcmd, len, chan); ior->io_Message.mn_Node.ln_Name = (char *)PKT_REQ; ior->io_Message.mn_ReplyPort = IOSink; ior->io_Data = (APTR)AllocMem(len, MEMF_PUBLIC); ior->io_Length = len; ior->io_Actual = 0; ior->io_Command = sdcmd; ior->io_Error = 0; ior->io_Message.mn_Node.ln_Pri = (chan > MAXCHAN) ? 126 : Chan[chan].pri; BMov(buf, ior->io_Data, len); Enqueue(&TxList, (NODE *)ior); do_wupdate(); } /* * Send a packet to a port. Used to send data/eof/close to channel * ports, and to relay open requests to server ports. */ void WritePort(port, scmd, buf, len, rettype, unit) PORT *port; int scmd; void *buf; int len; int rettype; int unit; { IOSTD *ior = AllocMem(sizeof(IOSTD), MEMF_PUBLIC); if (DDebug) printf("WritePort: cmd %ld buflen %ld rt %ld unit %ld\n", scmd, len, rettype, unit); ior->io_Message.mn_Node.ln_Name = (char *)rettype; ior->io_Message.mn_ReplyPort = (rettype) ? IOSink : DNetPort; ior->io_Unit = (struct Unit *)unit; ior->io_Command = scmd; ior->io_Error = 0; ior->io_Data = NULL; ior->io_Length = 0; ior->io_Actual = 0; if (buf) { ior->io_Data = (APTR)AllocMem(len, MEMF_PUBLIC); ior->io_Length = len; BMov(buf, ior->io_Data, len); } PutMsg(port, (MSG *)ior); if (rettype == PKT_REQ) ++NumCon; } /* * ALLOC_CHANNEL() * * Allocate a channel. Starting at a random point, find the first * free channel. Return -1 if no free channels found. */ alloc_channel() { static ulong ran = 13; long stamp[3]; uword i; DateStamp(stamp); ran = ((ran * 13) + 1) ^ (ran >> 9) + stamp[0] + stamp[1] + stamp[2]; for (i = ran % MAXCHAN; i < MAXCHAN; ++i) { if (Chan[i].state == 0) { return((int)i); } } for (i = ran % MAXCHAN; i != 0xFFFF; --i) { /* Fixed 28 September 1988 */ if (Chan[i].state == 0) { return((int)i); } } return(-1); } /* * Get next node in a linked list. If a pointer to a list base * is passed, gets the first node in the linked list. Returns * NULL if no further nodes in the list. */ GetNext(node) NODE *node; { NODE *next = node->ln_Succ; if (*(long *)next) return((long)next); return(NULL); } /* * CHKBUF * * Generate a two-byte checksum for data. Uses a very simple, but * effective algorithm. */ chkbuf(buf, bytes) ubyte *buf; uword bytes; { uword i; ubyte c1,c2; for (i = c1 = c2 = 0; i < bytes; ++i) { c1 += buf[i]; c2 += c1; } c1 = -(c1 + c2); return((c1<<8)|c2); } void TimerOpen(req, sink) IOT *req; PORT *sink; { if (OpenDevice("timer.device", UNIT_VBLANK, (IOR *)req, 0)) dneterror("timer.device"); req->tr_node.io_Message.mn_ReplyPort = sink; req->tr_node.io_Command = TR_ADDREQUEST; } void TimerClose(req) IOT *req; { CloseDevice((IOR *)req); req->tr_node.io_Device = NULL; } /* * RUNSERVER * * Search the file [S:]DNET.SERVERS for the specified server and * attempt to LoadSeg()/CreateProc() it. The port number must be * non-zero (allows commening out lines in DNET.SERVERS), and * regardless of whether the server is able to DListen(), it must * perform a small handshake sequence with DNET. */ #ifdef LATTICE static struct ProcID *SvBase; void InitServers() { SvBase = NULL; } void RunServer(portnum) uword portnum; { FILE *fi; char buf[128]; char s1[64], s2[64]; long v1; if (!portnum) return; if ((fi = fopen("dnet.servers", "r")) == NULL) fi = fopen("s:dnet.servers", "r"); if (fi) { while (fgets(buf, 128, fi)) { if (sscanf(buf, "%ld %s %s", &v1, s1, s2) == 3 && v1 == portnum) goto success; } fclose(fi); } return; success: fclose(fi); { PROC *myproc; MSG msg; struct ProcID *pid = malloc(sizeof(struct ProcID)); int error; BZero(pid, sizeof(*pid)); error = forkl(s1, "__dnet", "__dnet", NULL, NULL, pid); if (error < 0) { printf("Server not found: %s\n", s1); free(pid); } else { myproc = (PROC *)FindTask(NULL); msg.mn_ReplyPort = &myproc->pr_MsgPort; msg.mn_Node.ln_Name = s2; printf("Starting Server: %s proc %08lx ", s1, pid->process); fflush(stdout); PutMsg(&pid->process->pr_MsgPort, &msg); /* startup handshake */ WaitPort(&myproc->pr_MsgPort); (void)GetMsg(&myproc->pr_MsgPort); puts("started"); fflush(stdout); pid->nextID = SvBase; SvBase = pid; } } } void DeleteServers() { struct ProcID *pid, *pn; for (pid = SvBase; pid; pid = pn) { pn = pid->nextID; for (;;) { Signal((TASK *)pid->process, SIGBREAKF_CTRL_C); printf("Waiting for pid %08lx to die\n", pid->process); if (CheckPort(pid->parent)) break; Delay(10); } wait(pid); free(pid); } } #else static MLIST SvList; void InitServers() { NewList(&SvList); } void RunServer(portnum) uword portnum; { FILE *fi; char buf[128]; char s1[64], s2[64]; long v1; long seg; if (!portnum) return; if ((fi = fopen("dnet.servers", "r")) == NULL) fi = fopen("s:dnet.servers", "r"); if (fi) { while (fgets(buf, 128, fi)) { if (sscanf(buf, "%ld %s %s", &v1, s1, s2) == 3 && v1 == portnum) goto success; } fclose(fi); } return; success: fclose(fi); if (seg = (long)LoadSeg(s1)) { PNODE *pnode; PROC *myproc; PROC *proc; char *name; BSTR oldclicmd; CLI *cli; char *fakestr; MSG msg; void fakeseg(); printf("Addr: %08lx\n", seg); myproc = (PROC *)FindTask(NULL); pnode = AllocMem(sizeof(PNODE), MEMF_PUBLIC); sprintf(pnode->name, "DNET.SERVER.%ld", portnum); pnode->seg = seg; FakeArgs= "__dnet"; FakeLen = 6; FakeGo = ((long)pnode->seg << 2) + 4; FakeCLI = (long)myproc->pr_CLI; printf("Addr: %08lx %08lx\n", seg, FakeGo); fakestr = malloc(32); strcpy(fakestr, "\006__dnet"); cli = BTOC(FakeCLI); oldclicmd = cli->cli_CommandName; cli->cli_CommandName = CTOB(fakestr); if (proc = CreateProc(pnode->name, 0, (long)fakeseg >> 2, 4096)) { proc = (PROC *)((char *)proc - OFFSET(proc,pr_MsgPort)); msg.mn_ReplyPort = &myproc->pr_MsgPort; msg.mn_Node.ln_Name = s2; printf("Starting Server: %s %s\n", s1, pnode->name); PutMsg(&proc->pr_MsgPort, &msg); /* startup handshake */ WaitPort(&myproc->pr_MsgPort); (void)GetMsg(&myproc->pr_MsgPort); AddTail(&SvList, pnode); } else { printf("Unable to start server: %s %s\n", s1, pnode->name); FreeMem(pnode, sizeof(PNODE)); } cli->cli_CommandName = oldclicmd; free(fakestr); } else { printf("Server not found: %s\n", s1); } } void DeleteServers() { PNODE *pnode; PROC *proc; while (pnode = (PNODE *)RemHead(&SvList)) { Forbid(); while (proc = (PROC *)FindTask(pnode->name)) { Signal(proc, SIGBREAKF_CTRL_C); Permit(); printf("Waiting for server %s to exit\n", pnode->name); Forbid(); } Permit(); UnLoadSeg(pnode->seg); FreeMem(pnode, sizeof(PNODE)); } } #asm INCLUDE "exec/types.i" INCLUDE "exec/alerts.i" INCLUDE "exec/nodes.i" INCLUDE "exec/lists.i" INCLUDE "exec/ports.i" INCLUDE "exec/libraries.i" INCLUDE "exec/tasks.i" INCLUDE "exec/memory.i" INCLUDE "exec/execbase.i" INCLUDE "libraries/dos.i" INCLUDE "libraries/dosextens.i" public _geta4 public _LVOFindTask nop nop nop nop _fakeseg: nop nop nop nop bsr _geta4 move.l 4,A6 sub.l A1,A1 jsr _LVOFindTask(A6) move.l D0,A0 move.l _FakeCLI,pr_CLI(A0) ; dummy CLI so Lattice startup doesn't ; croak thinking its a workbench process move.l _FakeArgs,A0 move.l _FakeLen,D0 move.l _FakeGo,A1 jmp (A1) #endasm #endif /* * This cleans up as best as possible, but if there are still ACTIVE * servers or any CLIENTS, this call will not completely get rid of * them... * * Note that this call will KILL any servers automatically started up * by DNET and then UnLoadSeg() them. If the server has already exited, * it simply unloads the server's segment. */ void dneterror(str) char *str; { short i; if (str) puts(str); if (DNetPort) { IOSTD *ior; Forbid(); while ((ior = (IOSTD *)RemHead(&TxList)) || (ior = (IOSTD *)GetMsg(DNetPort))) { ior->io_Error = -1; ReplyMsg((MSG *)ior); } DeletePort(DNetPort); Permit(); DNetPort = NULL; } if (Wto.tr_node.io_Device) { if (Wto_act) { AbortIO((IOR *)&Wto); WaitIO((IOR *)&Wto); Wto_act = 0; } TimerClose(&Wto); } if (Rto.tr_node.io_Device) { if (Rto_act) { AbortIO((IOR *)&Rto); WaitIO((IOR *)&Rto); Rto_act = 0; } TimerClose(&Rto); } if (Cto.tr_node.io_Device) { if (Cto_act) { AbortIO((IOR *)&Cto); WaitIO((IOR *)&Cto); Cto_act = 0; } TimerClose(&Cto); } NetClose(); if (IOSink) DeletePort(IOSink); IOSink = NULL; for (i = 0; i < MAXCHAN; ++i) { if (Chan[i].state != CHAN_FREE && Chan[i].ior) { Chan[i].ior->io_Error = -1; Chan[i].state = CHAN_FREE; ReplyMsg((MSG *)Chan[i].ior); } } DeleteServers(); /* if (IPCPort) CloseIPC(IPCPort); if (DResBase) CloseLibrary(DResBase); */ exit(1); } void fixsignal(port) PORT *port; { if ((long)port->mp_MsgList.lh_Head != (long)&port->mp_MsgList.lh_Tail) Signal(port->mp_SigTask, 1 << port->mp_SigBit); } void SetTimeouts(baud) { WTimeoutVal = ((MAXPKT * 2) * 1000 / (baud / 10 + 1)); RTimeoutVal = ((MAXPKT + 50) * 1000 / (baud / 10 + 1)); WTimeoutVal *= 1000; RTimeoutVal *= 1000; }