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;
}