/* * SUBS.C * * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved. * */ #include "dnet.h" #include /* * Add the high-level command to the queue of commands to be sent to * the remote DNET. */ WriteStream(sdcmd, buf, len, chan) uword chan; { register IOR *ior = (IOR *)AllocMem(sizeof(IOR), 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; CopyMem(buf, ior->io_Data, len); Enqueue(&TxList, 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. */ WritePort(port, scmd, buf, len, rettype, unit) PORT *port; ubyte *buf; { register IOR *ior = (IOR *)AllocMem(sizeof(IOR), 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; CopyMem(buf, ior->io_Data, len); } PutMsg(port, 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]; register 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(i); } } for (i = ran % MAXCHAN; i < MAXCHAN; --i) { if (Chan[i].state == 0) { return(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; { register 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) 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); } TimerOpen(req, sink) IOT *req; PORT *sink; { if (OpenDevice("timer.device", UNIT_VBLANK, req, 0)) dneterror("timer.device"); req->tr_node.io_Message.mn_ReplyPort = sink; req->tr_node.io_Command = TR_ADDREQUEST; } TimerClose(req) IOT *req; { CloseDevice(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. */ 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 = LoadSeg(s1)) { PNODE *pnode; PROC *myproc; PROC *proc; char *name; MSG msg; myproc = (PROC *)FindTask(NULL); pnode = AllocMem(sizeof(PNODE), MEMF_PUBLIC); sprintf(pnode->name, "DNET.SERVER.%ld", portnum); pnode->seg = seg; if (proc = CreateProc(pnode->name, 0, pnode->seg, 4096)) { proc = (PROC *)((char *)proc - OFFSET(proc,pr_MsgPort)); msg.mn_ReplyPort = &myproc->pr_MsgPort; printf("Starting Server: %s %s\n", s1, pnode->name); PutMsg(&proc->pr_MsgPort, &msg); /* startup handshake */ WaitPort(&myproc->pr_MsgPort); GetMsg(&myproc->pr_MsgPort); AddTail(&SvList, pnode); } else { printf("Unable to start server: %s %s\n", s1, pnode->name); FreeMem(pnode, sizeof(PNODE)); } } else { printf("Server not found: %s\n", s1); } } /* * 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. */ dneterror(str) char *str; { register short i; if (str) puts(str); if (DNetPort) { register IOR *ior; Forbid(); while ((ior = (IOR *)RemHead(&TxList)) || (ior = (IOR *)GetMsg(DNetPort))) { ior->io_Error = -1; ReplyMsg(ior); } DeletePort(DNetPort); Permit(); DNetPort = NULL; } if (Wto.tr_node.io_Device) { if (Wto_act) { AbortIO(&Wto); WaitIO(&Wto); Wto_act = 0; } TimerClose(&Wto); } if (Rto.tr_node.io_Device) { if (Rto_act) { AbortIO(&Rto); WaitIO(&Rto); Rto_act = 0; } TimerClose(&Rto); } if (RNet) { AbortIO(RNet); WaitIO(RNet); } if (WNet) NetWrite(NULL, 0, 0); if (IOSink) DeletePort(IOSink); IOSink = NULL; NetClose(&RNet, &WNet); 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(Chan[i].ior); } } { register PNODE *pnode; register 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)); } } exit(1); } bzero(ptr, bytes) register ubyte *ptr; register long bytes; { while (bytes--) *ptr++ = 0; } fixsignal(port) register PORT *port; { if ((long)port->mp_MsgList.lh_Head != (long)&port->mp_MsgList.lh_Tail) { register ulong mask = 1 << port->mp_SigBit; SetSignal(mask, mask); } }