123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
|
/*******************************************************************************
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
license: BSD style: $(LICENSE)
author: Juan Jose Comellas <juanjo@comellas.com.ar>
*******************************************************************************/
module tango.sys.Pipe;
private import tango.sys.Common;
private import tango.io.device.Device;
private import tango.core.Exception;
version (Posix)
{
private import tango.stdc.posix.unistd;
}
debug (PipeConduit)
{
private import tango.io.Stdout;
}
private enum {DefaultBufferSize = 8 * 1024}
/**
* Conduit for pipes.
*
* Each PipeConduit can only read or write, depending on the way it has been
* created.
*/
class PipeConduit : Device
{
version (OLD)
{
alias Device.fileHandle fileHandle;
alias Device.copy copy;
alias Device.read read;
alias Device.write write;
alias Device.close close;
alias Device.error error;
}
private uint _bufferSize;
/**
* Create a PipeConduit with the provided handle and access permissions.
*
* Params:
* handle = handle of the operating system pipe we will wrap inside
* the PipeConduit.
* style = access flags for the pipe (readable, writable, etc.).
* bufferSize = buffer size.
*/
private this(Handle handle, uint bufferSize = DefaultBufferSize)
{
version (Windows)
io.handle = handle;
else
this.handle = handle;
_bufferSize = bufferSize;
}
/**
* Destructor.
*/
public ~this()
{
close();
}
/**
* Returns the buffer size for the PipeConduit.
*/
public override const size_t bufferSize()
{
return _bufferSize;
}
/**
* Returns the name of the device.
*/
public override immutable(char)[] toString()
{
return "<pipe>";
}
version (OLD)
{
/**
* Read a chunk of bytes from the file into the provided array
* (typically that belonging to an IBuffer)
*/
protected override uint read (void[] dst)
{
uint result;
DWORD read;
void *p = dst.ptr;
if (!ReadFile (handle, p, dst.length, &read, null))
{
if (SysError.lastCode() == ERROR_BROKEN_PIPE)
{
return Eof;
}
else
{
error();
}
}
if (read == 0 && dst.length > 0)
{
return Eof;
}
return read;
}
/**
* Write a chunk of bytes to the file from the provided array
* (typically that belonging to an IBuffer).
*/
protected override uint write (const(void)[] src)
{
DWORD written;
if (!WriteFile (handle, src.ptr, src.length, &written, null))
{
error();
}
return written;
}
}
}
/**
* Factory class for Pipes.
*/
class Pipe
{
private PipeConduit _source;
private PipeConduit _sink;
/**
* Create a Pipe.
*/
public this(uint bufferSize = DefaultBufferSize)
{
version (Windows)
{
this(bufferSize, null);
}
else version (Posix)
{
int fd[2];
if (pipe(fd.ptr) == 0)
{
_source = new PipeConduit(cast(ISelectable.Handle) fd[0], bufferSize);
_sink = new PipeConduit(cast(ISelectable.Handle) fd[1], bufferSize);
}
else
{
error();
}
}
else
{
assert(false, "Unknown platform");
}
}
version (Windows)
{
/**
* Helper constructor for pipes on Windows with non-null security
* attributes.
*/
package this(uint bufferSize, SECURITY_ATTRIBUTES *sa)
{
HANDLE sinkHandle;
HANDLE sourceHandle;
if (CreatePipe(&sourceHandle, &sinkHandle, sa, cast(DWORD) bufferSize))
{
_source = new PipeConduit(sourceHandle);
_sink = new PipeConduit(sinkHandle);
}
else
{
error();
}
}
}
/**
* Return the PipeConduit that you can write to.
*/
@property public PipeConduit sink()
{
return _sink;
}
/**
* Return the PipeConduit that you can read from.
*/
@property public PipeConduit source()
{
return _source;
}
/**
*
*/
private final void error ()
{
throw new IOException("Pipe error: " ~ SysError.lastMsg.idup);
}
}
|