winlin

fix #78 st joinable thread must be stop by other threads, 0.9.113

@@ -231,6 +231,7 @@ Supported operating systems and hardware: @@ -231,6 +231,7 @@ Supported operating systems and hardware:
231 * 2013-10-17, Created.<br/> 231 * 2013-10-17, Created.<br/>
232 232
233 ## History 233 ## History
  234 +* v1.0, 2014-05-22, fix [#78](https://github.com/winlinvip/simple-rtmp-server/issues/78), st joinable thread must be stop by other threads, 0.9.113
234 * v1.0, 2014-05-22, support amf0 StrictArray(0x0a). 0.9.111. 235 * v1.0, 2014-05-22, support amf0 StrictArray(0x0a). 0.9.111.
235 * v1.0, 2014-05-22, support flv parser, add amf0 to librtmp. 0.9.110 236 * v1.0, 2014-05-22, support flv parser, add amf0 to librtmp. 0.9.110
236 * v1.0, 2014-05-22, fix [#74](https://github.com/winlinvip/simple-rtmp-server/issues/74), add tcUrl for http callback on_connect, 0.9.109 237 * v1.0, 2014-05-22, fix [#74](https://github.com/winlinvip/simple-rtmp-server/issues/74), add tcUrl for http callback on_connect, 0.9.109
@@ -35,7 +35,11 @@ SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd) @@ -35,7 +35,11 @@ SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd)
35 server = srs_server; 35 server = srs_server;
36 stfd = client_stfd; 36 stfd = client_stfd;
37 connection_id = 0; 37 connection_id = 0;
38 - pthread = new SrsThread(this, 0); 38 + // the client thread should reap itself,
  39 + // so we never use joinable.
  40 + // TODO: FIXME: maybe other thread need to stop it.
  41 + // @see: https://github.com/winlinvip/simple-rtmp-server/issues/78
  42 + pthread = new SrsThread(this, 0, false);
39 } 43 }
40 44
41 SrsConnection::~SrsConnection() 45 SrsConnection::~SrsConnection()
@@ -69,7 +69,7 @@ SrsEdgeIngester::SrsEdgeIngester() @@ -69,7 +69,7 @@ SrsEdgeIngester::SrsEdgeIngester()
69 origin_index = 0; 69 origin_index = 0;
70 stream_id = 0; 70 stream_id = 0;
71 stfd = NULL; 71 stfd = NULL;
72 - pthread = new SrsThread(this, SRS_EDGE_INGESTER_SLEEP_US); 72 + pthread = new SrsThread(this, SRS_EDGE_INGESTER_SLEEP_US, true);
73 } 73 }
74 74
75 SrsEdgeIngester::~SrsEdgeIngester() 75 SrsEdgeIngester::~SrsEdgeIngester()
@@ -344,7 +344,7 @@ SrsEdgeForwarder::SrsEdgeForwarder() @@ -344,7 +344,7 @@ SrsEdgeForwarder::SrsEdgeForwarder()
344 origin_index = 0; 344 origin_index = 0;
345 stream_id = 0; 345 stream_id = 0;
346 stfd = NULL; 346 stfd = NULL;
347 - pthread = new SrsThread(this, SRS_EDGE_FORWARDER_SLEEP_US); 347 + pthread = new SrsThread(this, SRS_EDGE_FORWARDER_SLEEP_US, true);
348 queue = new SrsMessageQueue(); 348 queue = new SrsMessageQueue();
349 send_error_code = ERROR_SUCCESS; 349 send_error_code = ERROR_SUCCESS;
350 } 350 }
@@ -44,7 +44,7 @@ static std::vector<std::string> _transcoded_url; @@ -44,7 +44,7 @@ static std::vector<std::string> _transcoded_url;
44 44
45 SrsEncoder::SrsEncoder() 45 SrsEncoder::SrsEncoder()
46 { 46 {
47 - pthread = new SrsThread(this, SRS_RTMP_ENCODER_SLEEP_US); 47 + pthread = new SrsThread(this, SRS_RTMP_ENCODER_SLEEP_US, true);
48 pithy_print = new SrsPithyPrint(SRS_STAGE_ENCODER); 48 pithy_print = new SrsPithyPrint(SRS_STAGE_ENCODER);
49 } 49 }
50 50
@@ -54,7 +54,7 @@ SrsForwarder::SrsForwarder(SrsSource* _source) @@ -54,7 +54,7 @@ SrsForwarder::SrsForwarder(SrsSource* _source)
54 kbps = new SrsKbps(); 54 kbps = new SrsKbps();
55 stream_id = 0; 55 stream_id = 0;
56 56
57 - pthread = new SrsThread(this, SRS_FORWARDER_SLEEP_US); 57 + pthread = new SrsThread(this, SRS_FORWARDER_SLEEP_US, true);
58 queue = new SrsMessageQueue(); 58 queue = new SrsMessageQueue();
59 jitter = new SrsRtmpJitter(); 59 jitter = new SrsRtmpJitter();
60 } 60 }
@@ -291,6 +291,13 @@ SrsHttpHandler* SrsHttpHandler::res_content_type_mpegts(stringstream& ss) @@ -291,6 +291,13 @@ SrsHttpHandler* SrsHttpHandler::res_content_type_mpegts(stringstream& ss)
291 return this; 291 return this;
292 } 292 }
293 293
  294 +SrsHttpHandler* SrsHttpHandler::res_content_type_flv(stringstream& ss)
  295 +{
  296 + ss << "Content-Type: video/x-flv" << __CRLF
  297 + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF;
  298 + return this;
  299 +}
  300 +
