Home | History | Annotate | Download | only in app
      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  */
     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  */
     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  */
     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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 }
    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  */
    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  */
    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  */
    449 unsigned long Pipe::getReadHandle(void)
    450 {
    451     assert(mReadHandle != kInvalidHandle);
    452 
    453     return mReadHandle;
    454 }
    455 
    456 /*
    457  * Get the write handle.
    458  */
    459 unsigned long Pipe::getWriteHandle(void)
    460 {
    461     assert(mWriteHandle != kInvalidHandle);
    462 
    463     return mWriteHandle;
    464 }
    465 
    466