Skip to content

Commit

Permalink
[tests] Added a fast-connect-and-close unit test (#1323)
Browse files Browse the repository at this point in the history
* Added a fast-connect-and-close unit test
* Set connection timeout to 60s to prevent connection timeout failures
* Some fixes for Windows. Added more info to track down test failures
* Limited number of connections to 200
  • Loading branch information
ethouris authored Jun 24, 2020
1 parent 742e2f1 commit a29ce3b
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 0 deletions.
1 change: 1 addition & 0 deletions test/filelist.maf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
SOURCES
test_buffer.cpp
test_connection_timeout.cpp
test_many_connections.cpp
test_cryspr.cpp
test_enforced_encryption.cpp
test_epoll.cpp
Expand Down
177 changes: 177 additions & 0 deletions test/test_many_connections.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#define _CRT_RAND_S // For Windows, rand_s

#include <gtest/gtest.h>
#include <chrono>
#include <future>

#ifdef _WIN32
#include <stdlib.h>
#define rand_r rand_s
#define INC_SRT_WIN_WINTIME // exclude gettimeofday from srt headers
#else
typedef int SOCKET;
#define INVALID_SOCKET ((SOCKET)-1)
#define closesocket close
#endif

#include"platform_sys.h"
#include "srt.h"
#include "netinet_any.h"
#include "api.h"

using namespace std;


class TestConnection
: public ::testing::Test
{
protected:
TestConnection()
{
// initialization code here
}

~TestConnection()
{
// cleanup any pending stuff, but no exceptions allowed
}

// It should be as much as possible, but how many sockets can
// be withstood, depends on the platform. Currently used CI test
// servers seem not to withstand more than 240.
static const size_t NSOCK = 200;

protected:
// SetUp() is run immediately before a test starts.
void SetUp() override
{
ASSERT_EQ(srt_startup(), 0);

m_sa.sin_family = AF_INET;
m_sa.sin_addr.s_addr = INADDR_ANY;
m_udp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ASSERT_NE(m_udp_sock, -1);

// Find unused a port not used by any other service.
// Otherwise srt_connect may actually connect.
int bind_res = -1;
const sockaddr* psa = reinterpret_cast<const sockaddr*>(&m_sa);
for (int port = 5000; port <= 5555; ++port)
{
m_sa.sin_port = htons(port);
bind_res = ::bind(m_udp_sock, psa, sizeof m_sa);
if (bind_res >= 0)
{
cerr << "Running test on port " << port << "\n";
break;
}
}

// Close the socket to free the port.
ASSERT_NE(closesocket(m_udp_sock), -1);
ASSERT_GE(bind_res, 0);
ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &m_sa.sin_addr), 1);

// Fill the buffer with random data
time_t now;
time(&now);
unsigned int randseed = now % 255;
srand(randseed);
for (int i = 0; i < SRT_LIVE_DEF_PLSIZE; ++i)
buf[i] = rand_r(&randseed) % 255;

m_server_sock = srt_create_socket();

ASSERT_NE(srt_bind(m_server_sock, psa, sizeof m_sa), -1);
ASSERT_NE(srt_listen(m_server_sock, NSOCK), -1);
}

void TearDown() override
{
srt_cleanup();
}

void AcceptLoop()
{
//cerr << "[T] Accepting connections\n";
for (;;)
{
sockaddr_any addr;
int len = sizeof addr;
int acp = srt_accept(m_server_sock, addr.get(), &len);
if (acp == -1)
{
cerr << "[T] Accept error: " << srt_getlasterror_str();
break;
}
//cerr << "[T] Got new acp @" << acp << endl;
m_accepted.push_back(acp);
}

for (auto s: m_accepted)
{
srt_close(s);
}
}

protected:
SOCKET m_udp_sock = INVALID_SOCKET;
sockaddr_in m_sa = sockaddr_in();
SRTSOCKET m_server_sock = SRT_INVALID_SOCK;
vector<SRTSOCKET> m_accepted;
char buf[SRT_LIVE_DEF_PLSIZE];
SRTSOCKET srt_socket_list[NSOCK];
};



TEST_F(TestConnection, Multiple)
{
size_t size = SRT_LIVE_DEF_PLSIZE;

sockaddr_in lsa = m_sa;

const sockaddr* psa = reinterpret_cast<const sockaddr*>(&lsa);

auto ex = std::async([this] { return AcceptLoop(); });

for (size_t i = 0; i < NSOCK; i++)
{
srt_socket_list[i] = srt_create_socket();

// Give it 60s timeout, many platforms fail to process
// so many connections in a short time.
int conntimeo = 60;
srt_setsockflag(srt_socket_list[i], SRTO_CONNTIMEO, &conntimeo, sizeof conntimeo);

cout << "Connecting #" << i << " to " << SockaddrToString(sockaddr_any(psa)) << "...\n";

//cerr << "Connecting to: " << SockaddrToString(sockaddr_any(psa)) << endl;
ASSERT_NE(srt_connect(srt_socket_list[i], psa, sizeof lsa), SRT_ERROR);

// Set now async sending so that sending isn't blocked
int no = 0;
ASSERT_NE(srt_setsockflag(srt_socket_list[i], SRTO_SNDSYN, &no, sizeof no), -1);
}

for (size_t j = 1; j <= 100; j++)
{
for (size_t i = 0; i < NSOCK; i++)
{
EXPECT_GT(srt_send(srt_socket_list[i], buf, size), 0);
}
}

for (size_t i = 0; i < NSOCK; i++)
{
EXPECT_EQ(srt_close(srt_socket_list[i]), SRT_SUCCESS);
}

// Close server socket to break the accept loop
EXPECT_EQ(srt_close(m_server_sock), 0);

ex.wait();
}



0 comments on commit a29ce3b

Please sign in to comment.