1 /******************************************************************************* 2 copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved 3 license: BSD style: $(LICENSE) 4 author: Juan Jose Comellas <juanjo@comellas.com.ar> 5 *******************************************************************************/ 6 7 module tango.sys.Pipe; 8 9 private import tango.sys.Common; 10 private import tango.io.device.Device; 11 12 private import tango.core.Exception; 13 14 version (Posix) 15 { 16 private import tango.stdc.posix.unistd; 17 } 18 19 debug (PipeConduit) 20 { 21 private import tango.io.Stdout; 22 } 23 24 private enum {DefaultBufferSize = 8 * 1024} 25 26 27 /** 28 * Conduit for pipes. 29 * 30 * Each PipeConduit can only read or write, depending on the way it has been 31 * created. 32 */ 33 34 class PipeConduit : Device 35 { 36 version (OLD) 37 { 38 alias Device.fileHandle fileHandle; 39 alias Device.copy copy; 40 alias Device.read read; 41 alias Device.write write; 42 alias Device.close close; 43 alias Device.error error; 44 } 45 46 private uint _bufferSize; 47 48 49 /** 50 * Create a PipeConduit with the provided handle and access permissions. 51 * 52 * Params: 53 * handle = handle of the operating system pipe we will wrap inside 54 * the PipeConduit. 55 * style = access flags for the pipe (readable, writable, etc.). 56 * bufferSize = buffer size. 57 */ 58 private this(Handle handle, uint bufferSize = DefaultBufferSize) 59 { 60 version (Windows) 61 io.handle = handle; 62 else 63 this.handle = handle; 64 _bufferSize = bufferSize; 65 } 66 67 /** 68 * Destructor. 69 */ 70 public ~this() 71 { 72 close(); 73 } 74 75 /** 76 * Returns the buffer size for the PipeConduit. 77 */ 78 public override const size_t bufferSize() 79 { 80 return _bufferSize; 81 } 82 83 /** 84 * Returns the name of the device. 85 */ 86 public override immutable(char)[] toString() 87 { 88 return "<pipe>"; 89 } 90 91 version (OLD) 92 { 93 /** 94 * Read a chunk of bytes from the file into the provided array 95 * (typically that belonging to an IBuffer) 96 */ 97 protected override uint read (void[] dst) 98 { 99 uint result; 100 DWORD read; 101 void *p = dst.ptr; 102 103 if (!ReadFile (handle, p, dst.length, &read, null)) 104 { 105 if (SysError.lastCode() == ERROR_BROKEN_PIPE) 106 { 107 return Eof; 108 } 109 else 110 { 111 error(); 112 } 113 } 114 115 if (read == 0 && dst.length > 0) 116 { 117 return Eof; 118 } 119 return read; 120 } 121 122 /** 123 * Write a chunk of bytes to the file from the provided array 124 * (typically that belonging to an IBuffer). 125 */ 126 protected override uint write (const(void)[] src) 127 { 128 DWORD written; 129 130 if (!WriteFile (handle, src.ptr, src.length, &written, null)) 131 { 132 error(); 133 } 134 return written; 135 } 136 } 137 } 138 139 /** 140 * Factory class for Pipes. 141 */ 142 class Pipe 143 { 144 private PipeConduit _source; 145 private PipeConduit _sink; 146 147 /** 148 * Create a Pipe. 149 */ 150 public this(uint bufferSize = DefaultBufferSize) 151 { 152 version (Windows) 153 { 154 this(bufferSize, null); 155 } 156 else version (Posix) 157 { 158 int[2] fd; 159 160 if (pipe(fd.ptr) == 0) 161 { 162 _source = new PipeConduit(cast(ISelectable.Handle) fd[0], bufferSize); 163 _sink = new PipeConduit(cast(ISelectable.Handle) fd[1], bufferSize); 164 } 165 else 166 { 167 error(); 168 } 169 } 170 else 171 { 172 assert(false, "Unknown platform"); 173 } 174 } 175 176 version (Windows) 177 { 178 /** 179 * Helper constructor for pipes on Windows with non-null security 180 * attributes. 181 */ 182 package this(uint bufferSize, SECURITY_ATTRIBUTES *sa) 183 { 184 HANDLE sinkHandle; 185 HANDLE sourceHandle; 186 187 if (CreatePipe(&sourceHandle, &sinkHandle, sa, cast(DWORD) bufferSize)) 188 { 189 _source = new PipeConduit(sourceHandle); 190 _sink = new PipeConduit(sinkHandle); 191 } 192 else 193 { 194 error(); 195 } 196 } 197 } 198 199 /** 200 * Return the PipeConduit that you can write to. 201 */ 202 @property public PipeConduit sink() 203 { 204 return _sink; 205 } 206 207 /** 208 * Return the PipeConduit that you can read from. 209 */ 210 @property public PipeConduit source() 211 { 212 return _source; 213 } 214 215 /** 216 * 217 */ 218 private final void error () 219 { 220 throw new IOException("Pipe error: " ~ SysError.lastMsg.idup); 221 } 222 } 223