Merge branch '3.0release' into develop

min
winlin 5 years ago
commit fee58a8acb

@ -147,6 +147,8 @@ For previous versions, please read:
## V3 changes
* v3.0, 2019-12-20, Fix [#1508][bug #1508], http-client support read chunked response. 3.0.76
* v3.0, 2019-12-20, For [#1508][bug #1508], refactor srs_is_digital, support all zeros.
* <strong>v3.0, 2019-12-19, [3.0 alpha5(3.0.75)][r3.0a5] released. 115362 lines.</strong>
* v3.0, 2019-12-19, Refine the RTMP iovs cache increasing to much faster.
* v3.0, 2019-12-19, Fix [#1524][bug #1524], memory leak for amf0 strict array. 3.0.75
@ -1543,6 +1545,7 @@ Winlin
[bug #1506]: https://github.com/ossrs/srs/issues/1506
[bug #1520]: https://github.com/ossrs/srs/issues/1520
[bug #1223]: https://github.com/ossrs/srs/issues/1223
[bug #1508]: https://github.com/ossrs/srs/issues/1508
[bug #xxxxxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxxxxx
[bug #1111]: https://github.com/ossrs/srs/issues/1111

@ -23,6 +23,8 @@ echo "# build ${APP_TARGET}" >> ${FILE}
# generate the binary depends, for example:
# srs: objs/srs
echo "${BUILD_KEY}: ${APP_TARGET}" >> ${FILE}
echo "" >> ${FILE}
# the link commands, for example:
# objs/srs: objs/src/core/srs_core.o
echo -n "${APP_TARGET}: " >> ${FILE}
@ -88,5 +90,6 @@ done
# link options.
echo -n "${LINK_OPTIONS}" >> ${FILE}
echo "" >> ${FILE}
echo "" >> ${FILE}
echo -n "Generate app ${APP_NAME} ok"; echo '!';

@ -19,6 +19,7 @@ echo "Generating lib ${LIB_NAME} depends."
echo "" >> ${FILE}
echo "# archive library ${LIB_TAGET_STATIC}" >> ${FILE}
echo "${BUILD_KEY}: ${LIB_TAGET_STATIC}" >> ${FILE}
echo "" >> ${FILE}
# build depends
echo -n "${LIB_TAGET_STATIC}: " >> ${FILE}

4
trunk/configure vendored

@ -429,13 +429,13 @@ for SRS_MODULE in ${SRS_MODULES[*]}; do
# if export librtmp, donot build the bravo-ingest.
if [ $SRS_EXPORT_LIBRTMP_PROJECT != NO ]; then
cat << END >> ${SRS_WORKDIR}/${SRS_MAKEFILE}
$SRS_MODULE_NAME: _prepare_dir
$SRS_MODULE_NAME: _prepare_dir server
@echo "Ingore the $SRS_MODULE_NAME for srs-librtmp"
END
else
cat << END >> ${SRS_WORKDIR}/${SRS_MAKEFILE}
$SRS_MODULE_NAME: _prepare_dir
$SRS_MODULE_NAME: _prepare_dir server
@echo "Build the $SRS_MODULE_NAME over SRS"
\$(MAKE) -f ${SRS_OBJS_DIR}/${SRS_MAKEFILE} $SRS_MODULE_NAME

@ -29,7 +29,6 @@
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <math.h>
#include <netdb.h>
#ifdef SRS_OSX
@ -1158,17 +1157,6 @@ string srs_get_peer_ip(int fd)
return std::string(saddr);
}
bool srs_is_digit_number(const string& str)
{
if (str.empty()) {
return false;
}
int v = ::atoi(str.c_str());
int powv = (int)pow(10, str.length() - 1);
return v / powv >= 1 && v / powv <= 9;
}
bool srs_is_boolean(const string& str)
{
return str == "true" || str == "false";

@ -640,12 +640,6 @@ extern int srs_get_local_port(int fd);
// Where peer ip is the client public ip which connected to server.
extern std::string srs_get_peer_ip(int fd);
// Whether string is digit number
// is_digit("1234567890") === true
// is_digit("0123456789") === false
// is_digit("1234567890a") === false
// is_digit("a1234567890") === false
extern bool srs_is_digit_number(const std::string& str);
// Whether string is boolean
// is_bool("true") == true
// is_bool("false") == true

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

@ -52,14 +52,14 @@ IMergeReadHandler::~IMergeReadHandler()
}
#endif
SrsFastStream::SrsFastStream()
SrsFastStream::SrsFastStream(int size)
{
#ifdef SRS_PERF_MERGED_READ
merged_read = false;
_handler = NULL;
#endif
nb_buffer = SRS_DEFAULT_RECV_BUFFER_SIZE;
nb_buffer = size? size:SRS_DEFAULT_RECV_BUFFER_SIZE;
buffer = (char*)malloc(nb_buffer);
p = end = buffer;
}
@ -84,8 +84,7 @@ void SrsFastStream::set_buffer(int buffer_size)
{
// never exceed the max size.
if (buffer_size > SRS_MAX_SOCKET_BUFFER) {
srs_warn("limit the user-space buffer from %d to %d",
buffer_size, SRS_MAX_SOCKET_BUFFER);
srs_warn("limit buffer size %d to %d", buffer_size, SRS_MAX_SOCKET_BUFFER);
}
// the user-space buffer size limit to a max value.
@ -152,7 +151,7 @@ srs_error_t SrsFastStream::grow(ISrsReader* reader, int required_size)
srs_assert(nb_exists_bytes >= 0);
// resize the space when no left space.
if (nb_free_space < required_size - nb_exists_bytes) {
if (nb_exists_bytes + nb_free_space < required_size) {
// reset or move to get more space.
if (!nb_exists_bytes) {
// reset when buffer is empty.
@ -168,7 +167,7 @@ srs_error_t SrsFastStream::grow(ISrsReader* reader, int required_size)
// check whether enough free space in buffer.
nb_free_space = (int)(buffer + nb_buffer - end);
if (nb_free_space < required_size - nb_exists_bytes) {
if (nb_exists_bytes + nb_free_space < required_size) {
return srs_error_new(ERROR_READER_BUFFER_OVERFLOW, "overflow, required=%d, max=%d, left=%d", required_size, nb_buffer, nb_free_space);
}
}

@ -84,7 +84,8 @@ private:
// the size of buffer.
int nb_buffer;
public:
SrsFastStream();
// If buffer is 0, use default size.
SrsFastStream(int size=0);
virtual ~SrsFastStream();
public:
/**
@ -128,7 +129,7 @@ public:
virtual void skip(int size);
public:
/**
* grow buffer to the required size, loop to read from skt to fill.
* grow buffer to atleast required size, loop to read from skt to fill.
* @param reader, read more bytes from reader to fill the buffer to required size.
* @param required_size, loop to fill to ensure buffer size to required.
* @return an int error code, error if required_size negative.

@ -40,6 +40,8 @@ SrsHttpParser::SrsHttpParser()
{
buffer = new SrsFastStream();
header = NULL;
p_body_start = p_header_tail = NULL;
}
SrsHttpParser::~SrsHttpParser()
@ -80,7 +82,7 @@ srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** p
state = SrsHttpParseStateInit;
hp_header = http_parser();
// The body that we have read from cache.
pbody = NULL;
p_body_start = p_header_tail = NULL;
// We must reset the field name and value, because we may get a partial value in on_header_value.
field_name = field_value = "";
// The header of the request.
@ -115,15 +117,26 @@ srs_error_t SrsHttpParser::parse_message_imp(ISrsReader* reader)
while (true) {
if (buffer->size() > 0) {
ssize_t nparsed = http_parser_execute(&parser, &settings, buffer->bytes(), buffer->size());
if (buffer->size() != nparsed) {
return srs_error_new(ERROR_HTTP_PARSE_HEADER, "parse failed, nparsed=%d, size=%d", nparsed, buffer->size());
ssize_t consumed = http_parser_execute(&parser, &settings, buffer->bytes(), buffer->size());
// The error is set in http_errno.
enum http_errno code;
if ((code = HTTP_PARSER_ERRNO(&parser)) != HPE_OK) {
return srs_error_new(ERROR_HTTP_PARSE_HEADER, "parse %dB, nparsed=%d, err=%d/%s %s",
buffer->size(), consumed, http_errno_name(code), http_errno_description(code));
}
// The consumed size, does not include the body.
ssize_t consumed = nparsed;
if (pbody && buffer->bytes() < pbody) {
consumed = pbody - buffer->bytes();
// When buffer consumed these bytes, it's dropped so the new ptr is actually the HTTP body. But http-parser
// doesn't indicate the specific sizeof header, so we must finger it out.
// @remark We shouldn't use on_body, because it only works for normal case, and losts the chunk header and length.
// @see https://github.com/ossrs/srs/issues/1508
if (p_header_tail && buffer->bytes() < p_body_start) {
for (const char* p = p_header_tail; p <= p_body_start - 4; p++) {
if (p[0] == SRS_CONSTS_CR && p[1] == SRS_CONSTS_LF && p[2] == SRS_CONSTS_CR && p[3] == SRS_CONSTS_LF) {
consumed = p + 4 - buffer->bytes();
break;
}
}
}
srs_info("size=%d, nparsed=%d, consumed=%d", buffer->size(), (int)nparsed, consumed);
@ -199,6 +212,11 @@ int SrsHttpParser::on_url(http_parser* parser, const char* at, size_t length)
if (length > 0) {
obj->url = string(at, (int)length);
}
// When header parsed, we must save the position of start for body,
// because we have to consume the header in buffer.
// @see https://github.com/ossrs/srs/issues/1508
obj->p_header_tail = at;
srs_info("Method: %d, Url: %.*s", parser->method, (int)length, at);
@ -218,6 +236,11 @@ int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t l
if (length > 0) {
obj->field_name.append(at, (int)length);
}
// When header parsed, we must save the position of start for body,
// because we have to consume the header in buffer.
// @see https://github.com/ossrs/srs/issues/1508
obj->p_header_tail = at;
srs_info("Header field(%d bytes): %.*s", (int)length, (int)length, at);
return 0;
@ -231,6 +254,11 @@ int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t l
if (length > 0) {
obj->field_value.append(at, (int)length);
}
// When header parsed, we must save the position of start for body,
// because we have to consume the header in buffer.
// @see https://github.com/ossrs/srs/issues/1508
obj->p_header_tail = at;
srs_info("Header value(%d bytes): %.*s", (int)length, (int)length, at);
return 0;
@ -244,9 +272,10 @@ int SrsHttpParser::on_body(http_parser* parser, const char* at, size_t length)
// save the parser when body parsed.
obj->state = SrsHttpParseStateBody;
// Save the body position.
obj->pbody = at;
// Used to discover the header length.
// @see https://github.com/ossrs/srs/issues/1508
obj->p_body_start = at;
srs_info("Body: %.*s", (int)length, at);
return 0;
@ -962,11 +991,15 @@ srs_error_t SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb
// it's ok to set the pos and pos+1 to NULL.
at[length - 1] = 0;
at[length - 2] = 0;
// size is the bytes size, excludes the chunk header and end CRLF.
int ilength = (int)::strtol(at, NULL, 16);
if (ilength < 0) {
return srs_error_new(ERROR_HTTP_INVALID_CHUNK_HEADER, "invalid length=%d", ilength);
// @remark It must be hex format, please read https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding#Directives
// @remark For strtol, note that: If no conversion could be performed, 0 is returned and the global variable errno is set to EINVAL.
char* at_parsed = at; errno = 0;
int ilength = (int)::strtol(at, &at_parsed, 16);
if (ilength < 0 || errno != 0 || at_parsed - at != length - 2) {
return srs_error_new(ERROR_HTTP_INVALID_CHUNK_HEADER, "invalid length %s as %d, parsed=%.*s, errno=%d",
at, ilength, (int)(at_parsed-at), at, errno);
}
// all bytes in chunk is left now.

@ -55,7 +55,11 @@ private:
http_parser hp_header;
std::string url;
SrsHttpHeader* header;
const char* pbody;
private:
// Point to the start of body.
const char* p_body_start;
// To discover the length of header, point to the last few bytes in header.
const char* p_header_tail;
public:
SrsHttpParser();
virtual ~SrsHttpParser();

@ -28,6 +28,8 @@
#include <net/if.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <math.h>
#include <stdlib.h>
#include <map>
#include <sstream>
using namespace std;
@ -48,6 +50,28 @@ bool srs_string_is_rtmp(string url)
return srs_string_starts_with(url, "rtmp://");
}
bool srs_is_digit_number(const string& str)
{
if (str.empty()) {
return false;
}
const char* p = str.c_str();
const char* p_end = str.data() + str.length();
for (; p < p_end; p++) {
if (*p != '0') {
break;
}
}
if (p == p_end) {
return true;
}
int64_t v = ::atoll(p);
int64_t powv = (int64_t)pow(10, p_end - p - 1);
return v / powv >= 1 && v / powv <= 9;
}
// we detect all network device as internet or intranet device, by its ip address.
// key is device name, for instance, eth0
// value is whether internet, for instance, true.

@ -36,6 +36,18 @@
extern bool srs_string_is_http(std::string url);
extern bool srs_string_is_rtmp(std::string url);
// Whether string is digit number
// is_digit("0") === true
// is_digit("0000000000") === true
// is_digit("1234567890") === true
// is_digit("0123456789") === true
// is_digit("1234567890a") === false
// is_digit("a1234567890") === false
// is_digit("10e3") === false
// is_digit("!1234567890") === false
// is_digit("") === false
extern bool srs_is_digit_number(const std::string& str);
// Get local ip, fill to @param ips
extern std::vector<std::string>& srs_get_local_ips();

@ -251,6 +251,26 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter)
__MOCK_HTTP_EXPECT_STREQ2(200, "5\r\nHello\r\n8\r\n, world!\r\n0\r\n\r\n", w);
}
if (true) {
MockResponseWriter w;
w.header()->set_content_type("application/octet-stream");
w.write_header(SRS_CONSTS_HTTP_OK);
w.write((char*)"Hello, world!", 13);
w.final_request();
__MOCK_HTTP_EXPECT_STREQ2(200, "d\r\nHello, world!\r\n0\r\n\r\n", w);
}
if (true) {
MockResponseWriter w;
w.header()->set_content_type("application/octet-stream");
w.write_header(SRS_CONSTS_HTTP_OK);
w.write((char*)"Hello, world!", 13);
w.final_request();
__MOCK_HTTP_EXPECT_STREQ2(200, "d\r\nHello, world!\r\n0\r\n\r\n", w);
}
// If directly write empty string, sent an empty response with content-length 0
if (true) {
@ -267,6 +287,42 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter)
}
}
VOID TEST(ProtocolHTTPTest, ClientRequest)
{
srs_error_t err;
// Normal case, with chunked encoding.
if (true) {
MockBufferIO io; io.append(mock_http_response2(200, "0d\r\nHello, world!\r\n0\r\n\r\n"));
SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false));
ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg));
string res; HELPER_ASSERT_SUCCESS(msg->body_read_all(res));
EXPECT_EQ(200, msg->status_code());
EXPECT_STREQ("Hello, world!", res.c_str());
srs_freep(msg);
}
if (true) {
MockBufferIO io; io.append(mock_http_response2(200, "6\r\nHello!\r\n0\r\n\r\n"));
SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false));
ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg));
string res; HELPER_ASSERT_SUCCESS(msg->body_read_all(res));
EXPECT_EQ(200, msg->status_code());
EXPECT_STREQ("Hello!", res.c_str());
srs_freep(msg);
}
// Normal case, with specified content-length.
if (true) {
MockBufferIO io; io.append(mock_http_response(200, "Hello, world!"));
SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false));
ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg));
string res; HELPER_ASSERT_SUCCESS(msg->body_read_all(res));
EXPECT_EQ(200, msg->status_code());
EXPECT_STREQ("Hello, world!", res.c_str());
srs_freep(msg);
}
}
VOID TEST(ProtocolHTTPTest, ResponseHTTPError)
{
srs_error_t err;

@ -271,8 +271,12 @@ MockBufferReader::~MockBufferReader()
srs_error_t MockBufferReader::read(void* buf, size_t size, ssize_t* nread)
{
int len = srs_min(str.length(), size);
if (len == 0) {
return srs_error_new(-1, "no data");
}
memcpy(buf, str.data(), len);
str = str.substr(len);
if (nread) {
*nread = len;
@ -388,19 +392,73 @@ VOID TEST(KernelBufferTest, EraseBytes)
VOID TEST(KernelFastBufferTest, Grow)
{
SrsFastStream b;
MockBufferReader r("winlin");
b.grow(&r, 1);
EXPECT_EQ('w', b.read_1byte());
srs_error_t err;
b.grow(&r, 3);
b.skip(1);
EXPECT_EQ('n', b.read_1byte());
b.grow(&r, 100);
b.skip(99);
EXPECT_EQ('w', b.read_1byte());
if(true) {
SrsFastStream b(5);
MockBufferReader r("Hello, world!");
HELPER_ASSERT_SUCCESS(b.grow(&r, 5));
b.skip(2);
HELPER_ASSERT_FAILED(b.grow(&r, 6));
}
if(true) {
SrsFastStream b(5);
MockBufferReader r("Hello, world!");
HELPER_ASSERT_SUCCESS(b.grow(&r, 5));
b.skip(5);
HELPER_ASSERT_FAILED(b.grow(&r, 6));
}
if(true) {
SrsFastStream b(6);
MockBufferReader r("Hello, world!");
HELPER_ASSERT_SUCCESS(b.grow(&r, 5));
EXPECT_EQ('H', b.read_1byte()); EXPECT_EQ('e', b.read_1byte()); EXPECT_EQ('l', b.read_1byte());
b.skip(2);
HELPER_ASSERT_SUCCESS(b.grow(&r, 2));
b.skip(2);
HELPER_ASSERT_SUCCESS(b.grow(&r, 5));
EXPECT_EQ('w', b.read_1byte()); EXPECT_EQ('o', b.read_1byte()); EXPECT_EQ('r', b.read_1byte());
b.skip(2);
}
if(true) {
SrsFastStream b(5);
MockBufferReader r("Hello, world!");
HELPER_ASSERT_SUCCESS(b.grow(&r, 5));
EXPECT_EQ('H', b.read_1byte()); EXPECT_EQ('e', b.read_1byte()); EXPECT_EQ('l', b.read_1byte());
b.skip(2);
HELPER_ASSERT_SUCCESS(b.grow(&r, 2));
b.skip(2);
HELPER_ASSERT_SUCCESS(b.grow(&r, 5));
EXPECT_EQ('w', b.read_1byte()); EXPECT_EQ('o', b.read_1byte()); EXPECT_EQ('r', b.read_1byte());
b.skip(2);
}
if (true) {
SrsFastStream b;
MockBufferReader r("winlin");
HELPER_ASSERT_SUCCESS(b.grow(&r, 1));
EXPECT_EQ('w', b.read_1byte());
HELPER_ASSERT_SUCCESS(b.grow(&r, 3));
b.skip(1);
EXPECT_EQ('n', b.read_1byte());
HELPER_ASSERT_FAILED(b.grow(&r, 100));
}
}
/**

@ -27,6 +27,7 @@ using namespace std;
#include <srs_kernel_error.hpp>
#include <srs_app_listener.hpp>
#include <srs_service_st.hpp>
#include <srs_service_utility.hpp>
// Disable coroutine test for OSX.
#if !defined(SRS_OSX)
@ -225,6 +226,153 @@ VOID TEST(TCPServerTest, PingPongWithTimeout)
}
}
VOID TEST(TCPServerTest, StringIsDigital)
{
EXPECT_EQ(0, ::atoi("0"));
EXPECT_EQ(0, ::atoi("0000000000"));
EXPECT_EQ(1, ::atoi("01"));
EXPECT_EQ(12, ::atoi("012"));
EXPECT_EQ(1234567890L, ::atol("1234567890"));
EXPECT_EQ(123456789L, ::atol("0123456789"));
EXPECT_EQ(1234567890, ::atoi("1234567890a"));
EXPECT_EQ(10, ::atoi("10e3"));
EXPECT_EQ(0, ::atoi("!1234567890"));
EXPECT_EQ(0, ::atoi(""));
EXPECT_TRUE(srs_is_digit_number("0"));
EXPECT_TRUE(srs_is_digit_number("0000000000"));
EXPECT_TRUE(srs_is_digit_number("1234567890"));
EXPECT_TRUE(srs_is_digit_number("0123456789"));
EXPECT_FALSE(srs_is_digit_number("1234567890a"));
EXPECT_FALSE(srs_is_digit_number("a1234567890"));
EXPECT_FALSE(srs_is_digit_number("10e3"));
EXPECT_FALSE(srs_is_digit_number("!1234567890"));
EXPECT_FALSE(srs_is_digit_number(""));
}
VOID TEST(TCPServerTest, StringIsHex)
{
if (true) {
char* str = (char*)"0";
char* parsed = str; errno = 0;
EXPECT_EQ(0x0, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 1, parsed);
}
if (true) {
char* str = (char*)"0";
char* parsed = str; errno = 0;
EXPECT_EQ(0x0, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 1, parsed);
}
if (true) {
char* str = (char*)"0000000000";
char* parsed = str; errno = 0;
EXPECT_EQ(0x0, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 10, parsed);
}
if (true) {
char* str = (char*)"01";
char* parsed = str; errno = 0;
EXPECT_EQ(0x1, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 2, parsed);
}
if (true) {
char* str = (char*)"012";
char* parsed = str; errno = 0;
EXPECT_EQ(0x12, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 3, parsed);
}
if (true) {
char* str = (char*)"1234567890";
char* parsed = str; errno = 0;
EXPECT_EQ(0x1234567890L, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 10, parsed);
}
if (true) {
char* str = (char*)"0123456789";
char* parsed = str; errno = 0;
EXPECT_EQ(0x123456789L, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 10, parsed);
}
if (true) {
char* str = (char*)"1234567890a";
char* parsed = str; errno = 0;
EXPECT_EQ(0x1234567890a, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 11, parsed);
}
if (true) {
char* str = (char*)"0x1234567890a";
char* parsed = str; errno = 0;
EXPECT_EQ(0x1234567890a, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 13, parsed);
}
if (true) {
char* str = (char*)"1234567890f";
char* parsed = str; errno = 0;
EXPECT_EQ(0x1234567890f, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 11, parsed);
}
if (true) {
char* str = (char*)"10e3";
char* parsed = str; errno = 0;
EXPECT_EQ(0x10e3, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 4, parsed);
}
if (true) {
char* str = (char*)"!1234567890";
char* parsed = str; errno = 0;
EXPECT_EQ(0x0, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str, parsed);
}
if (true) {
char* str = (char*)"1234567890g";
char* parsed = str; errno = 0;
EXPECT_EQ(0x1234567890, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str + 10, parsed);
}
if (true) {
char* str = (char*)"";
char* parsed = str; errno = 0;
EXPECT_EQ(0x0, ::strtol(str, &parsed, 16));
EXPECT_EQ(0, errno);
EXPECT_EQ(str, parsed);
}
if (true) {
char* str = (char*)"1fffffffffffffffffffffffffffff";
char* parsed = str; errno = 0;
EXPECT_EQ(0x7fffffffffffffff, ::strtol(str, &parsed, 16));
EXPECT_NE(0, errno);
EXPECT_EQ(str+30, parsed);
}
}
VOID TEST(TCPServerTest, WritevIOVC)
{
srs_error_t err;

Loading…
Cancel
Save