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(); } }
// Low level interface void Cpp2Channel::sendMessage(SendCallback* callback, std::unique_ptr<folly::IOBuf>&& buf) { // Callback may be null. assert(buf); if (!transport_->good()) { VLOG(5) << "Channel is !good() in sendMessage"; // Callback must be last thing in sendMessage, or use guard if (callback) { callback->messageSendError( folly::make_exception_wrapper<TTransportException>( "Channel is !good()")); } return; } std::vector<SendCallback*> cbs; if (callback) { callback->sendQueued(); cbs.push_back(callback); } sendCallbacks_.push_back(std::move(cbs)); DestructorGuard dg(this); auto future = pipeline_->write(std::move(buf)); future.then([this,dg](folly::Try<void>&& t) { if (t.withException<TTransportException>( [&](const TTransportException& ex) { writeError(0, ex); }) || t.withException<std::exception>( [&](const std::exception& ex) { writeError(0, TTransportException(ex.what())); })) { return; } else { writeSuccess(); } }); }