1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
#include "gtest/gtest.h"
#include "test_env.h"
#include <thread>
#include "srt.h"
class TestMuxer
: public srt::Test
{
protected:
TestMuxer()
{
// initialization code here
}
~TestMuxer()
{
// cleanup any pending stuff, but no exceptions allowed
}
protected:
// SetUp() is run immediately before a test starts.
void setup() override
{
m_caller_sock = srt_create_socket();
ASSERT_NE(m_caller_sock, SRT_ERROR);
m_server_pollid = srt_epoll_create();
ASSERT_NE(SRT_ERROR, m_server_pollid);
m_client_pollid = srt_epoll_create();
ASSERT_NE(SRT_ERROR, m_client_pollid);
int yes = 1;
int no = 0;
ASSERT_NE(srt_setsockopt(m_caller_sock, 0, SRTO_SNDSYN, &no, sizeof no), SRT_ERROR); // for async connect
ASSERT_NE(srt_setsockflag(m_caller_sock, SRTO_SENDER, &yes, sizeof yes), SRT_ERROR);
ASSERT_NE(srt_setsockopt(m_caller_sock, 0, SRTO_TSBPDMODE, &yes, sizeof yes), SRT_ERROR);
int epoll_out = SRT_EPOLL_OUT;
srt_epoll_add_usock(m_client_pollid, m_caller_sock, &epoll_out);
}
void teardown() override
{
// Code here will be called just after the test completes.
// OK to throw exceptions from here if needed.
srt_epoll_release(m_client_pollid);
srt_epoll_release(m_server_pollid);
srt_close(m_listener_sock_ipv4);
srt_close(m_listener_sock_ipv6);
}
public:
void ClientThread()
{
sockaddr_in sa;
memset(&sa, 0, sizeof sa);
sa.sin_family = AF_INET;
sa.sin_port = htons(m_listen_port);
ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr), 1);
ASSERT_NE(srt_connect(m_caller_sock, (sockaddr*)&sa, sizeof sa), SRT_ERROR);
// Socket readiness for connection is checked by polling on WRITE allowed sockets.
{
int rlen = 2;
SRTSOCKET read[2];
int wlen = 2;
SRTSOCKET write[2];
ASSERT_NE(srt_epoll_wait(m_client_pollid, read, &rlen,
write, &wlen,
-1, // -1 is set for debuging purpose.
// in case of production we need to set appropriate value
0, 0, 0, 0), SRT_ERROR);
ASSERT_EQ(rlen, 0); // get exactly one write event without reads
ASSERT_EQ(wlen, 1); // get exactly one write event without reads
ASSERT_EQ(write[0], m_caller_sock); // for our client socket
}
char buffer[1316] = {1, 2, 3, 4};
ASSERT_NE(srt_sendmsg(m_caller_sock, buffer, sizeof buffer,
-1, // infinit ttl
true // in order must be set to true
), SRT_ERROR);
}
protected:
SRTSOCKET m_caller_sock;
SRTSOCKET m_listener_sock_ipv4;
SRTSOCKET m_listener_sock_ipv6;
int m_client_pollid = SRT_ERROR;
int m_server_pollid = SRT_ERROR;
const int m_listen_port = 4200;
};
TEST_F(TestMuxer, IPv4_and_IPv6)
{
SRTST_REQUIRES(IPv6);
int yes = 1;
int no = 0;
// 1. Create IPv4 listening socket
m_listener_sock_ipv4 = srt_create_socket();
ASSERT_NE(m_listener_sock_ipv4, SRT_ERROR);
ASSERT_NE(srt_setsockopt(m_listener_sock_ipv4, 0, SRTO_RCVSYN, &no, sizeof no), SRT_ERROR); // for async connect
ASSERT_NE(srt_setsockopt(m_listener_sock_ipv4, 0, SRTO_TSBPDMODE, &yes, sizeof yes), SRT_ERROR);
// 2. Add the IPv4 socket to epoll
int epoll_in = SRT_EPOLL_IN;
srt_epoll_add_usock(m_server_pollid, m_listener_sock_ipv4, &epoll_in);
// 3. Bind to IPv4 address.
sockaddr_in sa;
memset(&sa, 0, sizeof sa);
sa.sin_family = AF_INET;
sa.sin_port = htons(m_listen_port);
ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr), 1);
ASSERT_NE(srt_bind(m_listener_sock_ipv4, (sockaddr*)&sa, sizeof sa), SRT_ERROR);
ASSERT_NE(srt_listen(m_listener_sock_ipv4, SOMAXCONN), SRT_ERROR);
// 4. Create IPv6 socket bound to the same port as IPv4 socket
m_listener_sock_ipv6 = srt_create_socket();
ASSERT_NE(m_listener_sock_ipv6, SRT_ERROR);
sockaddr_in6 sa_v6;
memset(&sa_v6, 0, sizeof sa_v6);
sa_v6.sin6_family = AF_INET6;
sa_v6.sin6_port = htons(m_listen_port);
ASSERT_EQ(inet_pton(AF_INET6, "::1", &sa_v6.sin6_addr), 1);
// Set the IPv6only flag for the socket that should be bound to the same port
// as another socket binding to IPv4 address, otherwise the binding may fail,
// depending on the current value of IPV6ONLY option.
ASSERT_EQ(srt_setsockflag(m_listener_sock_ipv6, SRTO_IPV6ONLY, &yes, sizeof yes), 0);
ASSERT_NE(srt_bind(m_listener_sock_ipv6, (sockaddr*)&sa_v6, sizeof(sa_v6)), SRT_ERROR);
std::thread client(&TestMuxer::ClientThread, this);
{ // wait for connection from client
int rlen = 2;
SRTSOCKET read[2];
int wlen = 2;
SRTSOCKET write[2];
ASSERT_NE(srt_epoll_wait(m_server_pollid,
read, &rlen,
write, &wlen,
-1, // -1 is set for debuging purpose.
// in case of production we need to set appropriate value
0, 0, 0, 0), SRT_ERROR );
ASSERT_EQ(rlen, 1); // get exactly one read event without writes
ASSERT_EQ(read[0], m_listener_sock_ipv4) << "Read event on wrong socket";
}
sockaddr_storage scl;
int sclen = sizeof scl;
SRTSOCKET accepted_sock = srt_accept(m_listener_sock_ipv4, (sockaddr*)&scl, &sclen);
ASSERT_NE(accepted_sock, SRT_INVALID_SOCK);
srt_epoll_add_usock(m_server_pollid, accepted_sock, &epoll_in); // wait for input
char buffer[1316];
{ // wait for 1316 packet from client
int rlen = 2;
SRTSOCKET read[2];
int wlen = 2;
SRTSOCKET write[2];
ASSERT_NE(srt_epoll_wait(m_server_pollid,
read, &rlen,
write, &wlen,
-1, // -1 is set for debuging purpose.
// in case of production we need to set appropriate value
0, 0, 0, 0), SRT_ERROR );
ASSERT_EQ(rlen, 1); // get exactly one read event without writes
//ASSERT_EQ(wlen, 0); // get exactly one read event without writes
ASSERT_EQ(read[0], accepted_sock); // read event is for bind socket
}
char pattern[4] = {1, 2, 3, 4};
ASSERT_EQ(srt_recvmsg(accepted_sock, buffer, sizeof buffer), 1316);
ASSERT_EQ(memcmp(pattern, buffer, 4), 0);
srt_close(accepted_sock);
client.join();
}
|