#define _CRT_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
#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()
{
}
~TestConnection()
{
}
static const size_t NSOCK = 60;
protected:
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);
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;
}
}
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);
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()
{
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 at " << m_accepted.size()
<< "/" << NSOCK << ": " << srt_getlasterror_str() << endl;
break;
}
m_accepted.push_back(acp);
}
m_accept_exit = true;
cerr << "[T] Closing those accepted ones\n";
for (auto s: m_accepted)
{
srt_close(s);
}
cerr << "[T] End Accept Loop\n";
}
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];
volatile bool m_accept_exit = false;
};
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(); });
cout << "Opening " << NSOCK << " connections\n";
for (size_t i = 0; i < NSOCK; i++)
{
srt_socket_list[i] = srt_create_socket();
int conntimeo = 60;
srt_setsockflag(srt_socket_list[i], SRTO_CONNTIMEO, &conntimeo, sizeof conntimeo);
ASSERT_NE(srt_connect(srt_socket_list[i], psa, sizeof lsa), SRT_ERROR);
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);
}
}
cout << "Sending finished, closing caller sockets\n";
for (size_t i = 0; i < NSOCK; i++)
{
EXPECT_EQ(srt_close(srt_socket_list[i]), SRT_SUCCESS);
}
cout << "Closing server socket\n";
EXPECT_EQ(m_accept_exit, false);
EXPECT_EQ(srt_close(m_server_sock), 0);
ex.wait();
}