void NetworkInterfaceASIO::_beginCommunication(AsyncOp* op) {
    if (op->canceled()) {
        return _completeOperation(op, kCanceledStatus);
    }

    auto negotiatedProtocol =
        rpc::negotiate(op->connection()->serverProtocols(), op->connection()->clientProtocols());

    if (!negotiatedProtocol.isOK()) {
        return _completeOperation(op, negotiatedProtocol.getStatus());
    }

    op->setOperationProtocol(negotiatedProtocol.getValue());

    op->setToSend(std::move(*_messageFromRequest(op->request(), negotiatedProtocol.getValue())));

    // TODO: Is this logic actually necessary (SERVER-19320)?
    if (op->toSend()->empty())
        return _completedWriteCallback(op);

    // TODO: Some day we may need to support vector messages.
    fassert(28708, op->toSend()->buf() != 0);
    asio::const_buffer buf(op->toSend()->buf(), op->toSend()->size());
    return _asyncSendSimpleMessage(op, buf);
}
void NetworkInterfaceASIO::_recvMessageBody(AsyncOp* op) {
    // TODO: This error code should be more meaningful.
    std::error_code ec;

    // validate message length
    int len = op->header()->constView().getMessageLength();
    if (len == 542393671) {
        LOG(3) << "attempt to access MongoDB over HTTP on the native driver port.";
        return _networkErrorCallback(op, ec);
    } else if (len == -1) {
        // TODO: An endian check is run after the client connects, we should
        // set that we've received the client's handshake
        LOG(3) << "Endian check received from client";
        return _networkErrorCallback(op, ec);
    } else if (static_cast<size_t>(len) < sizeof(MSGHEADER::Value) ||
               static_cast<size_t>(len) > MaxMessageSizeBytes) {
        warning() << "recv(): message len " << len << " is invalid. "
                  << "Min " << sizeof(MSGHEADER::Value) << " Max: " << MaxMessageSizeBytes;
        return _networkErrorCallback(op, ec);
    }

    // validate response id
    uint32_t expectedId = op->toSend()->header().getId();
    uint32_t actualId = op->header()->constView().getResponseTo();
    if (actualId != expectedId) {
        LOG(3) << "got wrong response:"
               << " expected response id: " << expectedId << ", got response id: " << actualId;
        return _networkErrorCallback(op, ec);
    }

    int z = (len + 1023) & 0xfffffc00;
    invariant(z >= len);
    op->toRecv()->setData(reinterpret_cast<char*>(mongoMalloc(z)), true);
    MsgData::View mdView = op->toRecv()->buf();

    // copy header data into master buffer
    int headerLen = sizeof(MSGHEADER::Value);
    memcpy(mdView.view2ptr(), op->header(), headerLen);
    int bodyLength = len - headerLen;
    invariant(bodyLength >= 0);

    // receive remaining data into md->data
    asio::async_read(op->connection()->sock(),
                     asio::buffer(mdView.data(), bodyLength),
                     [this, op, mdView](asio::error_code ec, size_t bytes) {

                         if (op->canceled()) {
                             return _completeOperation(op, kCanceledStatus);
                         }

                         if (ec) {
                             LOG(3) << "error receiving message body";
                             return _networkErrorCallback(op, ec);
                         }

                         return _completedWriteCallback(op);
                     });
}
void NetworkInterfaceASIO::_beginCommunication(AsyncOp* op) {
    if (op->canceled()) {
        return _completeOperation(op, kCanceledStatus);
    }

    Message* toSend = op->toSend();
    _messageFromRequest(op->request(), toSend);

    if (toSend->empty())
        return _completedWriteCallback(op);

    // TODO: Some day we may need to support vector messages.
    fassert(28708, toSend->buf() != 0);
    asio::const_buffer buf(toSend->buf(), toSend->size());
    return _asyncSendSimpleMessage(op, buf);
}