294 SrsHttpHandler* SrsHttpHandler::res_content_length(stringstream& ss, int64_t length) 301 SrsHttpHandler* SrsHttpHandler::res_content_length(stringstream& ss, int64_t length)
295 { 302 {
296 ss << "Content-Length: "<< length << __CRLF; 303 ss << "Content-Length: "<< length << __CRLF;
@@ -1008,7 +1015,7 @@ const char* SrsHttpUri::get_path() @@ -1008,7 +1015,7 @@ const char* SrsHttpUri::get_path()
1008 1015
1009 const char* SrsHttpUri::get_query() 1016 const char* SrsHttpUri::get_query()
1010 { 1017 {
1011 - return path.data(); 1018 + return query.data();
1012 } 1019 }
1013 1020
1014 string SrsHttpUri::get_uri_field(string uri, http_parser_url* hp_u, http_parser_url_fields field) 1021 string SrsHttpUri::get_uri_field(string uri, http_parser_url* hp_u, http_parser_url_fields field)
@@ -250,6 +250,7 @@ public: @@ -250,6 +250,7 @@ public:
250 virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss); 250 virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss);
251 virtual SrsHttpHandler* res_content_type_m3u8(std::stringstream& ss); 251 virtual SrsHttpHandler* res_content_type_m3u8(std::stringstream& ss);
252 virtual SrsHttpHandler* res_content_type_mpegts(std::stringstream& ss); 252 virtual SrsHttpHandler* res_content_type_mpegts(std::stringstream& ss);
  253 + virtual SrsHttpHandler* res_content_type_flv(std::stringstream& ss);
