Ejemplo n.º 1
0
void FileRegion::FileWriteRequest::FileReadHandler::handlerReady(
    uint16_t events) noexcept {
  CHECK(events & EventHandler::WRITE);
  if (bytesToRead_ == 0) {
    unregisterHandler();
    return;
  }

  int flags = SPLICE_F_NONBLOCK | SPLICE_F_MORE;
  ssize_t spliced = ::splice(req_->readFd_, &req_->offset_,
                             pipe_in_, nullptr,
                             bytesToRead_, flags);
  if (spliced == -1) {
    if (errno == EAGAIN) {
      return;
    } else {
      req_->fail(__func__, AsyncSocketException(
          AsyncSocketException::INTERNAL_ERROR,
          "splice failed", errno));
      return;
    }
  }

  if (spliced > 0) {
    bytesToRead_ -= spliced;
    try {
      req_->queue_.putMessage(static_cast<size_t>(spliced));
    } catch (...) {
      req_->fail(__func__, AsyncSocketException(
          AsyncSocketException::INTERNAL_ERROR,
          "putMessage failed"));
      return;
    }
  }
}
Ejemplo n.º 2
0
void AsyncUDPSocket::dontFragment(bool df) {
  (void)df; // to avoid potential unused variable warning
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) && \
    defined(IP_PMTUDISC_WANT)
  if (address().getFamily() == AF_INET) {
    int v4 = df ? IP_PMTUDISC_DO : IP_PMTUDISC_WANT;
    if (fsp::setsockopt(fd_, IPPROTO_IP, IP_MTU_DISCOVER, &v4, sizeof(v4))) {
      throw AsyncSocketException(
          AsyncSocketException::NOT_OPEN,
          "Failed to set DF with IP_MTU_DISCOVER",
          errno);
    }
  }
#endif
#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) && \
    defined(IPV6_PMTUDISC_WANT)
  if (address().getFamily() == AF_INET6) {
    int v6 = df ? IPV6_PMTUDISC_DO : IPV6_PMTUDISC_WANT;
    if (fsp::setsockopt(
            fd_, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &v6, sizeof(v6))) {
      throw AsyncSocketException(
          AsyncSocketException::NOT_OPEN,
          "Failed to set DF with IPV6_MTU_DISCOVER",
          errno);
    }
  }
