예제 #1
0
void AsyncPipeReader::failRead(const AsyncSocketException& ex) {
  VLOG(5) << "AsyncPipeReader(this=" << this << ", fd=" << fd_
          << "): failed while reading: " << ex.what();

  DCHECK(readCallback_ != nullptr);
  AsyncReader::ReadCallback* callback = readCallback_;
  readCallback_ = nullptr;
  callback->readErr(ex);
  close();
}
예제 #2
0
void AsyncPipeReader::handlerReady(uint16_t events) noexcept {
  DestructorGuard dg(this);
  CHECK(events & EventHandler::READ);

  VLOG(5) << "AsyncPipeReader::handlerReady() this=" << this << ", fd=" << fd_;
  assert(readCallback_ != nullptr);

  while (readCallback_) {
    // - What API does callback support?
    const auto movable = readCallback_->isBufferMovable(); // noexcept

    // Get the buffer to read into.
    void* buf = nullptr;
    size_t buflen = 0;
    std::unique_ptr<IOBuf> ioBuf;

    if (movable) {
      ioBuf = IOBuf::create(readCallback_->maxBufferSize());
      buf = ioBuf->writableBuffer();
      buflen = ioBuf->capacity();
    } else {
      try {
        readCallback_->getReadBuffer(&buf, &buflen);
      } catch (const std::exception& ex) {
        AsyncSocketException aex(
            AsyncSocketException::BAD_ARGS,
            string("ReadCallback::getReadBuffer() "
                   "threw exception: ") +
                ex.what());
        failRead(aex);
        return;
      } catch (...) {
        AsyncSocketException aex(
            AsyncSocketException::BAD_ARGS,
            string("ReadCallback::getReadBuffer() "
                   "threw non-exception type"));
        failRead(aex);
        return;
      }
      if (buf == nullptr || buflen == 0) {
        AsyncSocketException aex(
            AsyncSocketException::INVALID_STATE,
            string("ReadCallback::getReadBuffer() "
                   "returned empty buffer"));
        failRead(aex);
        return;
      }
    }

    // Perform the read
#if _WIN32
    // On Windows you can't call read on a socket, so call recv instead.
    ssize_t bytesRead =
        folly::fileutil_detail::wrapNoInt(recv_internal, fd_, buf, buflen);
#else
    ssize_t bytesRead = folly::readNoInt(fd_.toFd(), buf, buflen);
#endif

    if (bytesRead > 0) {
      if (movable) {
        ioBuf->append(std::size_t(bytesRead));
        readCallback_->readBufferAvailable(std::move(ioBuf));
      } else {
        readCallback_->readDataAvailable(size_t(bytesRead));
      }
      // Fall through and continue around the loop if the read
      // completely filled the available buffer.
      // Note that readCallback_ may have been uninstalled or changed inside
      // readDataAvailable().
      if (static_cast<size_t>(bytesRead) < buflen) {
        return;
      }
    } else if (bytesRead < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
      // No more data to read right now.
      return;
    } else if (bytesRead < 0) {
      AsyncSocketException ex(
          AsyncSocketException::INVALID_STATE, "read failed", errno);
      failRead(ex);
      return;
    } else {
      assert(bytesRead == 0);
      // EOF

      unregisterHandler();
      AsyncReader::ReadCallback* callback = readCallback_;
      readCallback_ = nullptr;
      callback->readEOF();
      return;
    }
    // Max reads per loop?
  }
}
예제 #3
0
void AsyncPipeReader::handlerReady(uint16_t events) noexcept {
  DestructorGuard dg(this);
  CHECK(events & EventHandler::READ);

  VLOG(5) << "AsyncPipeReader::handlerReady() this=" << this << ", fd=" << fd_;
  assert(readCallback_ != nullptr);

  while (readCallback_) {
    // Get the buffer to read into.
    void* buf = nullptr;
    size_t buflen = 0;
    try {
      readCallback_->getReadBuffer(&buf, &buflen);
    } catch (const std::exception& ex) {
      AsyncSocketException aex(AsyncSocketException::BAD_ARGS,
                               string("ReadCallback::getReadBuffer() "
                                      "threw exception: ") + ex.what());
      failRead(aex);
      return;
    } catch (...) {
      AsyncSocketException ex(AsyncSocketException::BAD_ARGS,
                              string("ReadCallback::getReadBuffer() "
                                     "threw non-exception type"));
      failRead(ex);
      return;
    }
    if (buf == nullptr || buflen == 0) {
      AsyncSocketException ex(AsyncSocketException::INVALID_STATE,
                              string("ReadCallback::getReadBuffer() "
                                     "returned empty buffer"));
      failRead(ex);
      return;
    }

    // Perform the read
    ssize_t bytesRead = folly::readNoInt(fd_, buf, buflen);
    if (bytesRead > 0) {
      readCallback_->readDataAvailable(bytesRead);
      // Fall through and continue around the loop if the read
      // completely filled the available buffer.
      // Note that readCallback_ may have been uninstalled or changed inside
      // readDataAvailable().
      if (static_cast<size_t>(bytesRead) < buflen) {
        return;
      }
    } else if (bytesRead < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
      // No more data to read right now.
      return;
    } else if (bytesRead < 0) {
      AsyncSocketException ex(AsyncSocketException::INVALID_STATE,
                              "read failed", errno);
      failRead(ex);
      return;
    } else {
      assert(bytesRead == 0);
      // EOF

      unregisterHandler();
      AsyncReader::ReadCallback* callback = readCallback_;
      readCallback_ = nullptr;
      callback->readEOF();
      return;
    }
    // Max reads per loop?
  }
}