inline ctsIoPatternError ctsIoPatternState::CompletedTask()

in ctsTraffic/ctsIOPatternState.hpp [295:504]


inline ctsIoPatternError ctsIoPatternState::CompletedTask(const ctsTask& completedTask, uint32_t completedTransferBytes) noexcept
{
    // If already failed, don't continue processing
    if (InternalPatternState::ErrorIoFailed == m_internalState)
    {
        return ctsIoPatternError::ErrorIoFailed;
    }

    // if completed our connection id request, immediately return
    // (not validating IO below)
    if (InternalPatternState::ServerSendConnectionId == m_internalState || InternalPatternState::ClientRecvConnectionId == m_internalState)
    {
        // must have received the full id
        if (completedTransferBytes != ctsStatistics::ConnectionIdLength)
        {
            PRINT_DEBUG_INFO(
                L"\t\tctsIOPatternState::CompletedTask : ErrorIOFailed (TooFewBytes) [transfered %u, Expected ConnectionID (%u)]\n",
                completedTransferBytes,
                ctsStatistics::ConnectionIdLength);

            m_internalState = InternalPatternState::ErrorIoFailed;
            return ctsIoPatternError::TooFewBytes;
        }

        m_pendedState = false;
    }

    if (completedTask.m_trackIo)
    {
        // Checking for an inconsistent internal state 
        FAIL_FAST_IF_MSG(
            completedTransferBytes > m_inflightBytes,
            "ctsIOPatternState::CompletedTask : ctsIOTask (%p) returned more bytes (%u) than were in flight (%llu)",
            &completedTask, completedTransferBytes, m_inflightBytes);
        FAIL_FAST_IF_MSG(
            completedTask.m_bufferLength > m_inflightBytes,
            "ctsIOPatternState::CompletedTask : the ctsIOTask (%p) had requested more bytes (%u) than were in-flight (%llu)\n",
            &completedTask, completedTask.m_bufferLength, m_inflightBytes);
        FAIL_FAST_IF_MSG(
            completedTransferBytes > completedTask.m_bufferLength,
            "ctsIOPatternState::CompletedTask : ctsIOTask (%p) returned more bytes (%u) than were posted (%u)\n",
            &completedTask, completedTransferBytes, completedTask.m_bufferLength);

        // now update our internal tracking of bytes in-flight / completed
        m_inflightBytes -= completedTask.m_bufferLength;
        m_confirmedBytes += completedTransferBytes;
    }

    // Verify IO Post-condition protocol contracts haven't been violated
    const auto alreadyTransferred = m_confirmedBytes + m_inflightBytes;

    // Udp just tracks bytes
    if (ctsConfig::ProtocolType::UDP == ctsConfig::g_configSettings->Protocol)
    {
        if (alreadyTransferred == m_maxTransfer)
        {
            return ctsIoPatternError::SuccessfullyCompleted;
        }
        return ctsIoPatternError::NoError;
    }

    // Tcp has a full state machine
    if (alreadyTransferred < m_maxTransfer)
    {
        // guard against the client gracefully exiting before the completion of the transfer
        if (0 == completedTransferBytes)
        {
            PRINT_DEBUG_INFO(
                L"\t\tctsIOPatternState::CompletedTask : ErrorIOFailed (TooFewBytes) [transferred %llu, expected transfer %llu]\n",
                alreadyTransferred,
                m_maxTransfer);

            m_internalState = InternalPatternState::ErrorIoFailed;
            return ctsIoPatternError::TooFewBytes;
        }
    }
    else if (alreadyTransferred == m_maxTransfer)
    {
        // With TCP, if inflight_bytes > 0, we are not yet done
        // - we need to wait for that pended IO to complete
        if (0 == m_inflightBytes)
        {
            //
            // All TCP data has been sent/received
            //
            if (ctsConfig::IsListening())
            {
                // servers will first send their final status before starting their shutdown sequence
                switch (m_internalState)
                {
                    case InternalPatternState::MoreIo:
                        PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (MoreIo) : ServerSendCompletion\n");
                        m_internalState = InternalPatternState::ServerSendCompletion;
                        m_pendedState = false;
                        break;

                    case InternalPatternState::ServerSendCompletion:
                        PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (ServerSendCompletion) : RequestFIN\n");
                        m_internalState = InternalPatternState::RequestFin;
                        m_pendedState = false;
                        break;

                    case InternalPatternState::RequestFin:
                    {
                        if (completedTransferBytes != 0)
                        {
                            PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (RequestFIN) : ErrorIOFailed (TooManyBytes)\n");
                            m_internalState = InternalPatternState::ErrorIoFailed;
                            return ctsIoPatternError::TooManyBytes;
                        }

                        PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (RequestFIN) : CompletedTransfer\n");
                        m_internalState = InternalPatternState::CompletedTransfer;
                        return ctsIoPatternError::SuccessfullyCompleted;
                    }

                    default:
                        FAIL_FAST_MSG(
                            "ctsIOPatternState::CompletedTask - invalid internal_status (%d): dt %p ctsTraffic!ctsTraffic::ctsIOPatternState",
                            m_internalState, this);
                }
            }
            else
            {
                // clients will recv the server status, then process their shutdown sequence
                switch (m_internalState)
                {
                    case InternalPatternState::MoreIo:
                        PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (MoreIo) : ClientRecvCompletion\n");
                        m_internalState = InternalPatternState::ClientRecvCompletion;
                        m_pendedState = false;
                        break;

                    case InternalPatternState::ClientRecvCompletion:
                        // process the server's returned status
                        if (completedTransferBytes != c_completionMessageSize)
                        {
                            PRINT_DEBUG_INFO(
                                L"\t\tctsIOPatternState::CompletedTask (ClientRecvCompletion) : ErrorIOFailed (Server didn't return a completion - returned %u bytes)\n",
                                completedTransferBytes);
                            m_internalState = InternalPatternState::ErrorIoFailed;
                            return ctsIoPatternError::TooFewBytes;
                        }
                        if (memcmp(completedTask.m_buffer, c_completionMessage, c_completionMessageSize) != 0)
                        {
                            PRINT_DEBUG_INFO(
                                L"\t\tctsIOPatternState::CompletedTask (ClientRecvCompletion) : ErrorIOFailed (Server didn't return a correct completion message - expected to return DONE but it returned the 4 chars at %p)\n",
                                completedTask.m_buffer);
                            m_internalState = InternalPatternState::ErrorIoFailed;
                            return ctsIoPatternError::TooFewBytes;
                        }

                        if (ctsConfig::TcpShutdownType::GracefulShutdown == ctsConfig::g_configSettings->TcpShutdown)
                        {
                            PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (ClientRecvCompletion) : GracefulShutdown\n");
                            m_internalState = InternalPatternState::GracefulShutdown;
                            m_pendedState = false;
                        }
                        else
                        {
                            PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (ClientRecvCompletion) : HardShutdown\n");
                            m_internalState = InternalPatternState::HardShutdown;
                            m_pendedState = false;
                        }
                        break;

                    case InternalPatternState::GracefulShutdown:
                        PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (GracefulShutdown) : RequestFIN\n");
                        m_internalState = InternalPatternState::RequestFin;
                        m_pendedState = false;
                        break;

                    case InternalPatternState::RequestFin:
                        if (completedTransferBytes != 0)
                        {
                            PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (RequestFIN) : ErrorIOFailed (TooManyBytes)\n");
                            m_internalState = InternalPatternState::ErrorIoFailed;
                            return ctsIoPatternError::TooManyBytes;
                        }

                        PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (RequestFIN) : CompletedTransfer\n");
                        m_internalState = InternalPatternState::CompletedTransfer;
                        return ctsIoPatternError::SuccessfullyCompleted;

                    case InternalPatternState::HardShutdown:
                        PRINT_DEBUG_INFO(L"\t\tctsIOPatternState::CompletedTask (HardShutdown) : CompletedTransfer\n");
                        m_internalState = InternalPatternState::CompletedTransfer;
                        return ctsIoPatternError::SuccessfullyCompleted;

                    default:
                        FAIL_FAST_MSG(
                            "ctsIOPatternState::CompletedTask - invalid m_internalState (%d): dt %p ctsTraffic!ctsTraffic::ctsIOPatternState, dt %p ctsTraffic!ctstraffic::ctsIOTask",
                            m_internalState, this, &completedTask);
                }
            }
        }
    }
    else if (alreadyTransferred > m_maxTransfer)
    {
        PRINT_DEBUG_INFO(
            L"\t\tctsIOPatternState::CompletedTask : ErrorIOFailed (TooManyBytes) [transferred %llu, expected transfer %llu]\n",
            alreadyTransferred,
            m_maxTransfer);

        m_internalState = InternalPatternState::ErrorIoFailed;
        return ctsIoPatternError::TooManyBytes;
    }

    return ctsIoPatternError::NoError;
}