diff --git a/.circleci/config.yml b/.circleci/config.yml
index 9fa2e06e3..48d678850 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -5,13 +5,13 @@ jobs:
- image: ossrs/srs:dev
steps:
- checkout
- - run: cd trunk && ./configure && make
+ - run: cd trunk && ./configure --with-utest && make
test:
docker:
- image: ossrs/srs:dev
steps:
- checkout
- - run: cd trunk && ./configure --gcov && make && ./objs/srs_utest && bash auto/coverage.sh
+ - run: cd trunk && ./configure --with-utest --gcov && make && ./objs/srs_utest && bash auto/coverage.sh
workflows:
version: 2
build_and_test:
diff --git a/README.md b/README.md
index 222b112c9..9a351fc50 100755
--- a/README.md
+++ b/README.md
@@ -169,6 +169,9 @@ For previous versions, please read:
## V3 changes
+* v3.0, 2020-03-21, For [#1629][bug #1629], fix kickoff FLV client bug. 3.0.137
+* v3.0, 2020-03-21, For [#1619][bug #1619], configure without utest by default. 3.0.136
+* v3.0, 2020-03-21, For [#1651][bug #1651], fix return pnwrite of srs_write_large_iovs. 3.0.135
* v3.0, 2020-03-18, [3.0 beta3(3.0.134)][r3.0b3] released. 122509 lines.
* v3.0, 2020-03-12, For [#1635][bug #1635], inotify watch ConfigMap for reload. 3.0.134
* v3.0, 2020-03-12, For [#1635][bug #1635], support auto reaload config by inotify. 3.0.129
@@ -1710,6 +1713,9 @@ Winlin
[bug #1594]: https://github.com/ossrs/srs/issues/1594
[bug #1630]: https://github.com/ossrs/srs/issues/1630
[bug #1635]: https://github.com/ossrs/srs/issues/1635
+[bug #1651]: https://github.com/ossrs/srs/issues/1651
+[bug #1619]: https://github.com/ossrs/srs/issues/1619
+[bug #1629]: https://github.com/ossrs/srs/issues/1629
[bug #yyyyyyyyyyyyy]: https://github.com/ossrs/srs/issues/yyyyyyyyyyyyy
[bug #1631]: https://github.com/ossrs/srs/issues/1631
diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh
index ad89f882d..4548d819e 100755
--- a/trunk/auto/options.sh
+++ b/trunk/auto/options.sh
@@ -21,7 +21,7 @@ SRS_NGINX=NO
SRS_FFMPEG_TOOL=NO
SRS_LIBRTMP=NO
SRS_RESEARCH=NO
-SRS_UTEST=YES
+SRS_UTEST=NO
SRS_GPERF=NO # Performance test: tcmalloc
SRS_GPERF_MC=NO # Performance test: gperf memory check
SRS_GPERF_MD=NO # Performance test: gperf memory defence
@@ -397,7 +397,7 @@ function apply_user_presets() {
SRS_HDS=YES
SRS_LIBRTMP=YES
SRS_RESEARCH=NO
- SRS_UTEST=YES
+ SRS_UTEST=NO
SRS_STATIC=NO
fi
@@ -424,7 +424,7 @@ function apply_user_presets() {
SRS_HDS=YES
SRS_LIBRTMP=YES
SRS_RESEARCH=NO
- SRS_UTEST=YES
+ SRS_UTEST=NO
SRS_STATIC=NO
fi
diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp
index fc1831aa4..8f9429cbc 100644
--- a/trunk/src/app/srs_app_http_conn.cpp
+++ b/trunk/src/app/srs_app_http_conn.cpp
@@ -198,19 +198,32 @@ srs_error_t SrsResponseOnlyHttpConn::pop_message(ISrsHttpMessage** preq)
srs_error_t err = srs_success;
SrsStSocket skt;
-
+
if ((err = skt.initialize(stfd)) != srs_success) {
return srs_error_wrap(err, "init socket");
}
-
- if ((err = parser->parse_message(&skt, preq)) != srs_success) {
- return srs_error_wrap(err, "parse message");
+
+ // Check user interrupt by interval.
+ skt.set_recv_timeout(3 * SRS_UTIME_SECONDS);
+
+ // drop all request body.
+ char body[4096];
+ while (true) {
+ if ((err = trd->pull()) != srs_success) {
+ return srs_error_wrap(err, "timeout");
+ }
+
+ if ((err = skt.read(body, 4096, NULL)) != srs_success) {
+ // Because we use timeout to check trd state, so we should ignore any timeout.
+ if (srs_error_code(err) == ERROR_SOCKET_TIMEOUT) {
+ srs_freep(err);
+ continue;
+ }
+
+ return srs_error_wrap(err, "read response");
+ }
}
- // Attach owner connection to message.
- SrsHttpMessage* hreq = (SrsHttpMessage*)(*preq);
- hreq->set_connection(this);
-
return err;
}
@@ -219,12 +232,12 @@ srs_error_t SrsResponseOnlyHttpConn::on_got_http_message(ISrsHttpMessage* msg)
srs_error_t err = srs_success;
ISrsHttpResponseReader* br = msg->body_reader();
-
+
// when not specified the content length, ignore.
if (msg->content_length() == -1) {
return err;
}
-
+
// drop all request body.
char body[4096];
while (!br->eof()) {
@@ -236,6 +249,11 @@ srs_error_t SrsResponseOnlyHttpConn::on_got_http_message(ISrsHttpMessage* msg)
return err;
}
+void SrsResponseOnlyHttpConn::expire()
+{
+ SrsHttpConn::expire();
+}
+
SrsHttpServer::SrsHttpServer(SrsServer* svr)
{
server = svr;
diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp
index f3de6659e..7529cfc5b 100644
--- a/trunk/src/app/srs_app_http_conn.hpp
+++ b/trunk/src/app/srs_app_http_conn.hpp
@@ -101,6 +101,9 @@ public:
virtual srs_error_t pop_message(ISrsHttpMessage** preq);
public:
virtual srs_error_t on_got_http_message(ISrsHttpMessage* msg);
+public:
+ // Set connection to expired.
+ virtual void expire();
};
// The http server, use http stream or static server to serve requests.
diff --git a/trunk/src/app/srs_app_http_stream.cpp b/trunk/src/app/srs_app_http_stream.cpp
index fb7bd54b3..815561e1e 100755
--- a/trunk/src/app/srs_app_http_stream.cpp
+++ b/trunk/src/app/srs_app_http_stream.cpp
@@ -592,10 +592,15 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
SrsAutoFree(SrsPithyPrint, pprint);
SrsMessageArray msgs(SRS_PERF_MW_MSGS);
+
+ // Use receive thread to accept the close event to avoid FD leak.
+ // @see https://github.com/ossrs/srs/issues/636#issuecomment-298208427
+ SrsHttpMessage* hr = dynamic_cast(r);
+ SrsResponseOnlyHttpConn* hc = dynamic_cast(hr->connection());
// update the statistic when source disconveried.
SrsStatistic* stat = SrsStatistic::instance();
- if ((err = stat->on_client(_srs_context->get_id(), req, NULL, SrsRtmpConnPlay)) != srs_success) {
+ if ((err = stat->on_client(_srs_context->get_id(), req, hc, SrsRtmpConnPlay)) != srs_success) {
return srs_error_wrap(err, "stat on client");
}
@@ -613,11 +618,6 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess
}
SrsFlvStreamEncoder* ffe = dynamic_cast(enc);
-
- // Use receive thread to accept the close event to avoid FD leak.
- // @see https://github.com/ossrs/srs/issues/636#issuecomment-298208427
- SrsHttpMessage* hr = dynamic_cast(r);
- SrsResponseOnlyHttpConn* hc = dynamic_cast(hr->connection());
// Set the socket options for transport.
bool tcp_nodelay = _srs_config->get_tcp_nodelay(req->vhost);
diff --git a/trunk/src/core/srs_core_version3.hpp b/trunk/src/core/srs_core_version3.hpp
index 5ff02aa5a..95a9c694d 100644
--- a/trunk/src/core/srs_core_version3.hpp
+++ b/trunk/src/core/srs_core_version3.hpp
@@ -24,6 +24,6 @@
#ifndef SRS_CORE_VERSION3_HPP
#define SRS_CORE_VERSION3_HPP
-#define SRS_VERSION3_REVISION 134
+#define SRS_VERSION3_REVISION 137
#endif
diff --git a/trunk/src/protocol/srs_protocol_utility.cpp b/trunk/src/protocol/srs_protocol_utility.cpp
index 251d69854..57e65ecf0 100644
--- a/trunk/src/protocol/srs_protocol_utility.cpp
+++ b/trunk/src/protocol/srs_protocol_utility.cpp
@@ -336,21 +336,25 @@ srs_error_t srs_write_large_iovs(ISrsProtocolReadWriter* skt, iovec* iovs, int s
#endif
// send in a time.
- if (size < limits) {
+ if (size <= limits) {
if ((err = skt->writev(iovs, size, pnwrite)) != srs_success) {
return srs_error_wrap(err, "writev");
}
return err;
}
-
+
// send in multiple times.
int cur_iov = 0;
+ ssize_t nwrite = 0;
while (cur_iov < size) {
int cur_count = srs_min(limits, size - cur_iov);
- if ((err = skt->writev(iovs + cur_iov, cur_count, pnwrite)) != srs_success) {
+ if ((err = skt->writev(iovs + cur_iov, cur_count, &nwrite)) != srs_success) {
return srs_error_wrap(err, "writev");
}
cur_iov += cur_count;
+ if (pnwrite) {
+ *pnwrite += nwrite;
+ }
}
return err;
diff --git a/trunk/src/utest/srs_utest_protocol.cpp b/trunk/src/utest/srs_utest_protocol.cpp
index 0e952cf68..2535b6fd2 100644
--- a/trunk/src/utest/srs_utest_protocol.cpp
+++ b/trunk/src/utest/srs_utest_protocol.cpp
@@ -230,8 +230,6 @@ srs_error_t MockBufferIO::writev(const iovec *iov, int iov_size, ssize_t* nwrite
total += writen;
}
- sbytes += total;
-
if (nwrite) {
*nwrite = total;
}
@@ -6412,3 +6410,65 @@ VOID TEST(ProtocolKbpsTest, RAWStatistic)
}
}
+VOID TEST(ProtocolKbpsTest, WriteLargeIOVs)
+{
+ srs_error_t err;
+
+ if (true) {
+ iovec iovs[1];
+ iovs[0].iov_base = (char*)"Hello";
+ iovs[0].iov_len = 5;
+
+ MockBufferIO io;
+ ssize_t nn = 0;
+ HELPER_EXPECT_SUCCESS(srs_write_large_iovs(&io, iovs, 1, &nn));
+ EXPECT_EQ(5, nn);
+ EXPECT_EQ(5, io.sbytes);
+ }
+
+ if (true) {
+ iovec iovs[1024];
+ int nn_iovs = (int)(sizeof(iovs)/sizeof(iovec));
+ for (int i = 0; i < nn_iovs; i++) {
+ iovs[i].iov_base = (char*)"Hello";
+ iovs[i].iov_len = 5;
+ }
+
+ MockBufferIO io;
+ ssize_t nn = 0;
+ HELPER_EXPECT_SUCCESS(srs_write_large_iovs(&io, iovs, nn_iovs, &nn));
+ EXPECT_EQ(5 * nn_iovs, nn);
+ EXPECT_EQ(5 * nn_iovs, io.sbytes);
+ }
+
+ if (true) {
+ iovec iovs[1025];
+ int nn_iovs = (int)(sizeof(iovs)/sizeof(iovec));
+ for (int i = 0; i < nn_iovs; i++) {
+ iovs[i].iov_base = (char*)"Hello";
+ iovs[i].iov_len = 5;
+ }
+
+ MockBufferIO io;
+ ssize_t nn = 0;
+ HELPER_EXPECT_SUCCESS(srs_write_large_iovs(&io, iovs, nn_iovs, &nn));
+ EXPECT_EQ(5 * nn_iovs, nn);
+ EXPECT_EQ(5 * nn_iovs, io.sbytes);
+ }
+
+ if (true) {
+ iovec iovs[4096];
+ int nn_iovs = (int)(sizeof(iovs)/sizeof(iovec));
+ for (int i = 0; i < nn_iovs; i++) {
+ iovs[i].iov_base = (char*)"Hello";
+ iovs[i].iov_len = 5;
+ }
+
+ MockBufferIO io;
+ ssize_t nn = 0;
+ HELPER_EXPECT_SUCCESS(srs_write_large_iovs(&io, iovs, nn_iovs, &nn));
+ EXPECT_EQ(5 * nn_iovs, nn);
+ EXPECT_EQ(5 * nn_iovs, io.sbytes);
+ }
+}
+