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