void AsyncMockStreamFactory::MockStream::read(asio::mutable_buffer buf, StreamHandler&& readHandler) { // Suspend execution before data is read. _defer(kBlockedBeforeRead, [this, buf, readHandler]() { stdx::unique_lock<stdx::mutex> lk(_mutex); auto nextRead = std::move(_readQueue.front()); _readQueue.pop(); auto beginDst = asio::buffer_cast<uint8_t*>(buf); auto nToCopy = std::min(nextRead.size(), asio::buffer_size(buf)); auto endSrc = std::begin(nextRead); std::advance(endSrc, nToCopy); auto endDst = std::copy(std::begin(nextRead), endSrc, beginDst); invariant((endDst - beginDst) == static_cast<std::ptrdiff_t>(nToCopy)); log() << "read " << nToCopy << " bytes, " << (nextRead.size() - nToCopy) << " remaining in buffer"; lk.unlock(); _io_service->post( [readHandler, nToCopy] { readHandler(std::error_code(), nToCopy); }); }); }
void AsyncMockStreamFactory::MockStream::connect(asio::ip::tcp::resolver::iterator endpoints, ConnectHandler&& connectHandler) { // Suspend execution after "connecting" _defer(kBlockedBeforeConnect, [this, connectHandler, endpoints]() { _io_service->post( [connectHandler, endpoints] { connectHandler(std::error_code()); }); }); }
void AsyncMockStreamFactory::MockStream::connect(asio::ip::tcp::resolver::iterator endpoints, ConnectHandler&& connectHandler) { // Suspend execution after "connecting" _defer(kBlockedBeforeConnect, [this, connectHandler, endpoints]() { stdx::unique_lock<stdx::mutex> lk(_mutex); // We shim a lambda to give connectHandler the right signature since it doesn't take // a size_t param. checkCanceled( _io_service, &_state, [connectHandler](std::error_code ec, std::size_t) { return connectHandler(ec); }, 0); }); }
void AsyncMockStreamFactory::MockStream::read(asio::mutable_buffer buf, StreamHandler&& readHandler) { // Suspend execution before data is read. _defer(kBlockedBeforeRead, [this, buf, readHandler]() { stdx::unique_lock<stdx::mutex> lk(_mutex); int nToCopy = 0; // If we've set an error, return that instead of a read. if (!_error) { auto nextRead = std::move(_readQueue.front()); _readQueue.pop(); auto beginDst = asio::buffer_cast<uint8_t*>(buf); nToCopy = std::min(nextRead.size(), asio::buffer_size(buf)); auto endSrc = std::begin(nextRead); std::advance(endSrc, nToCopy); auto endDst = std::copy(std::begin(nextRead), endSrc, beginDst); invariant((endDst - beginDst) == static_cast<std::ptrdiff_t>(nToCopy)); log() << "read " << nToCopy << " bytes, " << (nextRead.size() - nToCopy) << " remaining in buffer"; } auto handler = readHandler; // If we did not receive all the bytes, we should return an error if (static_cast<size_t>(nToCopy) < asio::buffer_size(buf)) { handler = [readHandler](std::error_code ec, size_t len) { // If we have an error here we've been canceled, and that takes precedence if (ec) return readHandler(ec, len); // Call the original handler with an error readHandler(make_error_code(ErrorCodes::InvalidLength), len); }; } checkCanceled(_io_service, &_state, std::move(handler), nToCopy, _error); _error.clear(); }); }