/* * DNETLIB.C * * DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved. * * Library Interface for DNET. */ #define NOEXT #include "/dnet/dnet.h" #define CHANN struct _CHANN #define NAMELEN sizeof("DNET.PORT.XXXXX") #define NAMEPAT "DNET.PORT.%ld" CHANN { PORT port; /* receive data, replies */ PORT *dnetport; /* dnet's master port */ LIST rdylist; /* ready to be read */ uword chan; /* channel # for open channels */ ubyte eof; /* channel remotely closed/eof */ ubyte filler; int qlen; /* allowed write queue size */ int queued; /* current # packets queued */ }; static CHANN *MakeChannel(); PORT * DListen(portnum) uword portnum; { PORT *port = NULL; char *ptr; ptr = AllocMem(NAMELEN, MEMF_PUBLIC); /* memory the the name */ sprintf(ptr, NAMEPAT, portnum); Forbid(); /* task-atomic operation */ if (FindPort(ptr) || !(port = CreatePort(ptr,0))) FreeMem(ptr, NAMELEN); Permit(); return(port); } void DUnListen(lisport) PORT *lisport; { if (lisport) { register char *ptr = lisport->mp_Node.ln_Name; Forbid(); /* task-atomic operation */ while (DNAAccept(lisport)); /* remove all pending requests */ DeletePort(lisport); /* gone! */ Permit(); FreeMem(ptr, NAMELEN); } } /* * DAccept() * * Note: This call will work even if called by a task which does not * own the listen port. */ PORT * DAccept(lisport) PORT *lisport; { register IOR *ior; register CHANN *chan = NULL; while (!chan && (ior = GetMsg(lisport))) { switch(ior->io_Command) { case DNCMD_SOPEN: chan = MakeChannel(ior, NULL); break; default: ior->io_Error = 1; break; } ReplyMsg(ior); } if (lisport->mp_MsgList.lh_Head != (NODE *)&lisport->mp_MsgList.lh_Tail) SetSignal(1 << lisport->mp_SigBit, 1 << lisport->mp_SigBit); return((PORT *)chan); } /* * Refuse a connection */ DNAAccept(lisport) PORT *lisport; { IOR *ior; if (ior = GetMsg(lisport)) { ior->io_Error = 1; ReplyMsg(ior); } if (lisport->mp_MsgList.lh_Head != (NODE *)&lisport->mp_MsgList.lh_Tail) SetSignal(1 << lisport->mp_SigBit, 1 << lisport->mp_SigBit); return(ior != NULL); } DPri(chan, pri) CHANN *chan; { } PORT * DOpen(host, portnum, txpri, rxpri) char *host; char txpri, rxpri; uword portnum; { IOR ior; CHANN *chan; if (!host) host = "0"; chan = MakeChannel(&ior, host); if (rxpri > 126) rxpri = 126; if (rxpri < -127) rxpri = -127; if (txpri > 126) txpri = 126; if (txpri < -127) txpri = -127; if (chan->dnetport) { ior.io_Command = DNCMD_OPEN; ior.io_Unit = (void *)portnum; ior.io_Offset = (long)chan; ior.io_Message.mn_ReplyPort = (PORT *)chan; ior.io_Message.mn_Node.ln_Pri = txpri; ior.io_Message.mn_Node.ln_Name= (char *)rxpri; PutMsg(chan->dnetport, &ior); WaitMsg(&ior); if (ior.io_Error == 0) { chan->chan = (long)ior.io_Unit; FixSignal(chan); return((PORT *)chan); } } DeleteChannel(chan); return(NULL); } DNRead(chan, buf, bytes) CHANN *chan; char *buf; { register IOR *ior; int len = 0; long n; if (chan->eof) return(-1); while (bytes && ((ior = RemHead(&chan->rdylist)) || (ior = GetMsg(chan)))) { if (ior->io_Message.mn_Node.ln_Type == NT_REPLYMSG) { if (!chan->queued) puts("DNRead: Software Error"); else --chan->queued; if (ior->io_Length) FreeMem(ior->io_Data, ior->io_Length); FreeMem(ior, sizeof(IOR)); continue; } switch(ior->io_Command) { case DNCMD_CLOSE: case DNCMD_EOF: chan->eof = 1; ReplyMsg(ior); break; case DNCMD_WRITE: n = ior->io_Length - ior->io_Actual; if (n <= bytes) { CopyMem((char *)ior->io_Data + ior->io_Actual, buf, n); bytes -= n; len += n; buf += n; ReplyMsg(ior); } else { CopyMem((char *)ior->io_Data + ior->io_Actual, buf, bytes); len += bytes; ior->io_Actual += bytes; bytes = 0; Forbid(); /* DNET device is a task, no need to Disable() */ ior->io_Message.mn_Node.ln_Type = NT_MESSAGE; AddHead(&chan->port.mp_MsgList, ior); Permit(); } break; default: ior->io_Error = 1; ReplyMsg(ior); } } FixSignal(chan); if (chan->eof) SetSignal(1 << chan->port.mp_SigBit, 1 << chan->port.mp_SigBit); return(len); } DRead(chan, buf, bytes) char *buf; CHANN *chan; { long len = 0; long n; if (chan->eof) return(-1); while (bytes) { WaitPort(chan); n = DNRead(chan, buf, bytes); if (n < 0) break; len += n; buf += n; bytes -= n; if (chan->eof) break; } return(len); } DQueue(chan, n) CHANN *chan; { chan->qlen = n; } DWrite(chan, buf, bytes) CHANN *chan; { int error = bytes; if (chan->qlen) { if (WaitQueue(chan, NULL) >= 0) { register IOR *ior = AllocMem(sizeof(IOR), MEMF_CLEAR|MEMF_PUBLIC); ior->io_Command = DNCMD_WRITE; ior->io_Unit = (void *)chan->chan; ior->io_Offset = (long)chan; ior->io_Message.mn_ReplyPort = (PORT *)chan; ior->io_Data = AllocMem(bytes, MEMF_PUBLIC); ior->io_Length = bytes; CopyMem(buf, ior->io_Data, bytes); PutMsg(chan->dnetport, ior); ++chan->queued; } else { error = -1; } } else { IOR ior; ior.io_Command = DNCMD_WRITE; ior.io_Unit = (void *)chan->chan; ior.io_Offset = (long)chan; ior.io_Message.mn_ReplyPort = (PORT *)chan; ior.io_Data = (APTR)buf; ior.io_Length = bytes; PutMsg(chan->dnetport, &ior); WaitMsg(&ior); if (ior.io_Error) error = -1; } FixSignal(chan); return(error); } DEof(chan) CHANN *chan; { IOR ior; ior.io_Command = DNCMD_EOF; ior.io_Unit = (void *)chan->chan; ior.io_Offset = (long)chan; ior.io_Message.mn_ReplyPort = (PORT *)chan; PutMsg(chan->dnetport, &ior); WaitMsg(&ior); FixSignal(chan); } DIoctl(chan, cmd, val, aux) CHANN *chan; ubyte cmd; uword val; ubyte aux; { IOR ior; ior.io_Command = DNCMD_IOCTL; ior.io_Unit = (void *)chan->chan; ior.io_Offset = (long)chan; ior.io_Message.mn_ReplyPort = (PORT *)chan; ior.io_Data = (APTR)(long)((val<<16)|(aux<<8)|cmd); PutMsg(chan->dnetport, &ior); WaitMsg(&ior); FixSignal(chan); } DQuit(host) char *host; { IOR ior; char buf[sizeof(DNETPORTNAME)+32]; PORT *replyport = CreatePort(NULL, 0); PORT *dnetport; if (!host) host = "0"; sprintf(buf, "%s%s", DNETPORTNAME, host); if (dnetport = FindPort(buf)) { ior.io_Command = DNCMD_QUIT; ior.io_Unit = 0; ior.io_Offset = 0; ior.io_Message.mn_ReplyPort = replyport; PutMsg(dnetport, &ior); WaitMsg(&ior); DeletePort(replyport); } return(dnetport != NULL); } DClose(chan) CHANN *chan; { IOR ior; IOR *io; ior.io_Command = DNCMD_CLOSE; ior.io_Unit = (void *)chan->chan; ior.io_Offset = (long)chan; ior.io_Message.mn_ReplyPort = (PORT *)chan; PutMsg(chan->dnetport, &ior); ++chan->queued; chan->qlen = 0; WaitQueue(chan, &ior); while ((io = RemHead(&chan->rdylist)) || (io = GetMsg(chan))) { io->io_Error = 1; ReplyMsg(io); } DeleteChannel(chan); } WaitMsg(ior) IOR *ior; { while (ior->io_Message.mn_Node.ln_Type != NT_REPLYMSG) Wait(1 << ior->io_Message.mn_ReplyPort->mp_SigBit); Forbid(); Remove(ior); Permit(); } WaitQueue(chan, skipior) CHANN *chan; IOR *skipior; { register IOR *io; short error = 0; while (chan->queued > chan->qlen) { /* until done */ WaitPort(chan); /* something */ io = (IOR *)GetMsg(chan); if (io->io_Message.mn_Node.ln_Type == NT_REPLYMSG) { if (error == 0) error = io->io_Error; if (io != skipior) { if (io->io_Length) FreeMem(io->io_Data, io->io_Length); FreeMem(io, sizeof(IOR)); } --chan->queued; } else { AddTail(&chan->rdylist, io); } } return(error); } static CHANN * MakeChannel(ior, host) register IOR *ior; char *host; { CHANN *chan = AllocMem(sizeof(CHANN), MEMF_PUBLIC|MEMF_CLEAR); /* Name, Pri */ chan->port.mp_Node.ln_Type = NT_MSGPORT; chan->port.mp_SigBit = AllocSignal(-1); chan->port.mp_SigTask = FindTask(NULL); NewList(&chan->port.mp_MsgList); NewList(&chan->rdylist); chan->chan = (long)ior->io_Unit; ior->io_Offset = (long)chan; if (host) { char buf[sizeof(DNETPORTNAME)+32]; sprintf(buf, "%s%s", DNETPORTNAME, host); ior->io_Message.mn_ReplyPort = FindPort(buf); } chan->dnetport = ior->io_Message.mn_ReplyPort; return(chan); } static DeleteChannel(chan) CHANN *chan; { FreeSignal(chan->port.mp_SigBit); FreeMem(chan, sizeof(CHANN)); } static FixSignal(chan) register CHANN *chan; { if (chan->port.mp_MsgList.lh_Head != (NODE *)&chan->port.mp_MsgList.lh_Tail || chan->rdylist.lh_Head != (NODE *)&chan->rdylist.lh_Tail) SetSignal(1 << chan->port.mp_SigBit, 1 << chan->port.mp_SigBit); }