home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.6
/
ffcollection-1-6-1993-02.iso
/
ff_disks
/
061-090
/
ff_084.lha
/
PipeHandler
/
pipe-handler.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-06-28
|
11KB
|
378 lines
/****************************************************************************
** File: pipe-handler.c
** Program: pipe-handler - an AmigaDOS handler for named pipes
** Version: 1.2
** Author: Ed Puckett qix@mit-oz
**
** Copyright 1987 by EpAc Software. All Rights Reserved.
**
** History: 05-Jan-87 Original Version (1.0)
** 07-Feb-87 Added shared locks for individual pipes.
** PIPEDATA structure modified to include
** a FileLock structure.
** 07-Feb-87 Added #if's forautomatic pipe naming "feature"
** for pipes specified with empty names.
** 12-Feb-87 Added ParentDir packet handling.
** 12-Feb-87 Fixed bug in OpenPipe() and PipeLock():
** they previously ignored the lock passed in
** packet. Bug uncovered when pipes became
** lockable, and thus assignable.
** 27-Mar-87 Added the case for PipeDupLock(). This was
** missing in the original version!
** 28-Mar-87 Added code to handler() to remove ':' from
** end of handler name. This caused problems
** with Examine(); it expects no ending ':'.
*/
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/filehandler.h>
#include <exec/exec.h>
#include "pipelists.h"
#include "pipename.h"
#include "pipebuf.h"
#include "pipecreate.h"
#include "pipesched.h"
#include "pipe-handler.h"
#if PIPEDIR
# include "pipedir.h"
#endif PIPEDIR
#ifdef DEBUG
# include "pipedebug.h"
#endif DEBUG
/*---------------------------------------------------------------------------
** pipe-handler.c
** --------------
** This is the main module for the handler. Handlers are started with
** register D1 containing a BPTR to a startup packet, which in turn contains
** (BCPL) pointers to the name and DeviceNode. Since the entry, handler(),
** expects a byte address of the startup packet, an assembly language startup
** must be used to convert the BCPL pointer, and pass it on the stack.
**
** Problems arise if a handler tries to do I/O via the DOS functions Open(),
** Close(), Read() and Write(). DOS sends request packets to the handler
** via its DOS port (the one whose address forms the process ID). This is
** also the port used by the I/O functions. Therefore, if a request comes,
** and then an Open() call is performed, DOS will send a request packet for
** the open and erroneously pick up the request packet meant for the handler
** as its reply. A crash ensues.
**
** This is the reason for the I/O functions in pipedebug.c. They implement
** the regualar I/O calls, but use a different ReplyPort. With no debugging,
** these functions are unneeded, since all of the handler's normal I/O is
** performed asynchronously, using PutMsg().
**
** An alternate solution is to patch the handler's Task field with a new port
** instead of the handler's DOS port. This works, except that DOS always
** sends the initial request packets to the DOS port (when the handler is
** first started). This is probably because DeviceProc(), upon seeing that
** the handler has not yet been loaded, returns the result from its call to
** CreateProc() for the handler process. Only on subsequent calls to
** DeviceProc() will the patched field be returned. The upshot of this is
** that an alternate port can be used for handler requests, but there are
** always an unspecified number that may come over the DOS port regardless.
** Note that since not all handlers patch their Task field (because they want
** to be restarted each time), DOS is doing the "right" thing, or at least
** the best it can.
**
** Visible Functions
** -----------------
** void handler (StartPkt)
** PIPEDATA *FindPipe (name)
**
** Macros (in pipe-handler.h)
** --------------------------
** BPTRtoCptr (Bp)
** CptrtoBPTR (Cp)
** ReplyPkt (pkt)
**
** Local Functions
** ---------------
** struct DosPacket *GetPkt (port)
*/
/*---------------------------------------------------------------------------
** HandlerName : passed as a BSTR in startup packet Arg1, our device name.
** Everything from the ':' and beyond is removed.
** Used by PipeExamine() for the handler's "directory" name.
**
** DevNode : passed as a BPTR in startup packet Arg3. This is a pointer
** to our DeviceNode entry in the system device list (DevInfo).
**
** Pipeort : our DOS MsgPort, as well as our process ID. See above for
** notes about why we can't let DOS use this.
**
** pipelist : the list of currently existing pipes. PIPEDATA nodes are
** linked into this list.
**
** tapwaitlist : the list of requests waiting on tap opens/closes/writes.
** WAITINGDATA nodes are linked into this list. See pipesched.c
** and pipecreate.c.
**
** TapReplyPort : this is the MsgPort to which tap I/O replys are returned.
**
** SysBase,
** DOSBase : Standard system library pointers. Since we don't have the
** usual startup code, we must initialize these ourselves.
**
** PipeDate : If compiled with PIPEDIR true, the handler responds to some
** directory-like actions. This is the date for the entire
** handler, i.e., the directory date. The flag UPDATE_PIPEDATE
** controls whether this date is updated with each pipe access
** (true) or not (false). See SetPipeDate() and PipeExamine().
*/
char HandlerName[30];
struct DeviceNode *DevNode = NULL;
struct MsgPort *PipePort = NULL;
PIPELISTHEADER pipelist;
PIPELISTHEADER tapwaitlist;
struct MsgPort *TapReplyPort = NULL;
struct Library *SysBase = NULL;
struct Library *DOSBase = NULL;
#if PIPEDIR
struct DateStamp PipeDate;
#endif PIPEDIR
/*---------------------------------------------------------------------------
** Performs initialization, replies to startup packet, and dispatches
** incoming request packets to the apropriate functions. The TapReplyPort is
** also monitored for returning requests which were sent out by the handler.
** These returned requests are routed to HandleTapReply().
** Our DeviceNode Task field is patched with our process ID so that this
** process is used for subsequent handler requests. The function exits only
** if there is some initialization error.
*/
void handler (StartPkt)
struct DosPacket *StartPkt;
{ char *cp;
struct Task *Task;
ULONG PipeMask, TapReplyMask, WakeupMask, SigMask;
struct DosPacket *pkt, *GetPkt();
void OpenPipe(), ClosePipe();
SysBase= AbsExecBase;
if ((DOSBase= OpenLibrary (DOSNAME, 0)) == NULL)
goto QUIT;
BSTRtoCstr (BPTRtoCptr (StartPkt->dp_Arg1), HandlerName, sizeof (HandlerName));
for (cp= HandlerName; *cp != '\0'; ++cp)
if (*cp == ':') /* remainder of handler's first refernece follows */
{ *cp= '\0';
break;
}
Task= FindTask (0);
PipePort= (struct MsgPort *) ((ULONG) Task + sizeof (struct Task));
((struct Process *) Task)->pr_CurrentDir= 0; /* initial file system root */
if ((TapReplyPort= CreatePort (NULL, PipePort->mp_Node.ln_Pri)) == NULL)
goto QUIT;
#ifdef DEBUG
if (! InitDebugIO (PipePort->mp_Node.ln_Pri))
goto QUIT;
#endif DEBUG
PipeMask= (1L << PipePort->mp_SigBit);
TapReplyMask= (1L << TapReplyPort->mp_SigBit);
WakeupMask= (PipeMask | TapReplyMask);
DevNode= (struct DeviceNode *) BPTRtoCptr (StartPkt->dp_Arg3);
DevNode->dn_Task= PipePort;
InitList (&pipelist);
InitList (&tapwaitlist);
#if PIPEDIR
(void) DateStamp (&PipeDate);
#endif PIPEDIR
ReplyPkt (StartPkt);
LOOP:
SigMask= Wait (WakeupMask);
if (SigMask & TapReplyMask)
while ((pkt= GetPkt (TapReplyPort)) != NULL)
HandleTapReply (pkt);
if (SigMask & PipeMask)
while ((pkt= GetPkt (PipePort)) != NULL)
switch (pkt->dp_Type)
{ case MODE_READWRITE:
#ifdef DEBUG
OS ("Open READWRITE packet received\n");
#endif DEBUG
OpenPipe (pkt, 0);
break;
case MODE_READONLY: /* syn: MODE_OLDFILE, ACTION_FINDINPUT */
#ifdef DEBUG
OS ("Open READONLY packet received\n");
#endif DEBUG
OpenPipe (pkt, 0);
break;
case MODE_NEWFILE: /* syn: ACTION_FINDOUTPUT */
#ifdef DEBUG
OS ("Open NEWFILE packet received\n");
#endif DEBUG
OpenPipe (pkt, 0);
break;
case ACTION_END:
#ifdef DEBUG
OS ("Close packet received\n");
#endif DEBUG
ClosePipe (pkt);
break;
case ACTION_READ:
#ifdef DEBUG
OS ("<<< Read packet received\n");
#endif DEBUG
StartPipeIO (pkt, PIPEREAD);
break;
case ACTION_WRITE:
#ifdef DEBUG
OS (">>> Write packet received\n");
#endif DEBUG
StartPipeIO (pkt, PIPEWRITE);
break;
#if PIPEDIR
case ACTION_LOCATE_OBJECT:
# ifdef DEBUG
OS ( "Lock packet received\n");
# endif DEBUG
PipeLock (pkt);
break;
case ACTION_COPY_DIR:
# ifdef DEBUG
OS ( "DupLock packet received\n");
# endif DEBUG
PipeDupLock (pkt);
break;
case ACTION_FREE_LOCK:
# ifdef DEBUG
OS ( "UnLock packet received\n");
# endif DEBUG
PipeUnLock (pkt);
break;
case ACTION_EXAMINE_OBJECT:
# ifdef DEBUG
OS ( "Examine packet received\n");
# endif DEBUG
PipeExamine (pkt);
break;
case ACTION_EXAMINE_NEXT:
# ifdef DEBUG
OS ( "ExNext packet received\n");
# endif DEBUG
PipeExNext (pkt);
break;
case ACTION_PARENT:
# ifdef DEBUG
OS ( "ParentDir packet received\n");
# endif DEBUG
PipeParentDir (pkt);
break;
#endif PIPEDIR
default:
#ifdef DEBUG
OS ("BAD packet received, type = "); OL (pkt->dp_Type); NL;
#endif DEBUG
pkt->dp_Res1= 0;
pkt->dp_Res2= ERROR_ACTION_NOT_KNOWN;
ReplyPkt (pkt);
}
goto LOOP;
QUIT:
DevNode->dn_Task= NULL; /* bad if someone in process of accessing us . . . */
if (TapReplyPort != NULL)
FreeMem (TapReplyPort, sizeof (struct MsgPort)); /* signal bit won't matter */
#ifdef DEBUG
CleanupDebugIO ();
#endif DEBUG
if (DOSBase != NULL)
CloseLibrary (DOSBase);
}
/*---------------------------------------------------------------------------
** Returns the DosPacket associated with the next message on "port", or NULL
** if the port is empty. The message is removed from the port.
** A related macro, ReplyPkt() is provided in pipe-handler.h.
*/
static struct DosPacket *GetPkt (port)
register struct MsgPort *port;
{ register struct Message *msg;
return ((msg= GetMsg (port)) == NULL)
? NULL
: (struct DosPacket *) msg->mn_Node.ln_Name;
}
/*---------------------------------------------------------------------------
** Searches "pipelist" for a pipe whose name is "name". If found, a pointer
** to the pipe returns. Otherwise, NULL returns.
*/
PIPEDATA *FindPipe (name)
char *name;
{ PIPEDATA *p;
char *cp, *strdiff();
for (p= (PIPEDATA *) FirstItem (&pipelist); p != NULL; p= (PIPEDATA *) NextItem (p))
{ cp= strdiff (name, p->name);
if ((*cp == '\0') && (p->name[(LONG) cp - (LONG) name] == '\0'))
return p; /* same name */
}
return NULL; /* no match found */
}