• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "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 
37 using namespace android;
38 
39 const unsigned long kInvalidHandle = (unsigned long) -1;
40 
41 
42 /*
43  * Constructor.  Do little.
44  */
Pipe(void)45 Pipe::Pipe(void)
46     : mReadNonBlocking(false), mReadHandle(kInvalidHandle),
47       mWriteHandle(kInvalidHandle)
48 {
49 }
50 
51 /*
52  * Destructor.  Use the system-appropriate close call.
53  */
~Pipe(void)54 Pipe::~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  */
create(void)87 bool 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  */
createReader(unsigned long handle)124 bool 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  */
createWriter(unsigned long handle)134 bool 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  */
isCreated(void)144 bool 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  */
read(void * buf,int count)157 int 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  */
write(const void * buf,int count)209 int 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  */
readReady(void)245 bool 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  */
setReadNonBlocking(bool val)295 bool 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  */
setWriteNonBlocking(bool val)327 bool 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  */
disallowReadInherit(void)363 bool 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 }
disallowWriteInherit(void)377 bool 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  */
closeRead(void)395 bool 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  */
closeWrite(void)422 bool 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  */
getReadHandle(void)449 unsigned long Pipe::getReadHandle(void)
450 {
451     assert(mReadHandle != kInvalidHandle);
452 
453     return mReadHandle;
454 }
455 
456 /*
457  * Get the write handle.
458  */
getWriteHandle(void)459 unsigned long Pipe::getWriteHandle(void)
460 {
461     assert(mWriteHandle != kInvalidHandle);
462 
463     return mWriteHandle;
464 }
465 
466