Skip to content

Commit 676e0c9

Browse files
committed
Add "test_connection send_buffer_full"
1 parent 4fbfe83 commit 676e0c9

1 file changed

Lines changed: 94 additions & 2 deletions

File tree

tests/test_connection.cpp

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,97 @@ void Test_netloopback_throughput()
13501350
SteamNetworkingSockets()->CloseConnection( hClient, 0, nullptr, false );
13511351
}
13521352

1353+
void Test_send_buffer_full()
1354+
{
1355+
TEST_Printf( "***************************************************\n" );
1356+
TEST_Printf( "Test: SendMessages batch stop and retry on buffer full\n" );
1357+
TEST_Printf( "***************************************************\n" );
1358+
1359+
// Network loopback so we get real rate limiting
1360+
HSteamNetConnection hSender, hRecver;
1361+
assert( SteamNetworkingSockets()->CreateSocketPair( &hSender, &hRecver, true, nullptr, nullptr ) );
1362+
SteamNetworkingSockets()->SetConnectionName( hSender, "sender" );
1363+
SteamNetworkingSockets()->SetConnectionName( hRecver, "recver" );
1364+
1365+
// Low send rate so the buffer stays full long enough to observe
1366+
const int k_nSendRate = 64 * 1024;
1367+
SteamNetworkingUtils()->SetConnectionConfigValueInt32( hSender, k_ESteamNetworkingConfig_SendRateMin, k_nSendRate );
1368+
SteamNetworkingUtils()->SetConnectionConfigValueInt32( hSender, k_ESteamNetworkingConfig_SendRateMax, k_nSendRate );
1369+
1370+
// Buffer fits one 100K message but not two, so msg[1] overflows and msg[2] is never attempted
1371+
const int k_cbMsg = 100 * 1024;
1372+
const int k_nSendBuffer = 160 * 1024;
1373+
SteamNetworkingUtils()->SetConnectionConfigValueInt32( hSender, k_ESteamNetworkingConfig_SendBufferSize, k_nSendBuffer );
1374+
1375+
// Prepare three reliable messages
1376+
SteamNetworkingMessage_t *pMessages[3];
1377+
for ( int i = 0; i < 3; ++i )
1378+
{
1379+
pMessages[i] = SteamNetworkingUtils()->AllocateMessage( k_cbMsg );
1380+
pMessages[i]->m_conn = hSender;
1381+
pMessages[i]->m_nFlags = k_nSteamNetworkingSend_Reliable;
1382+
}
1383+
1384+
// Send all three at once. Pass bDeleteFailedMessages=false so the library
1385+
// leaves failed/not-attempted message pointers in place for retry.
1386+
int64 results[3] = {};
1387+
SteamNetworkingSockets()->SendMessages( 3, pMessages, results, /*bDeleteFailedMessages=*/false );
1388+
1389+
// First message fits in the 160K buffer: should succeed
1390+
assert( results[0] > 0 );
1391+
assert( pMessages[0] == nullptr ); // library took ownership
1392+
1393+
// Second message overflows the buffer: should fail
1394+
assert( results[1] == -k_EResultLimitExceeded );
1395+
assert( pMessages[1] != nullptr ); // we still own it; can retry
1396+
1397+
// Third message was never attempted because the second failed
1398+
assert( results[2] == 0 );
1399+
assert( pMessages[2] != nullptr ); // we still own it; can retry
1400+
1401+
TEST_Printf( "Initial send: msg[0]=#%lld succeeded, msg[1]=LimitExceeded, msg[2]=not attempted.\n", results[0] );
1402+
1403+
// Retry the two remaining messages one at a time. The buffer only holds one
1404+
// 100K message, so we must wait for space before each retry.
1405+
SteamNetworkingMessage_t *pRetry[2] = { pMessages[1], pMessages[2] };
1406+
for ( int i = 0; i < 2; ++i )
1407+
{
1408+
TEST_Printf( "Waiting for buffer space (retry %d)...\n", i );
1409+
SteamNetworkingMicroseconds usecDeadline = SteamNetworkingUtils()->GetLocalTimestamp() + 10 * 1000000LL;
1410+
for (;;)
1411+
{
1412+
TEST_PumpCallbacks();
1413+
1414+
// Keep the receiver drained so the connection stays healthy
1415+
SteamNetworkingMessage_t *pRecvMsgs[16];
1416+
for (;;)
1417+
{
1418+
int nRecv = SteamNetworkingSockets()->ReceiveMessagesOnConnection( hRecver, pRecvMsgs, 16 );
1419+
if ( nRecv <= 0 ) break;
1420+
for ( int j = 0; j < nRecv; ++j )
1421+
pRecvMsgs[j]->Release();
1422+
if ( nRecv < 16 ) break;
1423+
}
1424+
1425+
SteamNetConnectionRealTimeStatus_t status;
1426+
assert( k_EResultOK == SteamNetworkingSockets()->GetConnectionRealTimeStatus( hSender, &status, 0, nullptr ) );
1427+
if ( status.m_cbPendingReliable + k_cbMsg < k_nSendBuffer )
1428+
break;
1429+
1430+
assert( SteamNetworkingUtils()->GetLocalTimestamp() < usecDeadline );
1431+
}
1432+
1433+
int64 retryResult = 0;
1434+
SteamNetworkingSockets()->SendMessages( 1, &pRetry[i], &retryResult, /*bDeleteFailedMessages=*/false );
1435+
assert( retryResult > 0 );
1436+
assert( pRetry[i] == nullptr );
1437+
TEST_Printf( "Retry %d succeeded: queued as msg #%lld.\n", i, retryResult );
1438+
}
1439+
1440+
SteamNetworkingSockets()->CloseConnection( hSender, 0, nullptr, false );
1441+
SteamNetworkingSockets()->CloseConnection( hRecver, 0, nullptr, false );
1442+
}
1443+
13531444
int main( int argc, const char **argv )
13541445
{
13551446
typedef void (*FnTest)(void);
@@ -1367,15 +1458,16 @@ int main( int argc, const char **argv )
13671458
TEST(netloopback_throughput),
13681459
TEST(lane_quick_queueanddrain),
13691460
TEST(lane_quick_priority_and_background),
1370-
TEST(pipe)
1461+
TEST(pipe),
1462+
TEST(send_buffer_full)
13711463
};
13721464

13731465
struct Suite_t {
13741466
const char *m_pszName;
13751467
std::vector< Test_t > m_vecTests;
13761468
};
13771469
static const Suite_t test_suites[] = {
1378-
{ "suite-quick", { TEST(identity), TEST(quick), TEST(lane_quick_queueanddrain), TEST(netloopback_throughput), TEST(lane_quick_priority_and_background), TEST(pipe) } }
1470+
{ "suite-quick", { TEST(identity), TEST(quick), TEST(lane_quick_queueanddrain), TEST(netloopback_throughput), TEST(lane_quick_priority_and_background), TEST(pipe), TEST(send_buffer_full) } }
13791471
};
13801472

13811473
if ( argc < 2 )

0 commit comments

Comments
 (0)