1 /****************************************************************************
3 ** Program: pipe-handler - an AmigaDOS handler for named pipes
5 ** Author: Ed Puckett qix@mit-oz
7 ** Copyright 1987 by EpAc Software. All Rights Reserved.
9 ** History: 05-Jan-87 Original Version (1.0)
10 ** 07-Feb-87 Added lock initialization to OpenPipe()
11 ** for locks on individual pipes.
12 ** 12-Feb-87 Fixed bug in OpenPipe(): previously ignored
13 ** lock passed in packet. Bug uncovered when
14 ** pipes became lockable, and thus assignable.
15 ** 26-Mar-87 Fixed bug in ClosePipe(): not closing r/w
16 ** mode properly (extraneous else).
19 #include <libraries/dos.h>
20 #include <libraries/dosextens.h>
21 #include <libraries/filehandler.h>
22 #include <exec/exec.h>
24 #include "pipelists.h"
27 #include "pipecreate.h"
28 #include "pipesched.h"
29 #include "pipe-handler.h"
36 # include "pipedebug.h"
41 /*---------------------------------------------------------------------------
44 ** This module handles opens and closes for pipes.
48 ** void OpenPipe (pkt, tapfh)
49 ** void ClosePipe (pkt)
50 ** void DiscardPipe (pipe)
52 ** Macros (in pipecreate.h)
53 ** ------------------------
58 ** int TapFormsLoop (tapfh, pipe)
59 ** void OpenTap (pkt, tapname)
60 ** void CloseTap (tapfh)
65 /*---------------------------------------------------------------------------
66 ** OpenPipe() handles open requests. The DosPacket from the client and the
67 ** filehandle of the tap are sent. If tapfh is 0, but the name sent
68 ** indicates a tap is desired (see ParsePipeName() in pipename.c), then
69 ** an OpenTap() request is initiated and OpenPipe() is immediately exited.
70 ** Later, when the request returns (to HandleTapReply()), OpenPipe() is
71 ** called again with the same client packet and the newly returned tapfh.
72 ** If tapfh is nonzero, or if it is zero but no tap is desired, then
73 ** the an attempt to open the pipe is made. If a existent pipe with a tap is
74 ** to be opened and a new tapfh is given, the old tap is closed.
75 ** If the name's syntax is incorrect, then the request is returned
76 ** unsuccessful. Otherwise, if the pipe named by the request does not
77 ** already exist, a new pipe is created (if there is enough memory).
78 ** If it does exist, but it is already open for the mode requested, an error
79 ** is returned (a maximum of one reader and one writer is allowed).
80 ** A successful open returns the client's filehandle with its Arg1 field
81 ** pointing to a PIPEKEY, which in turn identifies the pipe and open mode.
82 ** Unless an OpenTap() is required, the packet is returned to the cleint
83 ** by this function. If an OpenTap() is required, it will be returned by the
84 ** the later call to this function when the tap open request is returned.
85 ** Note: the code which checks if the lock sent in the packet relies on
86 ** the fact that the pipe-handler does not allow subdirectories. If a lock
87 ** on a pipe is passed in, then that pipe is opened. Otherwise, the name is
88 ** parsed without reference to the lock.
91 static int TapFormsLoop(BPTR tapfh
, PIPEDATA
*pipe
);
92 static void CloseTap(BPTR tapfh
);
93 static void OpenTap(struct DosPacket
*pkt
,const char *tapname
);
95 void OpenPipe (pkt
, tapfh
)
97 struct DosPacket
*pkt
;
102 struct FileHandle
*handle
;
103 struct FileLock
*lock
;
104 char *pipename
= NULL
, *tapname
= NULL
;
106 PIPEKEY
*pipekey
= NULL
;
107 PIPEDATA
*pipe
= NULL
;
110 pkt
->dp_Res1
= 0; /* error, for now */
112 if (! ParsePipeName (BPTRtoCptr (pkt
->dp_Arg3
), &pipename
, &pipesize
, &tapname
))
113 { pkt
->dp_Res2
= ERROR_INVALID_COMPONENT_NAME
;
117 if ( (tapfh
== 0) && (tapname
!= NULL
) && (tapname
[0] != '\0') )
118 { OpenTap (pkt
, tapname
); /* start tap open request */
119 return; /* HandleTapReply() re-calls when request returns */
122 openmode
= pkt
->dp_Type
;
123 lock
= (struct FileLock
*) BPTRtoCptr (pkt
->dp_Arg2
);
126 if ( (lock
== NULL
) || ((pipe
= (PIPEDATA
*) lock
->fl_Key
) == NULL
) )
127 { if (pipename
[0] == '\0')
129 pipename
= get_autoname ((openmode
== MODE_NEWFILE
) || (openmode
== MODE_READWRITE
));
130 #else /* !AUTONAME */
131 { pkt
->dp_Res2
= ERROR_INVALID_COMPONENT_NAME
;
134 #endif /* AUTONAME */
135 if (AUTONAME_STAR
&& pipename
[0] == '*' && pipename
[1] == 0) {
136 pipename
= get_autoname ((openmode
== MODE_NEWFILE
) || (openmode
== MODE_READWRITE
));
139 pipe
= FindPipe (pipename
);
141 else /* packet's lock was on the pipe */
142 { if (pipename
[0] != '\0')
143 { pkt
->dp_Res2
= ERROR_INVALID_COMPONENT_NAME
;
147 pipename
= pipe
->name
;
151 handle
= (struct FileHandle
*) BPTRtoCptr (pkt
->dp_Arg1
);
153 if ((pipekey
= (PIPEKEY
*) AllocMem (sizeof (PIPEKEY
), ALLOCMEM_FLAGS
)) == NULL
)
154 { pkt
->dp_Res2
= ERROR_NO_FREE_STORE
;
159 if (pipe
== NULL
) /* then PIPE NOT FOUND */
160 { if (openmode
== MODE_READONLY
)
161 { pkt
->dp_Res2
= ERROR_OBJECT_NOT_FOUND
;
165 pkt
->dp_Res2
= ERROR_NO_FREE_STORE
; /* in case of AllocMem error */
167 if ((pipe
= (PIPEDATA
*) AllocMem (sizeof (PIPEDATA
), ALLOCMEM_FLAGS
)) == NULL
)
170 if ((pipe
->buf
= AllocPipebuf (pipesize
)) == NULL
)
173 if ((pipe
->lock
= (struct FileLock
*) AllocMem (sizeof (struct FileLock
), ALLOCMEM_FLAGS
)) == NULL
)
174 { FreePipebuf (pipe
->buf
);
176 FreeMem (pipe
, sizeof (PIPEDATA
));
181 l_strcpy (pipe
->name
, pipename
);
184 pipekey
->openmode
= openmode
;
186 if (openmode
== MODE_READONLY
)
187 { pipekey
->iotype
= PIPEREAD
;
188 pipe
->flags
|= OPEN_FOR_READ
;
190 else if (openmode
== MODE_NEWFILE
)
191 { pipekey
->iotype
= PIPEWRITE
;
192 pipe
->flags
= OPEN_FOR_WRITE
;
194 else /* MODE_READWRITE */
195 { pipekey
->iotype
= PIPERW
;
196 pipe
->flags
= (OPEN_FOR_READ
| OPEN_FOR_WRITE
);
199 InitList (&pipe
->readerlist
);
200 InitList (&pipe
->writerlist
);
206 InitLock (pipe
->lock
, pipe
);
209 InsertTail (&pipelist
, pipe
); /* at tail for directory's sake */
212 OS ("*** created pipe '"); OS (pipe
->name
);
213 OS ("' [buflen "); OL (pipe
->buf
->len
); OS ("]\n");
216 else /* PIPE WAS FOUND */
217 { if (TapFormsLoop (tapfh
, pipe
))
218 { pkt
->dp_Res2
= ERROR_INVALID_COMPONENT_NAME
;
223 pipekey
->openmode
= openmode
;
225 pkt
->dp_Res2
= ERROR_OBJECT_IN_USE
; /* in case of openmode error */
227 if (openmode
== MODE_READONLY
)
228 { if (pipe
->flags
& OPEN_FOR_READ
)
231 pipekey
->iotype
= PIPEREAD
;
232 pipe
->flags
|= OPEN_FOR_READ
;
234 else if (openmode
== MODE_NEWFILE
)
235 { if (pipe
->flags
& OPEN_FOR_WRITE
)
238 pipekey
->iotype
= PIPEWRITE
;
239 pipe
->flags
|= OPEN_FOR_WRITE
;
241 else /* MODE_READWRITE */
242 { if (pipe
->flags
& (OPEN_FOR_READ
| OPEN_FOR_WRITE
))
245 pipekey
->iotype
= PIPERW
;
246 pipe
->flags
= (OPEN_FOR_READ
| OPEN_FOR_WRITE
);
250 { if (pipe
->tapfh
!= 0)
251 CloseTap (pipe
->tapfh
); /* close old tap first */
258 handle
->fh_Arg1
= (IPTR
) pipekey
; /* for identification on Read, Write, Close */
260 pkt
->dp_Res2
= 0; /* for successful open */
264 if (pkt
->dp_Res1
== 0) /* then there was an error */
265 { if (pipekey
!= NULL
)
266 FreeMem (pipekey
, sizeof (PIPEKEY
));
281 /*---------------------------------------------------------------------------
282 ** This routine checks for "the old loop in the pipe trick" (86). If the
283 ** handler has a loop through its tap, the handler will endlessly pass
284 ** packets to itself. This would be disastrous if the handler is running at
288 static int TapFormsLoop (tapfh
, pipe
)
293 { struct FileHandle
*handle
;
296 int numchecks
; /* protection */
299 for (numchecks
= 0; ((tapfh
!= 0) && (numchecks
< 10000)); ++numchecks
)
300 { handle
= (struct FileHandle
*) BPTRtoCptr (tapfh
);
302 if (handle
->fh_Type
== PipePort
) /* then the tap is a pipe, too */
303 { if ( ((tapkey
= (PIPEKEY
*) handle
->fh_Arg1
) == NULL
) ||
304 ((tappipe
= tapkey
->pipe
) == NULL
) )
310 tapfh
= tappipe
->tapfh
;
321 /*---------------------------------------------------------------------------
322 ** The previous open performed on a pipe is terminated. The PIPEKEY
323 ** allocated for the client when the pipe was opened is freed. Then,
324 ** CheckWaiting() is called -- it will discard the pipe if it becomes empty
325 ** and is not opened for read or write.
330 struct DosPacket
*pkt
;
337 pipekey
= (PIPEKEY
*) pkt
->dp_Arg1
;
340 if ((pipekey
->iotype
== PIPEREAD
) || (pipekey
->iotype
== PIPERW
))
341 pipe
->flags
&= ~OPEN_FOR_READ
;
343 if ((pipekey
->iotype
== PIPEWRITE
) || (pipekey
->iotype
== PIPERW
))
344 pipe
->flags
&= ~OPEN_FOR_WRITE
;
346 FreeMem (pipekey
, sizeof (PIPEKEY
));
348 CheckWaiting (pipe
); /* will discard if empty */
358 /*---------------------------------------------------------------------------
359 ** Remove a pipe from the pipe list and release its memory. The pipe is
360 ** assumed empty and having no clients.
363 void DiscardPipe (pipe
)
369 OS ("*** discarding pipe '"); OS (pipe
->name
); OS ("'\n");
372 Delete (&pipelist
, pipe
);
374 FreePipebuf (pipe
->buf
);
375 FreeMem (pipe
->lock
, sizeof (struct FileLock
));
377 if (pipe
->tapfh
!= 0)
378 CloseTap (pipe
->tapfh
);
380 FreeMem (pipe
, sizeof (PIPEDATA
));
385 /*---------------------------------------------------------------------------
386 ** An open request for a tap is performed. A WAITINGDATA structure is
387 ** allocated to hold the client packet until later. HandleTapReply() will
388 ** deal with the reply and, if successful, re-call OpenPipe().
391 static void OpenTap (pkt
, tapname
)
393 struct DosPacket
*pkt
;
397 struct FileHandle
*handle
;
399 struct DosPacket
*tappkt
;
400 struct MsgPort
*Handler
;
401 struct FileLock
*Lock
;
405 if ( (tapname
== NULL
) ||
406 ((Bname
= (char *) AllocMem (OPENTAP_STRSIZE
, ALLOCMEM_FLAGS
)) == NULL
) )
409 if ((handle
= (struct FileHandle
*) AllocMem (sizeof (struct FileHandle
), (ALLOCMEM_FLAGS
| MEMF_CLEAR
))) == NULL
)
412 if ((wd
= (WAITINGDATA
*) AllocMem (sizeof (WAITINGDATA
), ALLOCMEM_FLAGS
)) == NULL
)
415 if ((tappkt
= AllocPacket (TapReplyPort
)) == NULL
)
418 if ((Handler
= DeviceProc (tapname
)) == NULL
)
419 { FreePacket (tappkt
);
421 FreeMem (wd
, sizeof (WAITINGDATA
));
423 FreeMem (handle
, sizeof (struct FileHandle
));
425 FreeMem (Bname
, OPENTAP_STRSIZE
);
428 pkt
->dp_Res2
= ERROR_INVALID_COMPONENT_NAME
;
433 Lock
= (struct FileLock
*) IoErr ();
434 CstrtoBSTR (tapname
, Bname
, OPENTAP_STRSIZE
);
438 handle
->fh_Type
= Handler
; /* initialize file handle */
441 wd
->pktinfo
.tapwait
.clientpkt
= pkt
;
442 wd
->pktinfo
.tapwait
.handle
= handle
; /* for HandleTapReply() */
444 StartTapIO ( tappkt
, ACTION_FINDOUTPUT
,
445 CptrtoBPTR (handle
), CptrtoBPTR (Lock
), CptrtoBPTR (Bname
),
448 InsertHead (&tapwaitlist
, wd
);
453 /*---------------------------------------------------------------------------
454 ** A close request for a tap filehandle is initiated. When HandleTapReply()
455 ** gets the reply, it merely discards it.
458 static void CloseTap (tapfh
)
462 { struct FileHandle
*taphandle
;
463 struct DosPacket
*tappkt
;
468 taphandle
= (struct FileHandle
*) BPTRtoCptr (tapfh
);
470 if ((tappkt
= AllocPacket (TapReplyPort
)) == NULL
)
473 if ((wd
= (WAITINGDATA
*) AllocMem (sizeof (WAITINGDATA
), ALLOCMEM_FLAGS
)) == NULL
)
474 { FreePacket (tappkt
);
476 FreeMem (taphandle
, sizeof (struct FileHandle
));
478 OS ("!!! ERROR - CloseTap() failed\n");
484 /* don't need ...tapwait.clientpkt */
485 wd
->pktinfo
.tapwait
.handle
= taphandle
; /* for HandleTapReply() */
487 StartTapIO ( tappkt
, ACTION_END
,
488 taphandle
->fh_Arg1
, 0, 0,
489 taphandle
->fh_Type
);
491 InsertHead (&tapwaitlist
, wd
);