1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-15 04:42:04 +00:00

Merge branch '3.0release' into develop

This commit is contained in:
winlin 2020-01-05 22:19:56 +08:00
commit 048742f468
20 changed files with 655 additions and 88 deletions

View file

@ -148,6 +148,10 @@ For previous versions, please read:
## V3 changes
* v3.0, 2020-01-05, Always use string instance to avoid crash risk. 3.0.95
* v3.0, 2020-01-05, For [#460][bug #460], fix ipv6 hostport parsing bug. 3.0.94
* v3.0, 2020-01-05, For [#460][bug #460], fix ipv6 intranet address filter bug. 3.0.93
* v3.0, 2020-01-05, For [#1543][bug #1543], use getpeername to retrieve client ip. 3.0.92
* v3.0, 2020-01-02, For [#1042][bug #1042], improve test coverage for config. 3.0.91
* v3.0, 2019-12-30, Fix mp4 security issue, check buffer when required size is variable.
* <strong>v3.0, 2019-12-29, [3.0 alpha7(3.0.90)][r3.0a7] released. 116356 lines.</strong>
@ -1583,6 +1587,7 @@ Winlin
[bug #1105]: https://github.com/ossrs/srs/issues/1105
[bug #1544]: https://github.com/ossrs/srs/issues/1544
[bug #1255]: https://github.com/ossrs/srs/issues/1255
[bug #1543]: https://github.com/ossrs/srs/issues/1543
[bug #xxxxxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxxxxx
[bug #1111]: https://github.com/ossrs/srs/issues/1111

View file

@ -296,7 +296,7 @@ bool srs_config_apply_filter(SrsConfDirective* dvr_apply, SrsRequest* req)
return false;
}
string srs_config_bool2switch(const string& sbool)
string srs_config_bool2switch(string sbool)
{
return sbool == "true"? "on":"off";
}

View file

@ -123,7 +123,7 @@ extern bool srs_stream_caster_is_flv(std::string caster);
extern bool srs_config_apply_filter(SrsConfDirective* dvr_apply, SrsRequest* req);
// Convert bool in str to on/off
extern std::string srs_config_bool2switch(const std::string& sbool);
extern std::string srs_config_bool2switch(std::string sbool);
// Parse loaded vhost directives to compatible mode.
// For exmaple, SRS1/2 use the follow refer style:

View file

@ -81,7 +81,7 @@ int SrsDummyCoroutine::cid()
_ST_THREAD_CREATE_PFN _pfn_st_thread_create = (_ST_THREAD_CREATE_PFN)st_thread_create;
SrsSTCoroutine::SrsSTCoroutine(const string& n, ISrsCoroutineHandler* h, int cid)
SrsSTCoroutine::SrsSTCoroutine(string n, ISrsCoroutineHandler* h, int cid)
{
name = n;
handler = h;

View file

@ -132,7 +132,7 @@ private:
public:
// Create a thread with name n and handler h.
// @remark User can specify a cid for thread to use, or we will allocate a new one.
SrsSTCoroutine(const std::string& n, ISrsCoroutineHandler* h, int cid = 0);
SrsSTCoroutine(std::string n, ISrsCoroutineHandler* h, int cid = 0);
virtual ~SrsSTCoroutine();
public:
// Start the thread.

View file

@ -1142,7 +1142,7 @@ string srs_get_peer_ip(int fd)
// discovery client information
sockaddr_storage addr;
socklen_t addrlen = sizeof(addr);
if (getsockname(fd, (sockaddr*)&addr, &addrlen) == -1) {
if (getpeername(fd, (sockaddr*)&addr, &addrlen) == -1) {
return "";
}
@ -1157,7 +1157,7 @@ string srs_get_peer_ip(int fd)
return std::string(saddr);
}
bool srs_is_boolean(const string& str)
bool srs_is_boolean(string str)
{
return str == "true" || str == "false";
}

View file

@ -644,7 +644,7 @@ extern std::string srs_get_peer_ip(int fd);
// is_bool("true") == true
// is_bool("false") == true
// otherwise, false.
extern bool srs_is_boolean(const std::string& str);
extern bool srs_is_boolean(std::string str);
// Dump summaries for /api/v1/summaries.
extern void srs_api_dump_summaries(SrsJsonObject* obj);

View file

@ -27,7 +27,7 @@
// The version config.
#define VERSION_MAJOR 3
#define VERSION_MINOR 0
#define VERSION_REVISION 91
#define VERSION_REVISION 95
// The macros generated by configure script.
#include <srs_auto_headers.hpp>

View file

@ -110,12 +110,12 @@ void srs_mp4_delimiter_newline(stringstream& ss, SrsMp4DumpContext dc)
srs_mp4_padding(ss, dc);
}
int srs_mp4_string_length(const string& v)
int srs_mp4_string_length(string v)
{
return (int)v.length()+1;
}
void srs_mp4_string_write(SrsBuffer* buf, const string& v)
void srs_mp4_string_write(SrsBuffer* buf, string v)
{
if (!v.empty()) {
buf->write_bytes((char*)v.data(), (int)v.length());

View file

@ -2169,7 +2169,7 @@ std::stringstream& srs_dumps_array(std::vector<T>&arr, std::stringstream& ss, Sr
pfn(elem, ss, dc);
if (i < limit - 1) {
if ((int)i < limit - 1) {
delimiter(ss, dc);
}
}
@ -2192,7 +2192,7 @@ std::stringstream& srs_dumps_array(T* arr, int size, std::stringstream& ss, SrsM
pfn(elem, ss, dc);
if (i < limit - 1) {
if ((int)i < limit - 1) {
delimiter(ss, dc);
}
}

View file

@ -170,44 +170,60 @@ string srs_dns_resolve(string host, int& family)
{
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_family = family;
addrinfo* r = NULL;
SrsAutoFree(addrinfo, r);
if(getaddrinfo(host.c_str(), NULL, NULL, &r)) {
if(getaddrinfo(host.c_str(), NULL, &hints, &r)) {
return "";
}
char saddr[64];
char* h = (char*)saddr;
socklen_t nbh = sizeof(saddr);
const int r0 = getnameinfo(r->ai_addr, r->ai_addrlen, h, nbh, NULL, 0, NI_NUMERICHOST);
if(!r0) {
family = r->ai_family;
return string(saddr);
char shost[64];
memset(shost, 0, sizeof(shost));
if (getnameinfo(r->ai_addr, r->ai_addrlen, shost, sizeof(shost), NULL, 0, NI_NUMERICHOST)) {
return "";
}
return "";
family = r->ai_family;
return string(shost);
}
void srs_parse_hostport(const string& hostport, string& host, int& port)
void srs_parse_hostport(string hostport, string& host, int& port)
{
const size_t pos = hostport.rfind(":"); // Look for ":" from the end, to work with IPv6.
if (pos != std::string::npos) {
const string p = hostport.substr(pos + 1);
if ((pos >= 1) &&
(hostport[0] == '[') &&
(hostport[pos - 1] == ']')) {
// Handle IPv6 in RFC 2732 format, e.g. [3ffe:dead:beef::1]:1935
host = hostport.substr(1, pos - 2);
} else {
// Handle IP address
host = hostport.substr(0, pos);
}
port = ::atoi(p.c_str());
} else {
// No host or port.
if (hostport.empty()) {
return;
}
size_t pos = string::npos;
// Host only for ipv4.
if ((pos = hostport.rfind(":")) == string::npos) {
host = hostport;
return;
}
// For ipv4(only one colon), host:port.
if (hostport.find(":") == pos) {
host = hostport.substr(0, pos);
string p = hostport.substr(pos + 1);
if (!p.empty()) {
port = ::atoi(p.c_str());
}
return;
}
// Host only for ipv6.
if (hostport.at(0) != '[' || (pos = hostport.rfind("]:")) == string::npos) {
host = hostport;
return;
}
// For ipv6, [host]:port.
host = hostport.substr(1, pos - 1);
string p = hostport.substr(pos + 2);
if (!p.empty()) {
port = ::atoi(p.c_str());
}
}

View file

@ -56,7 +56,7 @@ extern std::string srs_dns_resolve(std::string host, int& family);
// Split the host:port to host and port.
// @remark the hostport format in <host[:port]>, where port is optional.
extern void srs_parse_hostport(const std::string& hostport, std::string& host, int& port);
extern void srs_parse_hostport(std::string hostport, std::string& host, int& port);
// Parse the endpoint to ip and port.
// @remark The hostport format in <[ip:]port>, where ip is default to "0.0.0.0".

View file

@ -1731,7 +1731,7 @@ SrsJsonAny* srs_json_parse_tree(json_value* node)
}
}
SrsJsonAny* SrsJsonAny::loads(const string& str)
SrsJsonAny* SrsJsonAny::loads(string str)
{
if (str.empty()) {
return NULL;

View file

@ -107,7 +107,7 @@ public:
public:
// Read json tree from string.
// @return json object. NULL if error.
static SrsJsonAny* loads(const std::string& str);
static SrsJsonAny* loads(std::string str);
};
class SrsJsonObject : public SrsJsonAny

View file

@ -157,7 +157,7 @@ srs_error_t srs_tcp_connect(string server, int port, srs_utime_t tm, srs_netfd_t
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
addrinfo* r = NULL;
@ -187,6 +187,43 @@ srs_error_t srs_tcp_connect(string server, int port, srs_utime_t tm, srs_netfd_t
return srs_success;
}
srs_error_t do_srs_tcp_listen(int fd, addrinfo* r, srs_netfd_t* pfd)
{
srs_error_t err = srs_success;
// Detect alive for TCP connection.
// @see https://github.com/ossrs/srs/issues/1044
if ((err = srs_fd_keepalive(fd)) != srs_success) {
return srs_error_wrap(err, "set keepalive");
}
if ((err = srs_fd_closeexec(fd)) != srs_success) {
return srs_error_wrap(err, "set closeexec");
}
if ((err = srs_fd_reuseaddr(fd)) != srs_success) {
return srs_error_wrap(err, "set reuseaddr");
}
if ((err = srs_fd_reuseport(fd)) != srs_success) {
return srs_error_wrap(err, "set reuseport");
}
if (bind(fd, r->ai_addr, r->ai_addrlen) == -1) {
return srs_error_new(ERROR_SOCKET_BIND, "bind");
}
if (::listen(fd, SERVER_LISTEN_BACKLOG) == -1) {
return srs_error_new(ERROR_SOCKET_LISTEN, "listen");
}
if ((*pfd = srs_netfd_open_socket(fd)) == NULL){
return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open");
}
return err;
}
srs_error_t srs_tcp_listen(std::string ip, int port, srs_netfd_t* pfd)
{
srs_error_t err = srs_success;
@ -213,41 +250,36 @@ srs_error_t srs_tcp_listen(std::string ip, int port, srs_netfd_t* pfd)
r->ai_family, r->ai_socktype, r->ai_protocol);
}
// Detect alive for TCP connection.
// @see https://github.com/ossrs/srs/issues/1044
if ((err = srs_fd_keepalive(fd)) != srs_success) {
if ((err = do_srs_tcp_listen(fd, r, pfd)) != srs_success) {
::close(fd);
return srs_error_wrap(err, "set keepalive fd=%d", fd);
return srs_error_wrap(err, "fd=%d", fd);
}
return err;
}
srs_error_t do_srs_udp_listen(int fd, addrinfo* r, srs_netfd_t* pfd)
{
srs_error_t err = srs_success;
if ((err = srs_fd_closeexec(fd)) != srs_success) {
::close(fd);
return srs_error_wrap(err, "set closeexec fd=%d", fd);
return srs_error_wrap(err, "set closeexec");
}
if ((err = srs_fd_reuseaddr(fd)) != srs_success) {
::close(fd);
return srs_error_wrap(err, "set reuseaddr fd=%d", fd);
return srs_error_wrap(err, "set reuseaddr");
}
if ((err = srs_fd_reuseport(fd)) != srs_success) {
::close(fd);
return srs_error_wrap(err, "set reuseport fd=%d", fd);
return srs_error_wrap(err, "set reuseport");
}
if (bind(fd, r->ai_addr, r->ai_addrlen) == -1) {
::close(fd);
return srs_error_new(ERROR_SOCKET_BIND, "bind fd=%d", fd);
}
if (::listen(fd, SERVER_LISTEN_BACKLOG) == -1) {
::close(fd);
return srs_error_new(ERROR_SOCKET_LISTEN, "listen fd=%d", fd);
return srs_error_new(ERROR_SOCKET_BIND, "bind");
}
if ((*pfd = srs_netfd_open_socket(fd)) == NULL){
::close(fd);
return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open fd=%d", fd);
return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open");
}
return err;
@ -279,29 +311,9 @@ srs_error_t srs_udp_listen(std::string ip, int port, srs_netfd_t* pfd)
r->ai_family, r->ai_socktype, r->ai_protocol);
}
if ((err = srs_fd_closeexec(fd)) != srs_success) {
if ((err = do_srs_udp_listen(fd, r, pfd)) != srs_success) {
::close(fd);
return srs_error_wrap(err, "set closeexec fd=%d", fd);
}
if ((err = srs_fd_reuseaddr(fd)) != srs_success) {
::close(fd);
return srs_error_wrap(err, "set reuseaddr fd=%d", fd);
}
if ((err = srs_fd_reuseport(fd)) != srs_success) {
::close(fd);
return srs_error_wrap(err, "set reuseport fd=%d", fd);
}
if (bind(fd, r->ai_addr, r->ai_addrlen) == -1) {
::close(fd);
return srs_error_new(ERROR_SOCKET_BIND, "bind fd=%d", fd);
}
if ((*pfd = srs_netfd_open_socket(fd)) == NULL){
::close(fd);
return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open fd=%d", fd);
return srs_error_wrap(err, "fd=%d", fd);
}
return err;

View file

@ -51,7 +51,7 @@ bool srs_string_is_rtmp(string url)
return srs_string_starts_with(url, "rtmp://");
}
bool srs_is_digit_number(const string& str)
bool srs_is_digit_number(string str)
{
if (str.empty()) {
return false;
@ -115,8 +115,28 @@ bool srs_net_device_is_internet(const sockaddr* addr)
}
} else if(addr->sa_family == AF_INET6) {
const sockaddr_in6* a6 = (const sockaddr_in6*)addr;
if ((IN6_IS_ADDR_LINKLOCAL(&a6->sin6_addr)) ||
(IN6_IS_ADDR_SITELOCAL(&a6->sin6_addr))) {
// IPv6 loopback is ::1
if (IN6_IS_ADDR_LOOPBACK(&a6->sin6_addr)) {
return false;
}
// IPv6 unspecified is ::
if (IN6_IS_ADDR_UNSPECIFIED(&a6->sin6_addr)) {
return false;
}
// From IPv4, you might know APIPA (Automatic Private IP Addressing) or AutoNet.
// Whenever automatic IP configuration through DHCP fails.
// The prefix of a site-local address is FE80::/10.
if (IN6_IS_ADDR_LINKLOCAL(&a6->sin6_addr)) {
return false;
}
// Site-local addresses are equivalent to private IP addresses in IPv4.
// The prefix of a site-local address is FEC0::/10.
// https://4sysops.com/archives/ipv6-tutorial-part-6-site-local-addresses-and-link-local-addresses/
if (IN6_IS_ADDR_SITELOCAL(&a6->sin6_addr)) {
return false;
}
}

View file

@ -48,7 +48,7 @@ extern bool srs_string_is_rtmp(std::string url);
// is_digit("10e3") === false
// is_digit("!1234567890") === false
// is_digit("") === false
extern bool srs_is_digit_number(const std::string& str);
extern bool srs_is_digit_number(std::string str);
// Get local ip, fill to @param ips
extern std::vector<std::string>& srs_get_local_ips();

View file

@ -4253,6 +4253,118 @@ VOID TEST(KernelUtilityTest, CoverTimeUtilityAll)
_srs_system_time_us_cache -= 300*1000 * 1000 + 1;
EXPECT_TRUE(srs_update_system_time() > 0);
if (true) {
string host = "127.0.0.1:1935";
int port = 0;
srs_parse_hostport(host, host, port);
EXPECT_EQ(1935, port);
EXPECT_STREQ("127.0.0.1", host.c_str());
}
if (true) {
string host;
int port = 8080;
srs_parse_hostport("::1", host, port);
EXPECT_EQ(8080, port);
EXPECT_STREQ("::1", host.c_str());
}
if (true) {
string host;
int port = 8080;
srs_parse_hostport("::", host, port);
EXPECT_EQ(8080, port);
EXPECT_STREQ("::", host.c_str());
}
if (true) {
string host;
int port = 0;
srs_parse_hostport("3ffe:dead:beef::1", host, port);
EXPECT_EQ(0, port);
EXPECT_STREQ("3ffe:dead:beef::1", host.c_str());
}
if (true) {
string host;
int port = 10;
srs_parse_hostport("2001:da8:6000:291:21f:d0ff:fed4:928c", host, port);
EXPECT_EQ(10, port);
EXPECT_STREQ("2001:da8:6000:291:21f:d0ff:fed4:928c", host.c_str());
}
if (true) {
string host;
int port = 0;
srs_parse_hostport("[2001:da8:6000:291:21f:d0ff:fed4:928c]:167", host, port);
EXPECT_EQ(167, port);
EXPECT_STREQ("2001:da8:6000:291:21f:d0ff:fed4:928c", host.c_str());
}
if (true) {
string host;
int port = 0;
srs_parse_hostport("[::A.B.C.D]:167", host, port);
EXPECT_EQ(167, port);
EXPECT_STREQ("::A.B.C.D", host.c_str());
}
if (true) {
string host;
int port = 0;
srs_parse_hostport("::A.B.C.D", host, port);
EXPECT_EQ(0, port);
EXPECT_STREQ("::A.B.C.D", host.c_str());
}
if (true) {
string host;
int port = 0;
srs_parse_hostport("[::FFFF:A.B.C.D]:167", host, port);
EXPECT_EQ(167, port);
EXPECT_STREQ("::FFFF:A.B.C.D", host.c_str());
}
if (true) {
string host;
int port = 0;
srs_parse_hostport("[ff00::]:167", host, port);
EXPECT_EQ(167, port);
EXPECT_STREQ("ff00::", host.c_str());
}
if (true) {
string host;
int port = 0;
srs_parse_hostport("[fe80::a00:27ff:fe84:be2%eth0]:167", host, port);
EXPECT_EQ(167, port);
EXPECT_STREQ("fe80::a00:27ff:fe84:be2%eth0", host.c_str());
}
if (true) {
string host;
int port = 0;
srs_parse_hostport("::FFFF:A.B.C.D", host, port);
EXPECT_EQ(0, port);
EXPECT_STREQ("::FFFF:A.B.C.D", host.c_str());
}
if (true) {
string host;
int port = 8080;
srs_parse_hostport("", host, port);
EXPECT_EQ(8080, port);
EXPECT_STREQ("", host.c_str());
}
if (true) {
string host;
int port = 8080;
srs_parse_hostport("3ffe:dead:beef::1", host, port);
EXPECT_EQ(8080, port);
EXPECT_STREQ("3ffe:dead:beef::1", host.c_str());
}
if (true) {
string host;

View file

@ -35,6 +35,9 @@ using namespace std;
#include <srs_core_autofree.hpp>
#include <srs_utest_protocol.hpp>
#include <srs_utest_http.hpp>
#include <srs_service_utility.hpp>
#include <sys/socket.h>
#include <netdb.h>
class MockSrsConnection : public ISrsConnection
{
@ -679,3 +682,400 @@ VOID TEST(TCPServerTest, MessageWritev)
}
}
VOID TEST(TCPServerTest, TCPListen)
{
srs_error_t err;
// Failed for invalid ip.
if (true) {
srs_netfd_t pfd = NULL;
HELPER_EXPECT_FAILED(srs_tcp_listen("10.0.0.abc", 1935, &pfd));
srs_close_stfd(pfd);
}
// If listen multiple times, should success for we already set the REUSEPORT.
if (true) {
srs_netfd_t pfd = NULL;
HELPER_ASSERT_SUCCESS(srs_tcp_listen("127.0.0.1", 1935, &pfd));
srs_netfd_t pfd2 = NULL;
srs_error_t err2 = srs_tcp_listen("127.0.0.1", 1935, &pfd2);
srs_close_stfd(pfd);
srs_close_stfd(pfd2);
HELPER_EXPECT_SUCCESS(err2);
}
// Typical listen.
if (true) {
srs_netfd_t pfd = NULL;
HELPER_ASSERT_SUCCESS(srs_tcp_listen("127.0.0.1", 1935, &pfd));
srs_close_stfd(pfd);
}
}
VOID TEST(TCPServerTest, UDPListen)
{
srs_error_t err;
// Failed for invalid ip.
if (true) {
srs_netfd_t pfd = NULL;
HELPER_EXPECT_FAILED(srs_udp_listen("10.0.0.abc", 1935, &pfd));
srs_close_stfd(pfd);
}
// If listen multiple times, should success for we already set the REUSEPORT.
if (true) {
srs_netfd_t pfd = NULL;
HELPER_ASSERT_SUCCESS(srs_udp_listen("127.0.0.1", 1935, &pfd));
srs_netfd_t pfd2 = NULL;
srs_error_t err2 = srs_udp_listen("127.0.0.1", 1935, &pfd2);
srs_close_stfd(pfd);
srs_close_stfd(pfd2);
HELPER_EXPECT_SUCCESS(err2);
}
// Typical listen.
if (true) {
srs_netfd_t pfd = NULL;
HELPER_ASSERT_SUCCESS(srs_udp_listen("127.0.0.1", 1935, &pfd));
srs_close_stfd(pfd);
}
}
class MockOnCycleThread : public ISrsCoroutineHandler
{
public:
SrsSTCoroutine trd;
srs_cond_t cond;
MockOnCycleThread() : trd("mock", this, 0) {
cond = srs_cond_new();
};
virtual ~MockOnCycleThread() {
srs_cond_destroy(cond);
}
virtual srs_error_t cycle() {
srs_error_t err = srs_success;
for (;;) {
srs_usleep(10 * SRS_UTIME_MILLISECONDS);
srs_cond_signal(cond);
// If no one waiting on the cond, directly return event signal more than one time.
// If someone waiting, signal them more than one time.
srs_cond_signal(cond);
if ((err = trd.pull()) != srs_success) {
return err;
}
}
return err;
}
};
VOID TEST(TCPServerTest, ThreadCondWait)
{
MockOnCycleThread trd;
trd.trd.start();
srs_usleep(20 * SRS_UTIME_MILLISECONDS);
srs_cond_wait(trd.cond);
trd.trd.stop();
}
class MockOnCycleThread2 : public ISrsCoroutineHandler
{
public:
SrsSTCoroutine trd;
srs_mutex_t lock;
MockOnCycleThread2() : trd("mock", this, 0) {
lock = srs_mutex_new();
};
virtual ~MockOnCycleThread2() {
srs_mutex_destroy(lock);
}
virtual srs_error_t cycle() {
srs_error_t err = srs_success;
for (;;) {
srs_mutex_lock(lock);
srs_usleep(10 * SRS_UTIME_MILLISECONDS);
srs_mutex_unlock(lock);
srs_error_t err = trd.pull();
if (err != srs_success) {
return err;
}
}
return err;
}
};
VOID TEST(TCPServerTest, ThreadMutexWait)
{
MockOnCycleThread2 trd;
trd.trd.start();
srs_usleep(20 * SRS_UTIME_MILLISECONDS);
srs_mutex_lock(trd.lock);
trd.trd.stop();
srs_mutex_unlock(trd.lock);
}
class MockOnCycleThread3 : public ISrsCoroutineHandler
{
public:
SrsSTCoroutine trd;
srs_netfd_t fd;
MockOnCycleThread3() : trd("mock", this, 0) {
};
virtual ~MockOnCycleThread3() {
trd.stop();
srs_close_stfd(fd);
}
virtual srs_error_t start(string ip, int port) {
srs_error_t err = srs_success;
if ((err = srs_tcp_listen(ip, port, &fd)) != srs_success) {
return err;
}
return trd.start();
}
virtual srs_error_t do_cycle(srs_netfd_t cfd) {
srs_error_t err = srs_success;
SrsStSocket skt;
if ((err = skt.initialize(cfd)) != srs_success) {
return err;
}
skt.set_recv_timeout(1 * SRS_UTIME_SECONDS);
skt.set_send_timeout(1 * SRS_UTIME_SECONDS);
while (true) {
if ((err = trd.pull()) != srs_success) {
return err;
}
char buf[5];
if ((err = skt.read_fully(buf, 5, NULL)) != srs_success) {
return err;
}
if ((err = skt.write(buf, 5, NULL)) != srs_success) {
return err;
}
}
return err;
}
virtual srs_error_t cycle() {
srs_error_t err = srs_success;
srs_netfd_t cfd = srs_accept(fd, NULL, NULL, SRS_UTIME_NO_TIMEOUT);
if (cfd == NULL) {
return err;
}
err = do_cycle(cfd);
srs_close_stfd(cfd);
srs_freep(err);
return err;
}
};
VOID TEST(TCPServerTest, TCPClientServer)
{
srs_error_t err;
MockOnCycleThread3 trd;
HELPER_ASSERT_SUCCESS(trd.start("127.0.0.1", 1935));
SrsTcpClient c("127.0.0.1", 1935, 1 * SRS_UTIME_SECONDS);
HELPER_ASSERT_SUCCESS(c.connect());
c.set_recv_timeout(1 * SRS_UTIME_SECONDS);
c.set_send_timeout(1 * SRS_UTIME_SECONDS);
if (true) {
HELPER_ASSERT_SUCCESS(c.write((void*)"Hello", 5, NULL));
char buf[6]; HELPER_ARRAY_INIT(buf, 6, 0);
HELPER_ASSERT_SUCCESS(c.read(buf, 5, NULL));
EXPECT_STREQ("Hello", buf);
}
if (true) {
HELPER_ASSERT_SUCCESS(c.write((void*)"Hello", 5, NULL));
char buf[6]; HELPER_ARRAY_INIT(buf, 6, 0);
HELPER_ASSERT_SUCCESS(c.read_fully(buf, 5, NULL));
EXPECT_STREQ("Hello", buf);
}
if (true) {
HELPER_ASSERT_SUCCESS(c.write((void*)"Hello", 5, NULL));
char buf[6]; HELPER_ARRAY_INIT(buf, 6, 0);
ASSERT_EQ(5, srs_read(c.stfd, buf, 5, 1*SRS_UTIME_SECONDS));
EXPECT_STREQ("Hello", buf);
}
}
VOID TEST(TCPServerTest, CoverUtility)
{
EXPECT_TRUE(srs_string_is_http("http://"));
EXPECT_TRUE(srs_string_is_http("https://"));
EXPECT_TRUE(srs_string_is_http("http://localhost"));
EXPECT_TRUE(srs_string_is_http("https://localhost"));
EXPECT_FALSE(srs_string_is_http("ftp://"));
EXPECT_FALSE(srs_string_is_http("ftps://"));
EXPECT_FALSE(srs_string_is_http("http:"));
EXPECT_FALSE(srs_string_is_http("https:"));
EXPECT_TRUE(srs_string_is_rtmp("rtmp://"));
EXPECT_TRUE(srs_string_is_rtmp("rtmp://localhost"));
EXPECT_FALSE(srs_string_is_rtmp("http://"));
EXPECT_FALSE(srs_string_is_rtmp("rtmp:"));
// ipv4 loopback
if (true) {
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
addrinfo* r = NULL;
SrsAutoFree(addrinfo, r);
ASSERT_TRUE(!getaddrinfo("127.0.0.1", NULL, &hints, &r));
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
// ipv4 intranet
if (true) {
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
addrinfo* r = NULL;
SrsAutoFree(addrinfo, r);
ASSERT_TRUE(!getaddrinfo("192.168.0.1", NULL, &hints, &r));
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
EXPECT_FALSE(srs_net_device_is_internet("eth0"));
if (true) {
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(0x12000000);
EXPECT_TRUE(srs_net_device_is_internet((sockaddr*)&addr));
addr.sin_addr.s_addr = htonl(0x7f000000);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)&addr));
addr.sin_addr.s_addr = htonl(0x7f000001);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)&addr));
addr.sin_addr.s_addr = htonl(0x0a000000);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)&addr));
addr.sin_addr.s_addr = htonl(0x0a000001);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)&addr));
addr.sin_addr.s_addr = htonl(0x0affffff);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)&addr));
addr.sin_addr.s_addr = htonl(0xc0a80000);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)&addr));
addr.sin_addr.s_addr = htonl(0xc0a80001);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)&addr));
addr.sin_addr.s_addr = htonl(0xc0a8ffff);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)&addr));
}
// Normal ipv6 address.
if (true) {
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFree(addrinfo, r);
ASSERT_TRUE(!getaddrinfo("2001:da8:6000:291:21f:d0ff:fed4:928c", NULL, &hints, &r));
EXPECT_TRUE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
if (true) {
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFree(addrinfo, r);
ASSERT_TRUE(!getaddrinfo("3ffe:dead:beef::1", NULL, &hints, &r));
EXPECT_TRUE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
// IN6_IS_ADDR_UNSPECIFIED
if (true) {
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFree(addrinfo, r);
ASSERT_TRUE(!getaddrinfo("::", NULL, &hints, &r));
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
// IN6_IS_ADDR_SITELOCAL
if (true) {
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFree(addrinfo, r);
ASSERT_TRUE(!getaddrinfo("fec0::", NULL, &hints, &r));
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
// IN6_IS_ADDR_LINKLOCAL
if (true) {
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFree(addrinfo, r);
ASSERT_TRUE(!getaddrinfo("FE80::", NULL, &hints, &r));
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
// IN6_IS_ADDR_LINKLOCAL
if (true) {
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFree(addrinfo, r);
ASSERT_TRUE(!getaddrinfo("::1", NULL, &hints, &r));
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
}

View file

@ -29,5 +29,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <srs_utest.hpp>
#include <srs_app_st.hpp>
#endif