253 virtual SrsHttpHandler* res_content_length(std::stringstream& ss, int64_t length); 254 virtual SrsHttpHandler* res_content_length(std::stringstream& ss, int64_t length);
254 virtual SrsHttpHandler* res_enable_crossdomain(std::stringstream& ss); 255 virtual SrsHttpHandler* res_enable_crossdomain(std::stringstream& ss);
255 virtual SrsHttpHandler* res_header_eof(std::stringstream& ss); 256 virtual SrsHttpHandler* res_header_eof(std::stringstream& ss);
@@ -165,6 +165,8 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req) @@ -165,6 +165,8 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req)
165 165
166 if (srs_string_ends_with(fullpath, ".ts")) { 166 if (srs_string_ends_with(fullpath, ".ts")) {
167 return response_ts_file(skt, req, fullpath); 167 return response_ts_file(skt, req, fullpath);
  168 + } else if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) {
  169 + return response_flv_file(skt, req, fullpath);
168 } else { 170 } else {
169 return response_regular_file(skt, req, fullpath); 171 return response_regular_file(skt, req, fullpath);
170 } 172 }
@@ -225,6 +227,62 @@ int SrsHttpVhost::response_regular_file(SrsSocket* skt, SrsHttpMessage* req, str @@ -225,6 +227,62 @@ int SrsHttpVhost::response_regular_file(SrsSocket* skt, SrsHttpMessage* req, str
225 return ret; 227 return ret;
226 } 228 }
227 229
  230 +int SrsHttpVhost::response_flv_file(SrsSocket* skt, SrsHttpMessage* req, string fullpath)
  231 +{
  232 + int ret = ERROR_SUCCESS;
  233 +
  234 + // TODO: FIXME: use more advance cache.
  235 + // for ts video large file, use bytes to write it.
  236 + int fd = ::open(fullpath.c_str(), O_RDONLY);
  237 + if (fd < 0) {
  238 + ret = ERROR_HTTP_OPEN_FILE;
  239 + srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret);
  240 + return ret;
  241 + }
  242 +
  243 + int64_t length = (int64_t)::lseek(fd, 0, SEEK_END);
  244 + ::lseek(fd, 0, SEEK_SET);
  245 +
  246 + // write http header for ts.
  247 + std::stringstream ss;
  248 +
  249 + res_status_line(ss)->res_content_type_flv(ss)
  250 + ->res_content_length(ss, (int)length);
  251 +
  252 + if (req->requires_crossdomain()) {
  253 + res_enable_crossdomain(ss);
  254 + }
  255 +
  256 + res_header_eof(ss);
  257 +
  258 + // flush http header to peer
  259 + if ((ret = res_flush(skt, ss)) != ERROR_SUCCESS) {
  260 + return ret;
  261 + }
  262 +
  263 + // write body.
  264 + int64_t left = length;
  265 + char* buf = req->http_ts_send_buffer();
  266 +
  267 + while (left > 0) {
  268 + ssize_t nread = -1;
  269 + // TODO: FIXME: use st_read.
  270 + if ((nread = ::read(fd, buf, HTTP_TS_SEND_BUFFER_SIZE)) < 0) {
  271 + ret = ERROR_HTTP_READ_FILE;
  272 + srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret);
  273 + break;
  274 + }
  275 +
  276 + left -= nread;
  277 + if ((ret = skt->write(buf, nread, NULL)) != ERROR_SUCCESS) {
  278 + break;
  279 + }
  280 + }
  281 + ::close(fd);
  282 +
  283 + return ret;
  284 +}
  285 +
228 int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string fullpath) 286 int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string fullpath)
229 { 287 {
230 int ret = ERROR_SUCCESS; 288 int ret = ERROR_SUCCESS;
@@ -266,10 +324,9 @@ int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string f @@ -266,10 +324,9 @@ int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string f
266 ssize_t nread = -1; 324 ssize_t nread = -1;
267 // TODO: FIXME: use st_read. 325 // TODO: FIXME: use st_read.
268 if ((nread = ::read(fd, buf, HTTP_TS_SEND_BUFFER_SIZE)) < 0) { 326 if ((nread = ::read(fd, buf, HTTP_TS_SEND_BUFFER_SIZE)) < 0) {
269 - ::close(fd);  
270 ret = ERROR_HTTP_READ_FILE; 327 ret = ERROR_HTTP_READ_FILE;
271 srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); 328 srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret);
272 - return ret; 329 + break;
273 } 330 }
274 331
275 left -= nread; 332 left -= nread;
@@ -71,6 +71,7 @@ protected: @@ -71,6 +71,7 @@ protected:
71 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); 71 virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req);
72 private: 72 private:
73 virtual int response_regular_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); 73 virtual int response_regular_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath);
  74 + virtual int response_flv_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath);
74 virtual int response_ts_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); 75 virtual int response_ts_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath);
75 virtual std::string get_request_file(SrsHttpMessage* req); 76 virtual std::string get_request_file(SrsHttpMessage* req);
76 public: 77 public:
@@ -53,7 +53,7 @@ SrsIngester::SrsIngester() @@ -53,7 +53,7 @@ SrsIngester::SrsIngester()
53 { 53 {
54 _srs_config->subscribe(this); 54 _srs_config->subscribe(this);
55 55
56 - pthread = new SrsThread(this, SRS_AUTO_INGESTER_SLEEP_US); 56 + pthread = new SrsThread(this, SRS_AUTO_INGESTER_SLEEP_US, true);
57 pithy_print = new SrsPithyPrint(SRS_STAGE_INGESTER); 57 pithy_print = new SrsPithyPrint(SRS_STAGE_INGESTER);
58 } 58 }
59 59
@@ -84,7 +84,7 @@ SrsListener::SrsListener(SrsServer* server, SrsListenerType type) @@ -84,7 +84,7 @@ SrsListener::SrsListener(SrsServer* server, SrsListenerType type)
84 _server = server; 84 _server = server;
85 _type = type; 85 _type = type;
86 86
87 - pthread = new SrsThread(this, 0); 87 + pthread = new SrsThread(this, 0, true);
88 } 88 }
89 89
90 SrsListener::~SrsListener() 90 SrsListener::~SrsListener()
@@ -197,7 +197,7 @@ SrsSignalManager::SrsSignalManager(SrsServer* server) @@ -197,7 +197,7 @@ SrsSignalManager::SrsSignalManager(SrsServer* server)
197 197
198 _server = server; 198 _server = server;
199 sig_pipe[0] = sig_pipe[1] = -1; 199 sig_pipe[0] = sig_pipe[1] = -1;
200 - pthread = new SrsThread(this, 0); 200 + pthread = new SrsThread(this, 0, true);
201 signal_read_stfd = NULL; 201 signal_read_stfd = NULL;
202 } 202 }
203 203
@@ -54,7 +54,7 @@ void ISrsThreadHandler::on_thread_stop() @@ -54,7 +54,7 @@ void ISrsThreadHandler::on_thread_stop()
54 { 54 {
55 } 55 }
56 56
57 -SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us) 57 +SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable)
58 { 58 {
59 handler = thread_handler; 59 handler = thread_handler;
60 cycle_interval_us = interval_us; 60 cycle_interval_us = interval_us;
@@ -62,6 +62,7 @@ SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us) @@ -62,6 +62,7 @@ SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us)
62 tid = NULL; 62 tid = NULL;
63 loop = false; 63 loop = false;
64 _cid = -1; 64 _cid = -1;
  65 + _joinable = joinable;