#endif
}
Ejemplo n.º 3
0
void FileRegion::FileWriteRequest::start() {
  started_ = true;
  readBase_ = readPool.get()->getEventBase();
  readBase_->runInEventBaseThread([this]{
    auto flags = fcntl(readFd_, F_GETFL);
    if (flags == -1) {
      fail(__func__, AsyncSocketException(
          AsyncSocketException::INTERNAL_ERROR,
          "fcntl F_GETFL failed", errno));
      return;
    }

    flags &= O_ACCMODE;
    if (flags == O_WRONLY) {
      fail(__func__, AsyncSocketException(
          AsyncSocketException::BAD_ARGS, "file not open for reading"));
      return;
    }

#ifndef GLIBC_AT_LEAST_2_9
    fail(__func__, AsyncSocketException(
        AsyncSocketException::NOT_SUPPORTED,
        "writeFile unsupported on glibc < 2.9"));
    return;
#else
    int pipeFds[2];
    if (::pipe2(pipeFds, O_NONBLOCK) == -1) {
      fail(__func__, AsyncSocketException(
          AsyncSocketException::INTERNAL_ERROR,
          "pipe2 failed", errno));
      return;
    }

#ifdef F_SETPIPE_SZ
    // Max size for unprevileged processes as set in /proc/sys/fs/pipe-max-size
    // Ignore failures and just roll with it
    // TODO maybe read max size from /proc?
    fcntl(pipeFds[0], F_SETPIPE_SZ, 1048576);
    fcntl(pipeFds[1], F_SETPIPE_SZ, 1048576);
#endif

    pipe_out_ = pipeFds[0];

    socket_->getEventBase()->runInEventBaseThreadAndWait([&]{
      startConsuming(socket_->getEventBase(), &queue_);
    });
    readHandler_ = folly::make_unique<FileReadHandler>(
        this, pipeFds[1], count_);
#endif
  });
}
Ejemplo n.º 4
0
void AsyncUDPSocket::setErrMessageCallback(
    ErrMessageCallback* errMessageCallback) {
  errMessageCallback_ = errMessageCallback;
  int err = (errMessageCallback_ != nullptr);
#if defined(IP_RECVERR)
  if (address().getFamily() == AF_INET &&
      fsp::setsockopt(fd_, IPPROTO_IP, IP_RECVERR, &err, sizeof(err))) {
    throw AsyncSocketException(
        AsyncSocketException::NOT_OPEN, "Failed to set IP_RECVERR", errno);
  }
#endif
#if defined(IPV6_RECVERR)
  if (address().getFamily() == AF_INET6 &&
      fsp::setsockopt(fd_, IPPROTO_IPV6, IPV6_RECVERR, &err, sizeof(err))) {
    throw AsyncSocketException(
        AsyncSocketException::NOT_OPEN, "Failed to set IPV6_RECVERR", errno);
  }
#endif
  (void)err;
}
Ejemplo n.º 5
0
FileRegion::FileWriteRequest::FileReadHandler::FileReadHandler(
    FileWriteRequest* req, int pipe_in, size_t bytesToRead)
  : req_(req), pipe_in_(pipe_in), bytesToRead_(bytesToRead) {
  CHECK(req_->readBase_->isInEventBaseThread());
  initHandler(req_->readBase_, pipe_in);
  if (!registerHandler(EventFlags::WRITE | EventFlags::PERSIST)) {
    req_->fail(__func__, AsyncSocketException(
        AsyncSocketException::INTERNAL_ERROR,
        "registerHandler failed"));
  }
}
Ejemplo n.º 6
0
void AsyncPipeWriter::handleWrite() {
  DestructorGuard dg(this);
  assert(!queue_.empty());
  do {
    auto& front = queue_.front();
    folly::IOBufQueue& curQueue = front.first;
    DCHECK(!curQueue.empty());
    // someday, support writev.  The logic for partial writes is a bit complex
    const IOBuf* head = curQueue.front();
    CHECK(head->length());
#if _WIN32
    // On Windows you can't call write on a socket.
    ssize_t rc = folly::fileutil_detail::wrapNoInt(
        send_internal, fd_, head->data(), head->length());
#else
    ssize_t rc = folly::writeNoInt(fd_.toFd(), head->data(), head->length());
#endif
    if (rc < 0) {
      if (errno == EAGAIN || errno == EWOULDBLOCK) {
        // pipe is full
        VLOG(5) << "write blocked";
        registerHandler(EventHandler::WRITE);
        return;
      } else {
        failAllWrites(AsyncSocketException(
            AsyncSocketException::INTERNAL_ERROR, "write failed", errno));
        closeNow();
        return;
      }
    } else if (rc == 0) {
      registerHandler(EventHandler::WRITE);
      return;
    }
    curQueue.trimStart(size_t(rc));
    if (curQueue.empty()) {
      auto cb = front.second;
      queue_.pop_front();
      if (cb) {
        cb->writeSuccess();
      }
    } else {
      VLOG(5) << "partial write blocked";
    }
  } while (!queue_.empty());

  if (closeOnEmpty_) {
    closeNow();
  } else {
    unregisterHandler();
  }
}
Ejemplo n.º 7
0
void AsyncPipeWriter::closeNow() {
  VLOG(5) << "close now";
  if (!queue_.empty()) {
    failAllWrites(AsyncSocketException(
        AsyncSocketException::NOT_OPEN, "closed with pending writes"));
  }
  if (fd_ != NetworkSocket()) {
    unregisterHandler();
    changeHandlerFD(NetworkSocket());
    if (closeCb_) {
      closeCb_(fd_);
    } else {
      netops::close(fd_);
    }
    fd_ = NetworkSocket();
  }
}
Ejemplo n.º 8
0
void AsyncUDPSocket::bind(const folly::SocketAddress& address) {
  int socket = fsp::socket(address.getFamily(), SOCK_DGRAM, IPPROTO_UDP);
  if (socket == -1) {
    throw AsyncSocketException(
        AsyncSocketException::NOT_OPEN,
        "error creating async udp socket",
        errno);
  }

  auto g = folly::makeGuard([&] { ::close(socket); });

  // put the socket in non-blocking mode
  int ret = fcntl(socket, F_SETFL, O_NONBLOCK);
  if (ret != 0) {
    throw AsyncSocketException(
        AsyncSocketException::NOT_OPEN,
        "failed to put socket in non-blocking mode",
        errno);
  }

  if (reuseAddr_) {
    // put the socket in reuse mode
    int value = 1;
    if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)) !=
        0) {
      throw AsyncSocketException(
          AsyncSocketException::NOT_OPEN,
          "failed to put socket in reuse mode",
          errno);
    }
  }

  if (reusePort_) {
    // put the socket in port reuse mode
    int value = 1;
    if (setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value)) !=
        0) {
      throw AsyncSocketException(
          AsyncSocketException::NOT_OPEN,
          "failed to put socket in reuse_port mode",
          errno);
    }
  }

  if (busyPollUs_ > 0) {
#ifdef SO_BUSY_POLL
    // Set busy_poll time in microseconds on the socket.
    // It sets how long socket will be in busy_poll mode when no event occurs.
    int value = busyPollUs_;
    if (setsockopt(socket, SOL_SOCKET, SO_BUSY_POLL, &value, sizeof(value)) !=
        0) {
      throw AsyncSocketException(
          AsyncSocketException::NOT_OPEN,
          "failed to set SO_BUSY_POLL on the socket",
          errno);
    }
#else /* SO_BUSY_POLL is not supported*/
    throw AsyncSocketException(
        AsyncSocketException::NOT_OPEN, "SO_BUSY_POLL is not supported", errno);
#endif
  }

  if (rcvBuf_ > 0) {
    // Set the size of the buffer for the received messages in rx_queues.
    int value = rcvBuf_;
    if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) != 0) {
      throw AsyncSocketException(
          AsyncSocketException::NOT_OPEN,
          "failed to set SO_RCVBUF on the socket",
          errno);
    }
  }

  if (sndBuf_ > 0) {
    // Set the size of the buffer for the sent messages in tx_queues.
    int value = rcvBuf_;
    if (setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) != 0) {
      throw AsyncSocketException(
          AsyncSocketException::NOT_OPEN,
          "failed to set SO_SNDBUF on the socket",
          errno);
    }
  }

  // If we're using IPv6, make sure we don't accept V4-mapped connections
  if (address.getFamily() == AF_INET6) {
    int flag = 1;
    if (setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag))) {
      throw AsyncSocketException(
          AsyncSocketException::NOT_OPEN, "Failed to set IPV6_V6ONLY", errno);
    }
  }

  // bind to the address
  sockaddr_storage addrStorage;
  address.getAddress(&addrStorage);
  sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage);
  if (fsp::bind(socket, saddr, address.getActualSize()) != 0) {
    throw AsyncSocketException(
        AsyncSocketException::NOT_OPEN,
        "failed to bind the async udp socket for:" + address.describe(),
        errno);
  }

  // success
  g.dismiss();
  fd_ = socket;
  ownership_ = FDOwnership::OWNS;

  // attach to EventHandler
  EventHandler::changeHandlerFD(fd_);

  if (address.getPort() != 0) {
    localAddress_ = address;
  } else {
    localAddress_.setFromLocalAddress(fd_);
  }
}
Ejemplo n.º 9
0
void AsyncUDPSocket::bind(const folly::SocketAddress& address) {
  int socket = fsp::socket(address.getFamily(), SOCK_DGRAM, IPPROTO_UDP);
  if (socket == -1) {
    throw AsyncSocketException(AsyncSocketException::NOT_OPEN,
                              "error creating async udp socket",
                              errno);
  }

  auto g = folly::makeGuard([&] { ::close(socket); });

  // put the socket in non-blocking mode
  int ret = fcntl(socket, F_SETFL, O_NONBLOCK);
  if (ret != 0) {
    throw AsyncSocketException(AsyncSocketException::NOT_OPEN,
                              "failed to put socket in non-blocking mode",
                              errno);
  }

  if (reuseAddr_) {
    // put the socket in reuse mode
    int value = 1;
    if (setsockopt(socket,
                  SOL_SOCKET,
                  SO_REUSEADDR,
                  &value,
                  sizeof(value)) != 0) {
      throw AsyncSocketException(AsyncSocketException::NOT_OPEN,
                                "failed to put socket in reuse mode",
                                errno);
    }
  }

  if (reusePort_) {
    // put the socket in port reuse mode
    int value = 1;
    if (setsockopt(socket,
                   SOL_SOCKET,
                   SO_REUSEPORT,
                   &value,
                   sizeof(value)) != 0) {
      throw AsyncSocketException(AsyncSocketException::NOT_OPEN,
                                "failed to put socket in reuse_port mode",
                                errno);

    }
  }

  // If we're using IPv6, make sure we don't accept V4-mapped connections
  if (address.getFamily() == AF_INET6) {
    int flag = 1;
    if (setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag))) {
      throw AsyncSocketException(
        AsyncSocketException::NOT_OPEN,
        "Failed to set IPV6_V6ONLY",
        errno);
    }
  }

  // bind to the address
  sockaddr_storage addrStorage;
  address.getAddress(&addrStorage);
  sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage);
  if (fsp::bind(socket, saddr, address.getActualSize()) != 0) {
    throw AsyncSocketException(
        AsyncSocketException::NOT_OPEN,
        "failed to bind the async udp socket for:" + address.describe(),
        errno);
  }

  // success
  g.dismiss();
  fd_ = socket;
  ownership_ = FDOwnership::OWNS;

  // attach to EventHandler
  EventHandler::changeHandlerFD(fd_);

  if (address.getPort() != 0) {
    localAddress_ = address;
  } else {
    localAddress_.setFromLocalAddress(fd_);
  }
}