blob: 613906bedaa8f90b13b9e8bb200450a8963f13a0 [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//
18// Unidirectional pipe.
19//
20
21#include <utils/Pipe.h>
22#include <utils/Log.h>
23
24#if defined(HAVE_WIN32_IPC)
25# include <windows.h>
26#else
27# include <fcntl.h>
28# include <unistd.h>
29# include <errno.h>
30#endif
31
32#include <stdlib.h>
33#include <stdio.h>
34#include <assert.h>
35#include <string.h>
36
37using namespace android;
38
39const unsigned long kInvalidHandle = (unsigned long) -1;
40
41
42/*
43 * Constructor. Do little.
44 */
45Pipe::Pipe(void)
46 : mReadNonBlocking(false), mReadHandle(kInvalidHandle),
47 mWriteHandle(kInvalidHandle)
48{
49}
50
51/*
52 * Destructor. Use the system-appropriate close call.
53 */
54Pipe::~Pipe(void)
55{
56#if defined(HAVE_WIN32_IPC)
57 if (mReadHandle != kInvalidHandle) {
58 if (!CloseHandle((HANDLE)mReadHandle))
59 LOG(LOG_WARN, "pipe", "failed closing read handle (%ld)\n",
60 mReadHandle);
61 }
62 if (mWriteHandle != kInvalidHandle) {
63 FlushFileBuffers((HANDLE)mWriteHandle);
64 if (!CloseHandle((HANDLE)mWriteHandle))
65 LOG(LOG_WARN, "pipe", "failed closing write handle (%ld)\n",
66 mWriteHandle);
67 }
68#else
69 if (mReadHandle != kInvalidHandle) {
70 if (close((int) mReadHandle) != 0)
71 LOG(LOG_WARN, "pipe", "failed closing read fd (%d)\n",
72 (int) mReadHandle);
73 }
74 if (mWriteHandle != kInvalidHandle) {
75 if (close((int) mWriteHandle) != 0)
76 LOG(LOG_WARN, "pipe", "failed closing write fd (%d)\n",
77 (int) mWriteHandle);
78 }
79#endif
80}
81
82/*
83 * Create the pipe.
84 *
85 * Use the POSIX stuff for everything but Windows.
86 */
87bool Pipe::create(void)
88{
89 assert(mReadHandle == kInvalidHandle);
90 assert(mWriteHandle == kInvalidHandle);
91
92#if defined(HAVE_WIN32_IPC)
93 /* we use this across processes, so they need to be inheritable */
94 HANDLE handles[2];
95 SECURITY_ATTRIBUTES saAttr;
96
97 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
98 saAttr.bInheritHandle = TRUE;
99 saAttr.lpSecurityDescriptor = NULL;
100
101 if (!CreatePipe(&handles[0], &handles[1], &saAttr, 0)) {
102 LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
103 return false;
104 }
105 mReadHandle = (unsigned long) handles[0];
106 mWriteHandle = (unsigned long) handles[1];
107 return true;
108#else
109 int fds[2];
110
111 if (pipe(fds) != 0) {
112 LOG(LOG_ERROR, "pipe", "unable to create pipe\n");
113 return false;
114 }
115 mReadHandle = fds[0];
116 mWriteHandle = fds[1];
117 return true;
118#endif
119}
120
121/*
122 * Create a "half pipe". Please, no Segway riding.
123 */
124bool Pipe::createReader(unsigned long handle)
125{
126 mReadHandle = handle;
127 assert(mWriteHandle == kInvalidHandle);
128 return true;
129}
130
131/*
132 * Create a "half pipe" for writing.
133 */
134bool Pipe::createWriter(unsigned long handle)
135{
136 mWriteHandle = handle;
137 assert(mReadHandle == kInvalidHandle);
138 return true;
139}
140
141/*
142 * Return "true" if create() has been called successfully.
143 */
144bool Pipe::isCreated(void)
145{
146 // one or the other should be open
147 return (mReadHandle != kInvalidHandle || mWriteHandle != kInvalidHandle);
148}
149
150
151/*
152 * Read data from the pipe.
153 *
154 * For Linux and Darwin, just call read(). For Windows, implement
155 * non-blocking reads by calling PeekNamedPipe first.
156 */
157int Pipe::read(void* buf, int count)
158{
159 assert(mReadHandle != kInvalidHandle);
160
161#if defined(HAVE_WIN32_IPC)
162 DWORD totalBytesAvail = count;
163 DWORD bytesRead;
164
165 if (mReadNonBlocking) {
166 // use PeekNamedPipe to adjust read count expectations
167 if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
168 &totalBytesAvail, NULL))
169 {
170 LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
171 return -1;
172 }
173
174 if (totalBytesAvail == 0)
175 return 0;
176 }
177
178 if (!ReadFile((HANDLE) mReadHandle, buf, totalBytesAvail, &bytesRead,
179 NULL))
180 {
181 DWORD err = GetLastError();
182 if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
183 return 0;
184 LOG(LOG_ERROR, "pipe", "ReadFile failed (err=%ld)\n", err);
185 return -1;
186 }
187
188 return (int) bytesRead;
189#else
190 int cc;
191 cc = ::read(mReadHandle, buf, count);
192 if (cc < 0 && errno == EAGAIN)
193 return 0;
194 return cc;
195#endif
196}
197
198/*
199 * Write data to the pipe.
200 *
201 * POSIX systems are trivial, Windows uses a different call and doesn't
202 * handle non-blocking writes.
203 *
204 * If we add non-blocking support here, we probably want to make it an
205 * all-or-nothing write.
206 *
207 * DO NOT use LOG() here, we could be writing a log message.
208 */
209int Pipe::write(const void* buf, int count)
210{
211 assert(mWriteHandle != kInvalidHandle);
212
213#if defined(HAVE_WIN32_IPC)
214 DWORD bytesWritten;
215
216 if (mWriteNonBlocking) {
217 // BUG: can't use PeekNamedPipe() to get the amount of space
218 // left. Looks like we need to use "overlapped I/O" functions.
219 // I just don't care that much.
220 }
221
222 if (!WriteFile((HANDLE) mWriteHandle, buf, count, &bytesWritten, NULL)) {
223 // can't LOG, use stderr
224 fprintf(stderr, "WriteFile failed (err=%ld)\n", GetLastError());
225 return -1;
226 }
227
228 return (int) bytesWritten;
229#else
230 int cc;
231 cc = ::write(mWriteHandle, buf, count);
232 if (cc < 0 && errno == EAGAIN)
233 return 0;
234 return cc;
235#endif
236}
237
238/*
239 * Figure out if there is data available on the read fd.
240 *
241 * We return "true" on error because we want the caller to try to read
242 * from the pipe. They'll notice the read failure and do something
243 * appropriate.
244 */
245bool Pipe::readReady(void)
246{
247 assert(mReadHandle != kInvalidHandle);
248
249#if defined(HAVE_WIN32_IPC)
250 DWORD totalBytesAvail;
251
252 if (!PeekNamedPipe((HANDLE) mReadHandle, NULL, 0, NULL,
253 &totalBytesAvail, NULL))
254 {
255 LOG(LOG_ERROR, "pipe", "PeekNamedPipe failed\n");
256 return true;
257 }
258
259 return (totalBytesAvail != 0);
260#else
261 errno = 0;
262 fd_set readfds;
263 struct timeval tv = { 0, 0 };
264 int cc;
265
266 FD_ZERO(&readfds);
267 FD_SET(mReadHandle, &readfds);
268
269 cc = select(mReadHandle+1, &readfds, NULL, NULL, &tv);
270 if (cc < 0) {
271 LOG(LOG_ERROR, "pipe", "select() failed\n");
272 return true;
273 } else if (cc == 0) {
274 /* timed out, nothing available */
275 return false;
276 } else if (cc == 1) {
277 /* our fd is ready */
278 return true;
279 } else {
280 LOG(LOG_ERROR, "pipe", "HUH? select() returned > 1\n");
281 return true;
282 }
283#endif
284}
285
286/*
287 * Enable or disable non-blocking mode for the read descriptor.
288 *
289 * NOTE: the calls succeed under Mac OS X, but the pipe doesn't appear to
290 * actually be in non-blocking mode. If this matters -- i.e. you're not
291 * using a select() call -- put a call to readReady() in front of the
292 * ::read() call, with a PIPE_NONBLOCK_BROKEN #ifdef in the Makefile for
293 * Darwin.
294 */
295bool Pipe::setReadNonBlocking(bool val)
296{
297 assert(mReadHandle != kInvalidHandle);
298
299#if defined(HAVE_WIN32_IPC)
300 // nothing to do
301#else
302 int flags;
303
304 if (fcntl(mReadHandle, F_GETFL, &flags) == -1) {
305 LOG(LOG_ERROR, "pipe", "couldn't get flags for pipe read fd\n");
306 return false;
307 }
308 if (val)
309 flags |= O_NONBLOCK;
310 else
311 flags &= ~(O_NONBLOCK);
312 if (fcntl(mReadHandle, F_SETFL, &flags) == -1) {
313 LOG(LOG_ERROR, "pipe", "couldn't set flags for pipe read fd\n");
314 return false;
315 }
316#endif
317
318 mReadNonBlocking = val;
319 return true;
320}
321
322/*
323 * Enable or disable non-blocking mode for the write descriptor.
324 *
325 * As with setReadNonBlocking(), this does not work on the Mac.
326 */
327bool Pipe::setWriteNonBlocking(bool val)
328{
329 assert(mWriteHandle != kInvalidHandle);
330
331#if defined(HAVE_WIN32_IPC)
332 // nothing to do
333#else
334 int flags;
335
336 if (fcntl(mWriteHandle, F_GETFL, &flags) == -1) {
337 LOG(LOG_WARN, "pipe",
338 "Warning: couldn't get flags for pipe write fd (errno=%d)\n",
339 errno);
340 return false;
341 }
342 if (val)
343 flags |= O_NONBLOCK;
344 else
345 flags &= ~(O_NONBLOCK);
346 if (fcntl(mWriteHandle, F_SETFL, &flags) == -1) {
347 LOG(LOG_WARN, "pipe",
348 "Warning: couldn't set flags for pipe write fd (errno=%d)\n",
349 errno);
350 return false;
351 }
352#endif
353
354 mWriteNonBlocking = val;
355 return true;
356}
357
358/*
359 * Specify whether a file descriptor can be inherited by a child process.
360 * Under Linux this means setting the close-on-exec flag, under Windows
361 * this is SetHandleInformation(HANDLE_FLAG_INHERIT).
362 */
363bool Pipe::disallowReadInherit(void)
364{
365 if (mReadHandle == kInvalidHandle)
366 return false;
367
368#if defined(HAVE_WIN32_IPC)
369 if (SetHandleInformation((HANDLE) mReadHandle, HANDLE_FLAG_INHERIT, 0) == 0)
370 return false;
371#else
372 if (fcntl((int) mReadHandle, F_SETFD, FD_CLOEXEC) != 0)
373 return false;
374#endif
375 return true;
376}
377bool Pipe::disallowWriteInherit(void)
378{
379 if (mWriteHandle == kInvalidHandle)
380 return false;
381
382#if defined(HAVE_WIN32_IPC)
383 if (SetHandleInformation((HANDLE) mWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0)
384 return false;
385#else
386 if (fcntl((int) mWriteHandle, F_SETFD, FD_CLOEXEC) != 0)
387 return false;
388#endif
389 return true;
390}
391
392/*
393 * Close read descriptor.
394 */
395bool Pipe::closeRead(void)
396{
397 if (mReadHandle == kInvalidHandle)
398 return false;
399
400#if defined(HAVE_WIN32_IPC)
401 if (mReadHandle != kInvalidHandle) {
402 if (!CloseHandle((HANDLE)mReadHandle)) {
403 LOG(LOG_WARN, "pipe", "failed closing read handle\n");
404 return false;
405 }
406 }
407#else
408 if (mReadHandle != kInvalidHandle) {
409 if (close((int) mReadHandle) != 0) {
410 LOG(LOG_WARN, "pipe", "failed closing read fd\n");
411 return false;
412 }
413 }
414#endif
415 mReadHandle = kInvalidHandle;
416 return true;
417}
418
419/*
420 * Close write descriptor.
421 */
422bool Pipe::closeWrite(void)
423{
424 if (mWriteHandle == kInvalidHandle)
425 return false;
426
427#if defined(HAVE_WIN32_IPC)
428 if (mWriteHandle != kInvalidHandle) {
429 if (!CloseHandle((HANDLE)mWriteHandle)) {
430 LOG(LOG_WARN, "pipe", "failed closing write handle\n");
431 return false;
432 }
433 }
434#else
435 if (mWriteHandle != kInvalidHandle) {
436 if (close((int) mWriteHandle) != 0) {
437 LOG(LOG_WARN, "pipe", "failed closing write fd\n");
438 return false;
439 }
440 }
441#endif
442 mWriteHandle = kInvalidHandle;
443 return true;
444}
445
446/*
447 * Get the read handle.
448 */
449unsigned long Pipe::getReadHandle(void)
450{
451 assert(mReadHandle != kInvalidHandle);
452
453 return mReadHandle;
454}
455
456/*
457 * Get the write handle.
458 */
459unsigned long Pipe::getWriteHandle(void)
460{
461 assert(mWriteHandle != kInvalidHandle);
462
463 return mWriteHandle;
464}
465