65 } 66 }
66 67
67 SrsThread::~SrsThread() 68 SrsThread::~SrsThread()
@@ -83,7 +84,7 @@ int SrsThread::start() @@ -83,7 +84,7 @@ int SrsThread::start()
83 return ret; 84 return ret;
84 } 85 }
85 86
86 - if((tid = st_thread_create(thread_fun, this, 1, 0)) == NULL){ 87 + if((tid = st_thread_create(thread_fun, this, (_joinable? 1:0), 0)) == NULL){
87 ret = ERROR_ST_CREATE_CYCLE_THREAD; 88 ret = ERROR_ST_CREATE_CYCLE_THREAD;
88 srs_error("st_thread_create failed. ret=%d", ret); 89 srs_error("st_thread_create failed. ret=%d", ret);
89 return ret; 90 return ret;
@@ -93,7 +94,7 @@ int SrsThread::start() @@ -93,7 +94,7 @@ int SrsThread::start()
93 loop = true; 94 loop = true;
94 95
95 // wait for cid to ready, for parent thread to get the cid. 96 // wait for cid to ready, for parent thread to get the cid.
96 - while (_cid < 0) { 97 + while (_cid < 0 && loop) {
97 st_usleep(10 * SRS_TIME_MILLISECONDS); 98 st_usleep(10 * SRS_TIME_MILLISECONDS);
98 } 99 }
99 100
@@ -88,6 +88,7 @@ private: @@ -88,6 +88,7 @@ private:
88 st_thread_t tid; 88 st_thread_t tid;
89 int _cid; 89 int _cid;
90 bool loop; 90 bool loop;
  91 + bool _joinable;
91 private: 92 private:
92 ISrsThreadHandler* handler; 93 ISrsThreadHandler* handler;
93 int64_t cycle_interval_us; 94 int64_t cycle_interval_us;
@@ -96,8 +97,15 @@ public: @@ -96,8 +97,15 @@ public:
96 * initialize the thread. 97 * initialize the thread.
97 * @param thread_handler, the cycle handler for the thread. 98 * @param thread_handler, the cycle handler for the thread.
98 * @param interval_us, the sleep interval when cycle finished. 99 * @param interval_us, the sleep interval when cycle finished.
  100 + * @param joinable, if joinable, other thread must stop the thread.
  101 + * @remark if joinable, thread never quit itself, or memory leak.
  102 + * @see: https://github.com/winlinvip/simple-rtmp-server/issues/78
99 */ 103 */
100 - SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us); 104 + /**
  105 + * TODO: FIXME: maybe all thread must be reap by others threads,
  106 + * @see: https://github.com/winlinvip/simple-rtmp-server/issues/77
  107 + */
  108 + SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable);
101 virtual ~SrsThread(); 109 virtual ~SrsThread();
102 public: 110 public:
103 /** 111 /**
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR "0" 32 #define VERSION_MAJOR "0"
33 #define VERSION_MINOR "9" 33 #define VERSION_MINOR "9"
34 -#define VERSION_REVISION "112" 34 +#define VERSION_REVISION "113"
35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION 35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "SRS" 37 #define RTMP_SIG_SRS_KEY "SRS"