mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Merge branch '2.0release' into develop
This commit is contained in:
commit
478873fdec
48 changed files with 3634 additions and 2988 deletions
|
@ -566,6 +566,7 @@ Supported operating systems and hardware:
|
|||
|
||||
### SRS 2.0 history
|
||||
|
||||
* v2.0, 2015-05-23, fix [#391](https://github.com/simple-rtmp-server/srs/issues/391) copy request for async call.
|
||||
* v2.0, 2015-05-22, fix [#397](https://github.com/simple-rtmp-server/srs/issues/397) the USER_HZ maybe not 100. 2.0.165
|
||||
* v2.0, 2015-05-22, for [#400](https://github.com/simple-rtmp-server/srs/issues/400), parse when got entire http header, by feilong. 2.0.164.
|
||||
* v2.0, 2015-05-19, merge from bravo system, add the rtmfp to bms(commercial srs). 2.0.163.
|
||||
|
|
4
trunk/configure
vendored
4
trunk/configure
vendored
|
@ -159,7 +159,7 @@ MODULE_DEPENDS=("CORE" "KERNEL")
|
|||
ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot})
|
||||
MODULE_FILES=("srs_rtmp_amf0" "srs_rtmp_io" "srs_rtmp_stack" "srs_rtmp_sdk"
|
||||
"srs_rtmp_handshake" "srs_rtmp_utility" "srs_rtmp_msg_array" "srs_rtmp_buffer"
|
||||
"srs_raw_avc" "srs_rtsp_stack")
|
||||
"srs_raw_avc" "srs_rtsp_stack" "srs_http_stack")
|
||||
RTMP_INCS="src/protocol"; MODULE_DIR=${RTMP_INCS} . auto/modules.sh
|
||||
RTMP_OBJS="${MODULE_OBJS[@]}"
|
||||
#
|
||||
|
@ -169,7 +169,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
|
|||
MODULE_DEPENDS=("CORE" "KERNEL" "RTMP")
|
||||
ModuleLibIncs=(${LibSTRoot} ${LibHttpParserRoot} ${SRS_OBJS_DIR})
|
||||
MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_st_socket" "srs_app_source"
|
||||
"srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http"
|
||||
"srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder"
|
||||
"srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config"
|
||||
"srs_app_pithy_print" "srs_app_reload" "srs_app_http_api" "srs_app_http_conn" "srs_app_http_hooks"
|
||||
"srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge"
|
||||
|
|
|
@ -46,6 +46,8 @@ file
|
|||
../../src/kernel/srs_kernel_utility.hpp,
|
||||
../../src/kernel/srs_kernel_utility.cpp,
|
||||
protocol readonly separator,
|
||||
../../src/protocol/srs_http_stack.hpp,
|
||||
../../src/protocol/srs_http_stack.cpp,
|
||||
../../src/protocol/srs_raw_avc.hpp,
|
||||
../../src/protocol/srs_raw_avc.cpp,
|
||||
../../src/protocol/srs_rtmp_amf0.hpp,
|
||||
|
@ -91,8 +93,6 @@ file
|
|||
../../src/app/srs_app_heartbeat.cpp,
|
||||
../../src/app/srs_app_hls.hpp,
|
||||
../../src/app/srs_app_hls.cpp,
|
||||
../../src/app/srs_app_http.hpp,
|
||||
../../src/app/srs_app_http.cpp,
|
||||
../../src/app/srs_app_http_api.hpp,
|
||||
../../src/app/srs_app_http_api.cpp,
|
||||
../../src/app/srs_app_http_client.hpp,
|
||||
|
|
|
@ -74,7 +74,6 @@
|
|||
<ClInclude Include="..\..\src\app\srs_app_forward.hpp" />
|
||||
<ClInclude Include="..\..\src\app\srs_app_heartbeat.hpp" />
|
||||
<ClInclude Include="..\..\src\app\srs_app_hls.hpp" />
|
||||
<ClInclude Include="..\..\src\app\srs_app_http.hpp" />
|
||||
<ClInclude Include="..\..\src\app\srs_app_http_api.hpp" />
|
||||
<ClInclude Include="..\..\src\app\srs_app_http_client.hpp" />
|
||||
<ClInclude Include="..\..\src\app\srs_app_http_conn.hpp" />
|
||||
|
@ -119,6 +118,7 @@
|
|||
<ClInclude Include="..\..\src\libs\srs_librtmp.hpp" />
|
||||
<ClInclude Include="..\..\src\libs\srs_lib_bandwidth.hpp" />
|
||||
<ClInclude Include="..\..\src\libs\srs_lib_simple_socket.hpp" />
|
||||
<ClInclude Include="..\..\src\protocol\srs_http_stack.hpp" />
|
||||
<ClInclude Include="..\..\src\protocol\srs_raw_avc.hpp" />
|
||||
<ClInclude Include="..\..\src\protocol\srs_rtmp_amf0.hpp" />
|
||||
<ClInclude Include="..\..\src\protocol\srs_rtmp_buffer.hpp" />
|
||||
|
@ -155,7 +155,6 @@
|
|||
<ClCompile Include="..\..\src\app\srs_app_forward.cpp" />
|
||||
<ClCompile Include="..\..\src\app\srs_app_heartbeat.cpp" />
|
||||
<ClCompile Include="..\..\src\app\srs_app_hls.cpp" />
|
||||
<ClCompile Include="..\..\src\app\srs_app_http.cpp" />
|
||||
<ClCompile Include="..\..\src\app\srs_app_http_api.cpp" />
|
||||
<ClCompile Include="..\..\src\app\srs_app_http_client.cpp" />
|
||||
<ClCompile Include="..\..\src\app\srs_app_http_conn.cpp" />
|
||||
|
@ -201,6 +200,7 @@
|
|||
<ClCompile Include="..\..\src\libs\srs_lib_bandwidth.cpp" />
|
||||
<ClCompile Include="..\..\src\libs\srs_lib_simple_socket.cpp" />
|
||||
<ClCompile Include="..\..\src\main\srs_main_server.cpp" />
|
||||
<ClCompile Include="..\..\src\protocol\srs_http_stack.cpp" />
|
||||
<ClCompile Include="..\..\src\protocol\srs_raw_avc.cpp" />
|
||||
<ClCompile Include="..\..\src\protocol\srs_rtmp_amf0.cpp" />
|
||||
<ClCompile Include="..\..\src\protocol\srs_rtmp_buffer.cpp" />
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3C0E1B8D1B0F5ADF003ADEF7 /* srs_http_stack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C0E1B8B1B0F5ADF003ADEF7 /* srs_http_stack.cpp */; };
|
||||
3C1231F61AAE652D00CE8F6C /* srs_core_autofree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1231F01AAE652C00CE8F6C /* srs_core_autofree.cpp */; };
|
||||
3C1231F71AAE652D00CE8F6C /* srs_core_performance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1231F21AAE652C00CE8F6C /* srs_core_performance.cpp */; };
|
||||
3C1231F81AAE652D00CE8F6C /* srs_core.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1231F41AAE652D00CE8F6C /* srs_core.cpp */; };
|
||||
|
@ -48,7 +49,6 @@
|
|||
3C1232A01AAE81D900CE8F6C /* srs_app_http_client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1232641AAE81D900CE8F6C /* srs_app_http_client.cpp */; };
|
||||
3C1232A11AAE81D900CE8F6C /* srs_app_http_conn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1232661AAE81D900CE8F6C /* srs_app_http_conn.cpp */; };
|
||||
3C1232A21AAE81D900CE8F6C /* srs_app_http_hooks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1232681AAE81D900CE8F6C /* srs_app_http_hooks.cpp */; };
|
||||
3C1232A31AAE81D900CE8F6C /* srs_app_http.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C12326A1AAE81D900CE8F6C /* srs_app_http.cpp */; };
|
||||
3C1232A41AAE81D900CE8F6C /* srs_app_ingest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C12326C1AAE81D900CE8F6C /* srs_app_ingest.cpp */; };
|
||||
3C1232A51AAE81D900CE8F6C /* srs_app_json.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C12326E1AAE81D900CE8F6C /* srs_app_json.cpp */; };
|
||||
3C1232A61AAE81D900CE8F6C /* srs_app_kbps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1232701AAE81D900CE8F6C /* srs_app_kbps.cpp */; };
|
||||
|
@ -122,6 +122,8 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
3C0E1B8B1B0F5ADF003ADEF7 /* srs_http_stack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_http_stack.cpp; path = ../../../src/protocol/srs_http_stack.cpp; sourceTree = "<group>"; };
|
||||
3C0E1B8C1B0F5ADF003ADEF7 /* srs_http_stack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_http_stack.hpp; path = ../../../src/protocol/srs_http_stack.hpp; sourceTree = "<group>"; };
|
||||
3C1231E51AAE64A400CE8F6C /* srs_xcode */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = srs_xcode; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3C1231F01AAE652C00CE8F6C /* srs_core_autofree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_core_autofree.cpp; path = ../../../src/core/srs_core_autofree.cpp; sourceTree = "<group>"; };
|
||||
3C1231F11AAE652C00CE8F6C /* srs_core_autofree.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_core_autofree.hpp; path = ../../../src/core/srs_core_autofree.hpp; sourceTree = "<group>"; };
|
||||
|
@ -205,8 +207,6 @@
|
|||
3C1232671AAE81D900CE8F6C /* srs_app_http_conn.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_app_http_conn.hpp; path = ../../../src/app/srs_app_http_conn.hpp; sourceTree = "<group>"; };
|
||||
3C1232681AAE81D900CE8F6C /* srs_app_http_hooks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_app_http_hooks.cpp; path = ../../../src/app/srs_app_http_hooks.cpp; sourceTree = "<group>"; };
|
||||
3C1232691AAE81D900CE8F6C /* srs_app_http_hooks.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_app_http_hooks.hpp; path = ../../../src/app/srs_app_http_hooks.hpp; sourceTree = "<group>"; };
|
||||
3C12326A1AAE81D900CE8F6C /* srs_app_http.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_app_http.cpp; path = ../../../src/app/srs_app_http.cpp; sourceTree = "<group>"; };
|
||||
3C12326B1AAE81D900CE8F6C /* srs_app_http.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_app_http.hpp; path = ../../../src/app/srs_app_http.hpp; sourceTree = "<group>"; };
|
||||
3C12326C1AAE81D900CE8F6C /* srs_app_ingest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_app_ingest.cpp; path = ../../../src/app/srs_app_ingest.cpp; sourceTree = "<group>"; };
|
||||
3C12326D1AAE81D900CE8F6C /* srs_app_ingest.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_app_ingest.hpp; path = ../../../src/app/srs_app_ingest.hpp; sourceTree = "<group>"; };
|
||||
3C12326E1AAE81D900CE8F6C /* srs_app_json.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_app_json.cpp; path = ../../../src/app/srs_app_json.cpp; sourceTree = "<group>"; };
|
||||
|
@ -487,6 +487,8 @@
|
|||
3C12322C1AAE819900CE8F6C /* protocol */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3C0E1B8B1B0F5ADF003ADEF7 /* srs_http_stack.cpp */,
|
||||
3C0E1B8C1B0F5ADF003ADEF7 /* srs_http_stack.hpp */,
|
||||
3C12322D1AAE81A400CE8F6C /* srs_raw_avc.cpp */,
|
||||
3C12322E1AAE81A400CE8F6C /* srs_raw_avc.hpp */,
|
||||
3C12322F1AAE81A400CE8F6C /* srs_rtmp_amf0.cpp */,
|
||||
|
@ -550,8 +552,6 @@
|
|||
3C1232671AAE81D900CE8F6C /* srs_app_http_conn.hpp */,
|
||||
3C1232681AAE81D900CE8F6C /* srs_app_http_hooks.cpp */,
|
||||
3C1232691AAE81D900CE8F6C /* srs_app_http_hooks.hpp */,
|
||||
3C12326A1AAE81D900CE8F6C /* srs_app_http.cpp */,
|
||||
3C12326B1AAE81D900CE8F6C /* srs_app_http.hpp */,
|
||||
3C12326C1AAE81D900CE8F6C /* srs_app_ingest.cpp */,
|
||||
3C12326D1AAE81D900CE8F6C /* srs_app_ingest.hpp */,
|
||||
3C12326E1AAE81D900CE8F6C /* srs_app_json.cpp */,
|
||||
|
@ -886,6 +886,7 @@
|
|||
3C1232411AAE81A400CE8F6C /* srs_raw_avc.cpp in Sources */,
|
||||
3C1232491AAE81A400CE8F6C /* srs_rtmp_utility.cpp in Sources */,
|
||||
3C663F191AB0155100286D8B /* srs_publish.c in Sources */,
|
||||
3C0E1B8D1B0F5ADF003ADEF7 /* srs_http_stack.cpp in Sources */,
|
||||
3C1232A01AAE81D900CE8F6C /* srs_app_http_client.cpp in Sources */,
|
||||
3C689F981AB6AAAC00C9CEEE /* key.c in Sources */,
|
||||
3C12329B1AAE81D900CE8F6C /* srs_app_ffmpeg.cpp in Sources */,
|
||||
|
@ -936,7 +937,6 @@
|
|||
3C1232AF1AAE81D900CE8F6C /* srs_app_rtsp.cpp in Sources */,
|
||||
3CC52DDD1ACE4023006FEB01 /* srs_utest_reload.cpp in Sources */,
|
||||
3C689FA11AB6AAC800C9CEEE /* sync.c in Sources */,
|
||||
3C1232A31AAE81D900CE8F6C /* srs_app_http.cpp in Sources */,
|
||||
3C12329A1AAE81D900CE8F6C /* srs_app_encoder.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -31,65 +31,64 @@ using namespace std;
|
|||
// the sleep interval for http async callback.
|
||||
#define SRS_AUTO_ASYNC_CALLBACL_SLEEP_US 300000
|
||||
|
||||
ISrsDvrAsyncCall::ISrsDvrAsyncCall()
|
||||
ISrsAsyncCallTask::ISrsAsyncCallTask()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsDvrAsyncCall::~ISrsDvrAsyncCall()
|
||||
ISrsAsyncCallTask::~ISrsAsyncCallTask()
|
||||
{
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallThread::SrsDvrAsyncCallThread()
|
||||
SrsAsyncCallWorker::SrsAsyncCallWorker()
|
||||
{
|
||||
pthread = new SrsThread("async", this, SRS_AUTO_ASYNC_CALLBACL_SLEEP_US, true);
|
||||
pthread = new SrsReusableThread("async", this, SRS_AUTO_ASYNC_CALLBACL_SLEEP_US);
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallThread::~SrsDvrAsyncCallThread()
|
||||
SrsAsyncCallWorker::~SrsAsyncCallWorker()
|
||||
{
|
||||
stop();
|
||||
srs_freep(pthread);
|
||||
|
||||
std::vector<ISrsDvrAsyncCall*>::iterator it;
|
||||
for (it = callbacks.begin(); it != callbacks.end(); ++it) {
|
||||
ISrsDvrAsyncCall* call = *it;
|
||||
srs_freep(call);
|
||||
std::vector<ISrsAsyncCallTask*>::iterator it;
|
||||
for (it = tasks.begin(); it != tasks.end(); ++it) {
|
||||
ISrsAsyncCallTask* task = *it;
|
||||
srs_freep(task);
|
||||
}
|
||||
callbacks.clear();
|
||||
tasks.clear();
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallThread::call(ISrsDvrAsyncCall* c)
|
||||
int SrsAsyncCallWorker::execute(ISrsAsyncCallTask* t)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
callbacks.push_back(c);
|
||||
tasks.push_back(t);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallThread::start()
|
||||
int SrsAsyncCallWorker::start()
|
||||
{
|
||||
return pthread->start();
|
||||
}
|
||||
|
||||
void SrsDvrAsyncCallThread::stop()
|
||||
void SrsAsyncCallWorker::stop()
|
||||
{
|
||||
pthread->stop();
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallThread::cycle()
|
||||
int SrsAsyncCallWorker::cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::vector<ISrsDvrAsyncCall*> copies = callbacks;
|
||||
callbacks.clear();
|
||||
std::vector<ISrsAsyncCallTask*> copies = tasks;
|
||||
tasks.clear();
|
||||
|
||||
std::vector<ISrsDvrAsyncCall*>::iterator it;
|
||||
std::vector<ISrsAsyncCallTask*>::iterator it;
|
||||
for (it = copies.begin(); it != copies.end(); ++it) {
|
||||
ISrsDvrAsyncCall* call = *it;
|
||||
if ((ret = call->call()) != ERROR_SUCCESS) {
|
||||
srs_warn("ignore async callback %s, ret=%d", call->to_string().c_str(), ret);
|
||||
ISrsAsyncCallTask* task = *it;
|
||||
if ((ret = task->call()) != ERROR_SUCCESS) {
|
||||
srs_warn("ignore async callback %s, ret=%d", task->to_string().c_str(), ret);
|
||||
}
|
||||
srs_freep(call);
|
||||
srs_freep(task);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -42,32 +42,36 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
* a video and pass it to the dvr again.
|
||||
* futhurmore, the aync call never block the main worker thread.
|
||||
*/
|
||||
class ISrsDvrAsyncCall
|
||||
class ISrsAsyncCallTask
|
||||
{
|
||||
public:
|
||||
ISrsDvrAsyncCall();
|
||||
virtual ~ISrsDvrAsyncCall();
|
||||
ISrsAsyncCallTask();
|
||||
virtual ~ISrsAsyncCallTask();
|
||||
public:
|
||||
virtual int call() = 0;
|
||||
virtual std::string to_string() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* the async callback for dvr.
|
||||
*/
|
||||
class SrsDvrAsyncCallThread : public ISrsThreadHandler
|
||||
* the async callback for dvr.
|
||||
* when worker call with the task, the worker will do it in isolate thread.
|
||||
* that is, the task is execute/call in async mode.
|
||||
*/
|
||||
class SrsAsyncCallWorker : public ISrsReusableThreadHandler
|
||||
{
|
||||
private:
|
||||
SrsThread* pthread;
|
||||
std::vector<ISrsDvrAsyncCall*> callbacks;
|
||||
SrsReusableThread* pthread;
|
||||
std::vector<ISrsAsyncCallTask*> tasks;
|
||||
public:
|
||||
SrsDvrAsyncCallThread();
|
||||
virtual ~SrsDvrAsyncCallThread();
|
||||
SrsAsyncCallWorker();
|
||||
virtual ~SrsAsyncCallWorker();
|
||||
public:
|
||||
virtual int call(ISrsDvrAsyncCall* c);
|
||||
virtual int execute(ISrsAsyncCallTask* t);
|
||||
public:
|
||||
virtual int start();
|
||||
virtual void stop();
|
||||
// interface ISrsReusableThreadHandler
|
||||
public:
|
||||
virtual int cycle();
|
||||
};
|
||||
|
||||
|
|
|
@ -45,12 +45,17 @@ SrsConnection::SrsConnection(IConnectionManager* cm, st_netfd_t c)
|
|||
// so we never use joinable.
|
||||
// TODO: FIXME: maybe other thread need to stop it.
|
||||
// @see: https://github.com/simple-rtmp-server/srs/issues/78
|
||||
pthread = new SrsThread("conn", this, 0, false);
|
||||
pthread = new SrsOneCycleThread("conn", this);
|
||||
}
|
||||
|
||||
SrsConnection::~SrsConnection()
|
||||
{
|
||||
stop();
|
||||
/**
|
||||
* when delete the connection, stop the connection,
|
||||
* close the underlayer socket, delete the thread.
|
||||
*/
|
||||
srs_close_stfd(stfd);
|
||||
srs_freep(pthread);
|
||||
}
|
||||
|
||||
int SrsConnection::start()
|
||||
|
@ -83,9 +88,6 @@ int SrsConnection::cycle()
|
|||
if (ret == ERROR_SOCKET_CLOSED) {
|
||||
srs_warn("client disconnect peer. ret=%d", ret);
|
||||
}
|
||||
|
||||
// set loop to stop to quit.
|
||||
pthread->stop_loop();
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -101,10 +103,4 @@ int SrsConnection::srs_id()
|
|||
return id;
|
||||
}
|
||||
|
||||
void SrsConnection::stop()
|
||||
{
|
||||
srs_close_stfd(stfd);
|
||||
srs_freep(pthread);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -58,14 +58,14 @@ public:
|
|||
* all connections accept from listener must extends from this base class,
|
||||
* server will add the connection to manager, and delete it when remove.
|
||||
*/
|
||||
class SrsConnection : public virtual ISrsThreadHandler, public virtual IKbpsDelta
|
||||
class SrsConnection : public virtual ISrsOneCycleThreadHandler, public virtual IKbpsDelta
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* each connection start a green thread,
|
||||
* when thread stop, the connection will be delete by server.
|
||||
*/
|
||||
SrsThread* pthread;
|
||||
SrsOneCycleThread* pthread;
|
||||
/**
|
||||
* the id of connection.
|
||||
*/
|
||||
|
@ -97,6 +97,8 @@ public:
|
|||
* to remove the client by server->remove(this).
|
||||
*/
|
||||
virtual int start();
|
||||
// interface ISrsOneCycleThreadHandler
|
||||
public:
|
||||
/**
|
||||
* the thread cycle function,
|
||||
* when serve connection completed, terminate the loop which will terminate the thread,
|
||||
|
@ -119,12 +121,6 @@ protected:
|
|||
* for concrete connection to do the cycle.
|
||||
*/
|
||||
virtual int do_cycle() = 0;
|
||||
private:
|
||||
/**
|
||||
* when delete the connection, stop the connection,
|
||||
* close the underlayer socket, delete the thread.
|
||||
*/
|
||||
virtual void stop();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -498,12 +498,13 @@ int SrsFlvSegment::on_reload_vhost_dvr(std::string /*vhost*/)
|
|||
|
||||
SrsDvrAsyncCallOnDvr::SrsDvrAsyncCallOnDvr(SrsRequest* r, string p)
|
||||
{
|
||||
req = r;
|
||||
req = r->copy();
|
||||
path = p;
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallOnDvr::~SrsDvrAsyncCallOnDvr()
|
||||
{
|
||||
srs_freep(req);
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallOnDvr::call()
|
||||
|
@ -547,7 +548,7 @@ SrsDvrPlan::SrsDvrPlan()
|
|||
|
||||
dvr_enabled = false;
|
||||
segment = new SrsFlvSegment(this);
|
||||
async = new SrsDvrAsyncCallThread();
|
||||
async = new SrsAsyncCallWorker();
|
||||
}
|
||||
|
||||
SrsDvrPlan::~SrsDvrPlan()
|
||||
|
@ -628,7 +629,7 @@ int SrsDvrPlan::on_reap_segment()
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if ((ret = async->call(new SrsDvrAsyncCallOnDvr(req, segment->get_path()))) != ERROR_SUCCESS) {
|
||||
if ((ret = async->execute(new SrsDvrAsyncCallOnDvr(req, segment->get_path()))) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ public:
|
|||
/**
|
||||
* the dvr async call.
|
||||
*/
|
||||
class SrsDvrAsyncCallOnDvr : public ISrsDvrAsyncCall
|
||||
class SrsDvrAsyncCallOnDvr : public ISrsAsyncCallTask
|
||||
{
|
||||
private:
|
||||
std::string path;
|
||||
|
@ -206,7 +206,7 @@ public:
|
|||
SrsRequest* req;
|
||||
protected:
|
||||
SrsFlvSegment* segment;
|
||||
SrsDvrAsyncCallThread* async;
|
||||
SrsAsyncCallWorker* async;
|
||||
bool dvr_enabled;
|
||||
public:
|
||||
SrsDvrPlan();
|
||||
|
|
|
@ -70,7 +70,7 @@ SrsEdgeIngester::SrsEdgeIngester()
|
|||
origin_index = 0;
|
||||
stream_id = 0;
|
||||
stfd = NULL;
|
||||
pthread = new SrsThread("edge-igs", this, SRS_EDGE_INGESTER_SLEEP_US, true);
|
||||
pthread = new SrsReusableThread2("edge-igs", this, SRS_EDGE_INGESTER_SLEEP_US);
|
||||
}
|
||||
|
||||
SrsEdgeIngester::~SrsEdgeIngester()
|
||||
|
@ -171,7 +171,7 @@ int SrsEdgeIngester::ingest()
|
|||
SrsPithyPrint* pprint = SrsPithyPrint::create_edge();
|
||||
SrsAutoFree(SrsPithyPrint, pprint);
|
||||
|
||||
while (pthread->can_loop()) {
|
||||
while (!pthread->interrupted()) {
|
||||
pprint->elapse();
|
||||
|
||||
// pithy print
|
||||
|
@ -397,7 +397,7 @@ SrsEdgeForwarder::SrsEdgeForwarder()
|
|||
origin_index = 0;
|
||||
stream_id = 0;
|
||||
stfd = NULL;
|
||||
pthread = new SrsThread("edge-fwr", this, SRS_EDGE_FORWARDER_SLEEP_US, true);
|
||||
pthread = new SrsReusableThread2("edge-fwr", this, SRS_EDGE_FORWARDER_SLEEP_US);
|
||||
queue = new SrsMessageQueue();
|
||||
send_error_code = ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ int SrsEdgeForwarder::cycle()
|
|||
|
||||
SrsMessageArray msgs(SYS_MAX_EDGE_SEND_MSGS);
|
||||
|
||||
while (pthread->can_loop()) {
|
||||
while (!pthread->interrupted()) {
|
||||
if (send_error_code != ERROR_SUCCESS) {
|
||||
st_usleep(SRS_EDGE_FORWARDER_ERROR_US);
|
||||
continue;
|
||||
|
|
|
@ -75,7 +75,7 @@ enum SrsEdgeUserState
|
|||
/**
|
||||
* edge used to ingest stream from origin.
|
||||
*/
|
||||
class SrsEdgeIngester : public ISrsThreadHandler
|
||||
class SrsEdgeIngester : public ISrsReusableThread2Handler
|
||||
{
|
||||
private:
|
||||
int stream_id;
|
||||
|
@ -83,7 +83,7 @@ private:
|
|||
SrsSource* _source;
|
||||
SrsPlayEdge* _edge;
|
||||
SrsRequest* _req;
|
||||
SrsThread* pthread;
|
||||
SrsReusableThread2* pthread;
|
||||
st_netfd_t stfd;
|
||||
ISrsProtocolReaderWriter* io;
|
||||
SrsKbps* kbps;
|
||||
|
@ -96,7 +96,7 @@ public:
|
|||
virtual int initialize(SrsSource* source, SrsPlayEdge* edge, SrsRequest* req);
|
||||
virtual int start();
|
||||
virtual void stop();
|
||||
// interface ISrsThreadHandler
|
||||
// interface ISrsReusableThread2Handler
|
||||
public:
|
||||
virtual int cycle();
|
||||
private:
|
||||
|
@ -110,7 +110,7 @@ private:
|
|||
/**
|
||||
* edge used to forward stream to origin.
|
||||
*/
|
||||
class SrsEdgeForwarder : public ISrsThreadHandler
|
||||
class SrsEdgeForwarder : public ISrsReusableThread2Handler
|
||||
{
|
||||
private:
|
||||
int stream_id;
|
||||
|
@ -118,7 +118,7 @@ private:
|
|||
SrsSource* _source;
|
||||
SrsPublishEdge* _edge;
|
||||
SrsRequest* _req;
|
||||
SrsThread* pthread;
|
||||
SrsReusableThread2* pthread;
|
||||
st_netfd_t stfd;
|
||||
ISrsProtocolReaderWriter* io;
|
||||
SrsKbps* kbps;
|
||||
|
@ -144,7 +144,7 @@ public:
|
|||
virtual int initialize(SrsSource* source, SrsPublishEdge* edge, SrsRequest* req);
|
||||
virtual int start();
|
||||
virtual void stop();
|
||||
// interface ISrsThreadHandler
|
||||
// interface ISrsReusableThread2Handler
|
||||
public:
|
||||
virtual int cycle();
|
||||
public:
|
||||
|
|
|
@ -44,7 +44,7 @@ static std::vector<std::string> _transcoded_url;
|
|||
|
||||
SrsEncoder::SrsEncoder()
|
||||
{
|
||||
pthread = new SrsThread("encoder", this, SRS_RTMP_ENCODER_SLEEP_US, true);
|
||||
pthread = new SrsReusableThread("encoder", this, SRS_RTMP_ENCODER_SLEEP_US);
|
||||
pprint = SrsPithyPrint::create_encoder();
|
||||
}
|
||||
|
||||
|
|
|
@ -45,13 +45,13 @@ class SrsFFMPEG;
|
|||
* the encoder for a stream,
|
||||
* may use multiple ffmpegs to transcode the specified stream.
|
||||
*/
|
||||
class SrsEncoder : public ISrsThreadHandler
|
||||
class SrsEncoder : public ISrsReusableThreadHandler
|
||||
{
|
||||
private:
|
||||
std::string input_stream_name;
|
||||
std::vector<SrsFFMPEG*> ffmpegs;
|
||||
private:
|
||||
SrsThread* pthread;
|
||||
SrsReusableThread* pthread;
|
||||
SrsPithyPrint* pprint;
|
||||
public:
|
||||
SrsEncoder();
|
||||
|
@ -59,7 +59,7 @@ public:
|
|||
public:
|
||||
virtual int on_publish(SrsRequest* req);
|
||||
virtual void on_unpublish();
|
||||
// interface ISrsThreadHandler.
|
||||
// interface ISrsReusableThreadHandler.
|
||||
public:
|
||||
virtual int cycle();
|
||||
virtual void on_thread_stop();
|
||||
|
|
|
@ -59,7 +59,7 @@ SrsForwarder::SrsForwarder(SrsSource* _source)
|
|||
kbps = new SrsKbps();
|
||||
stream_id = 0;
|
||||
|
||||
pthread = new SrsThread("forward", this, SRS_FORWARDER_SLEEP_US, true);
|
||||
pthread = new SrsReusableThread2("forward", this, SRS_FORWARDER_SLEEP_US);
|
||||
queue = new SrsMessageQueue();
|
||||
jitter = new SrsRtmpJitter();
|
||||
|
||||
|
@ -407,7 +407,7 @@ int SrsForwarder::forward()
|
|||
}
|
||||
}
|
||||
|
||||
while (pthread->can_loop()) {
|
||||
while (!pthread->interrupted()) {
|
||||
pprint->elapse();
|
||||
|
||||
// read from client.
|
||||
|
|
|
@ -48,7 +48,7 @@ class SrsKbps;
|
|||
* forward the stream to other servers.
|
||||
*/
|
||||
// TODO: FIXME: refine the error log, comments it.
|
||||
class SrsForwarder : public ISrsThreadHandler
|
||||
class SrsForwarder : public ISrsReusableThread2Handler
|
||||
{
|
||||
private:
|
||||
// the ep to forward, server[:port].
|
||||
|
@ -57,7 +57,7 @@ private:
|
|||
int stream_id;
|
||||
private:
|
||||
st_netfd_t stfd;
|
||||
SrsThread* pthread;
|
||||
SrsReusableThread2* pthread;
|
||||
private:
|
||||
SrsSource* source;
|
||||
ISrsProtocolReaderWriter* io;
|
||||
|
@ -95,7 +95,7 @@ public:
|
|||
* @param shared_video, directly ptr, copy it if need to save it.
|
||||
*/
|
||||
virtual int on_video(SrsSharedPtrMessage* shared_video);
|
||||
// interface ISrsThreadHandler.
|
||||
// interface ISrsReusableThread2Handler.
|
||||
public:
|
||||
virtual int cycle();
|
||||
private:
|
||||
|
|
|
@ -33,9 +33,9 @@ using namespace std;
|
|||
#include <srs_app_config.hpp>
|
||||
#include <srs_app_http_client.hpp>
|
||||
#include <srs_app_json.hpp>
|
||||
#include <srs_app_http.hpp>
|
||||
#include <srs_app_utility.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_app_http_conn.hpp>
|
||||
|
||||
SrsHttpHeartbeat::SrsHttpHeartbeat()
|
||||
{
|
||||
|
@ -82,14 +82,14 @@ void SrsHttpHeartbeat::heartbeat()
|
|||
return;
|
||||
}
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
ISrsHttpMessage* msg = NULL;
|
||||
if ((ret = http.post(uri.get_path(), req, &msg)) != ERROR_SUCCESS) {
|
||||
srs_info("http post hartbeart uri failed. "
|
||||
"url=%s, request=%s, response=%s, ret=%d",
|
||||
url.c_str(), req.c_str(), res.c_str(), ret);
|
||||
return;
|
||||
}
|
||||
SrsAutoFree(SrsHttpMessage, msg);
|
||||
SrsAutoFree(ISrsHttpMessage, msg);
|
||||
|
||||
std::string res;
|
||||
if ((ret = msg->body_read_all(res)) != ERROR_SUCCESS) {
|
||||
|
|
|
@ -172,7 +172,7 @@ void SrsHlsSegment::update_duration(int64_t current_frame_dts)
|
|||
|
||||
SrsDvrAsyncCallOnHls::SrsDvrAsyncCallOnHls(SrsRequest* r, string p, string t, string m, string mu, int s, double d)
|
||||
{
|
||||
req = r;
|
||||
req = r->copy();
|
||||
path = p;
|
||||
ts_url = t;
|
||||
m3u8 = m;
|
||||
|
@ -183,6 +183,7 @@ SrsDvrAsyncCallOnHls::SrsDvrAsyncCallOnHls(SrsRequest* r, string p, string t, st
|
|||
|
||||
SrsDvrAsyncCallOnHls::~SrsDvrAsyncCallOnHls()
|
||||
{
|
||||
srs_freep(req);
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallOnHls::call()
|
||||
|
@ -221,12 +222,13 @@ string SrsDvrAsyncCallOnHls::to_string()
|
|||
|
||||
SrsDvrAsyncCallOnHlsNotify::SrsDvrAsyncCallOnHlsNotify(SrsRequest* r, string u)
|
||||
{
|
||||
req = r;
|
||||
req = r->copy();
|
||||
ts_url = u;
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallOnHlsNotify::~SrsDvrAsyncCallOnHlsNotify()
|
||||
{
|
||||
srs_freep(req);
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallOnHlsNotify::call()
|
||||
|
@ -284,7 +286,7 @@ SrsHlsMuxer::SrsHlsMuxer()
|
|||
acodec = SrsCodecAudioReserved1;
|
||||
should_write_cache = false;
|
||||
should_write_file = true;
|
||||
async = new SrsDvrAsyncCallThread();
|
||||
async = new SrsAsyncCallWorker();
|
||||
context = new SrsTsContext();
|
||||
}
|
||||
|
||||
|
@ -667,7 +669,7 @@ int SrsHlsMuxer::segment_close(string log_desc)
|
|||
segments.push_back(current);
|
||||
|
||||
// use async to call the http hooks, for it will cause thread switch.
|
||||
if ((ret = async->call(new SrsDvrAsyncCallOnHls(req,
|
||||
if ((ret = async->execute(new SrsDvrAsyncCallOnHls(req,
|
||||
current->full_path, current->uri, m3u8, m3u8_url,
|
||||
current->sequence_no, current->duration))) != ERROR_SUCCESS)
|
||||
{
|
||||
|
@ -675,7 +677,7 @@ int SrsHlsMuxer::segment_close(string log_desc)
|
|||
}
|
||||
|
||||
// use async to call the http hooks, for it will cause thread switch.
|
||||
if ((ret = async->call(new SrsDvrAsyncCallOnHlsNotify(req, current->uri))) != ERROR_SUCCESS) {
|
||||
if ((ret = async->execute(new SrsDvrAsyncCallOnHlsNotify(req, current->uri))) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ public:
|
|||
/**
|
||||
* the hls async call: on_hls
|
||||
*/
|
||||
class SrsDvrAsyncCallOnHls : public ISrsDvrAsyncCall
|
||||
class SrsDvrAsyncCallOnHls : public ISrsAsyncCallTask
|
||||
{
|
||||
private:
|
||||
std::string path;
|
||||
|
@ -180,7 +180,7 @@ public:
|
|||
/**
|
||||
* the hls async call: on_hls_notify
|
||||
*/
|
||||
class SrsDvrAsyncCallOnHlsNotify : public ISrsDvrAsyncCall
|
||||
class SrsDvrAsyncCallOnHlsNotify : public ISrsAsyncCallTask
|
||||
{
|
||||
private:
|
||||
std::string ts_url;
|
||||
|
@ -215,7 +215,7 @@ private:
|
|||
double hls_aof_ratio;
|
||||
double hls_fragment;
|
||||
double hls_window;
|
||||
SrsDvrAsyncCallThread* async;
|
||||
SrsAsyncCallWorker* async;
|
||||
private:
|
||||
// whether use floor algorithm for timestamp.
|
||||
bool hls_ts_floor;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,686 +0,0 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 SRS(simple-rtmp-server)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SRS_APP_HTTP_HPP
|
||||
#define SRS_APP_HTTP_HPP
|
||||
|
||||
/*
|
||||
#include <srs_app_http.hpp>
|
||||
*/
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_PARSER
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include <http_parser.h>
|
||||
|
||||
#include <srs_app_st.hpp>
|
||||
#include <srs_kernel_consts.hpp>
|
||||
|
||||
class SrsRequest;
|
||||
class SrsStSocket;
|
||||
class SrsHttpUri;
|
||||
class SrsHttpMessage;
|
||||
class SrsFileReader;
|
||||
class SrsSimpleBuffer;
|
||||
class SrsHttpMuxEntry;
|
||||
class ISrsHttpResponseWriter;
|
||||
class SrsFastBuffer;
|
||||
class SrsConnection;
|
||||
|
||||
// http specification
|
||||
// CR = <US-ASCII CR, carriage return (13)>
|
||||
#define SRS_HTTP_CR SRS_CONSTS_CR // 0x0D
|
||||
// LF = <US-ASCII LF, linefeed (10)>
|
||||
#define SRS_HTTP_LF SRS_CONSTS_LF // 0x0A
|
||||
// SP = <US-ASCII SP, space (32)>
|
||||
#define SRS_HTTP_SP ' ' // 0x20
|
||||
// HT = <US-ASCII HT, horizontal-tab (9)>
|
||||
#define SRS_HTTP_HT '\x09' // 0x09
|
||||
|
||||
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
|
||||
// protocol elements except the entity-body (see appendix 19.3 for
|
||||
// tolerant applications).
|
||||
#define SRS_HTTP_CRLF "\r\n" // 0x0D0A
|
||||
#define SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
|
||||
|
||||
// @see SrsHttpMessage._http_ts_send_buffer
|
||||
#define SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
|
||||
|
||||
// helper function: response in json format.
|
||||
extern int srs_go_http_response_json(ISrsHttpResponseWriter* w, std::string data);
|
||||
|
||||
// state of message
|
||||
enum SrsHttpParseState {
|
||||
SrsHttpParseStateInit = 0,
|
||||
SrsHttpParseStateStart,
|
||||
SrsHttpParseStateHeaderComplete,
|
||||
SrsHttpParseStateMessageComplete
|
||||
};
|
||||
|
||||
// A Header represents the key-value pairs in an HTTP header.
|
||||
class SrsHttpHeader
|
||||
{
|
||||
private:
|
||||
std::map<std::string, std::string> headers;
|
||||
public:
|
||||
SrsHttpHeader();
|
||||
virtual ~SrsHttpHeader();
|
||||
public:
|
||||
// Add adds the key, value pair to the header.
|
||||
// It appends to any existing values associated with key.
|
||||
virtual void set(std::string key, std::string value);
|
||||
// Get gets the first value associated with the given key.
|
||||
// If there are no values associated with the key, Get returns "".
|
||||
// To access multiple values of a key, access the map directly
|
||||
// with CanonicalHeaderKey.
|
||||
virtual std::string get(std::string key);
|
||||
public:
|
||||
/**
|
||||
* get the content length. -1 if not set.
|
||||
*/
|
||||
virtual int64_t content_length();
|
||||
/**
|
||||
* set the content length by header "Content-Length"
|
||||
*/
|
||||
virtual void set_content_length(int64_t size);
|
||||
public:
|
||||
/**
|
||||
* get the content type. empty string if not set.
|
||||
*/
|
||||
virtual std::string content_type();
|
||||
/**
|
||||
* set the content type by header "Content-Type"
|
||||
*/
|
||||
virtual void set_content_type(std::string ct);
|
||||
public:
|
||||
/**
|
||||
* write all headers to string stream.
|
||||
*/
|
||||
virtual void write(std::stringstream& ss);
|
||||
};
|
||||
|
||||
// A ResponseWriter interface is used by an HTTP handler to
|
||||
// construct an HTTP response.
|
||||
// Usage 1, response with specified length content:
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// std::string msg = "Hello, HTTP!";
|
||||
// w->header()->set_content_type("text/plain; charset=utf-8");
|
||||
// w->header()->set_content_length(msg.length());
|
||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->final_request(); // optional flush.
|
||||
// Usage 2, response with HTTP code only, zero content length.
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// w->header()->set_content_length(0);
|
||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
// w->final_request();
|
||||
// Usage 3, response in chunked encoding.
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// std::string msg = "Hello, HTTP!";
|
||||
// w->header()->set_content_type("application/octet-stream");
|
||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->final_request(); // required to end the chunked and flush.
|
||||
class ISrsHttpResponseWriter
|
||||
{
|
||||
public:
|
||||
ISrsHttpResponseWriter();
|
||||
virtual ~ISrsHttpResponseWriter();
|
||||
public:
|
||||
// when chunked mode,
|
||||
// final the request to complete the chunked encoding.
|
||||
// for no-chunked mode,
|
||||
// final to send request, for example, content-length is 0.
|
||||
virtual int final_request() = 0;
|
||||
|
||||
// Header returns the header map that will be sent by WriteHeader.
|
||||
// Changing the header after a call to WriteHeader (or Write) has
|
||||
// no effect.
|
||||
virtual SrsHttpHeader* header() = 0;
|
||||
|
||||
// Write writes the data to the connection as part of an HTTP reply.
|
||||
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
|
||||
// before writing the data. If the Header does not contain a
|
||||
// Content-Type line, Write adds a Content-Type set to the result of passing
|
||||
// the initial 512 bytes of written data to DetectContentType.
|
||||
// @param data, the data to send. NULL to flush header only.
|
||||
virtual int write(char* data, int size) = 0;
|
||||
|
||||
// WriteHeader sends an HTTP response header with status code.
|
||||
// If WriteHeader is not called explicitly, the first call to Write
|
||||
// will trigger an implicit WriteHeader(http.StatusOK).
|
||||
// Thus explicit calls to WriteHeader are mainly used to
|
||||
// send error codes.
|
||||
// @remark, user must set header then write or write_header.
|
||||
virtual void write_header(int code) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* the reader interface for http response.
|
||||
*/
|
||||
class ISrsHttpResponseReader
|
||||
{
|
||||
public:
|
||||
ISrsHttpResponseReader();
|
||||
virtual ~ISrsHttpResponseReader();
|
||||
public:
|
||||
/**
|
||||
* whether response read EOF.
|
||||
*/
|
||||
virtual bool eof() = 0;
|
||||
/**
|
||||
* read from the response body.
|
||||
* @param data, the buffer to read data buffer to.
|
||||
* @param nb_data, the max size of data buffer.
|
||||
* @param nb_read, the actual read size of bytes. NULL to ignore.
|
||||
* @remark when eof(), return error.
|
||||
*/
|
||||
virtual int read(char* data, int nb_data, int* nb_read) = 0;
|
||||
};
|
||||
|
||||
// Objects implementing the Handler interface can be
|
||||
// registered to serve a particular path or subtree
|
||||
// in the HTTP server.
|
||||
//
|
||||
// ServeHTTP should write reply headers and data to the ResponseWriter
|
||||
// and then return. Returning signals that the request is finished
|
||||
// and that the HTTP server can move on to the next request on
|
||||
// the connection.
|
||||
class ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsHttpMuxEntry* entry;
|
||||
public:
|
||||
ISrsHttpHandler();
|
||||
virtual ~ISrsHttpHandler();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r) = 0;
|
||||
};
|
||||
|
||||
// Redirect to a fixed URL
|
||||
class SrsHttpRedirectHandler : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
std::string url;
|
||||
int code;
|
||||
public:
|
||||
SrsHttpRedirectHandler(std::string u, int c);
|
||||
virtual ~SrsHttpRedirectHandler();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
// NotFound replies to the request with an HTTP 404 not found error.
|
||||
class SrsHttpNotFoundHandler : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsHttpNotFoundHandler();
|
||||
virtual ~SrsHttpNotFoundHandler();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
// FileServer returns a handler that serves HTTP requests
|
||||
// with the contents of the file system rooted at root.
|
||||
//
|
||||
// To use the operating system's file system implementation,
|
||||
// use http.Dir:
|
||||
//
|
||||
// http.Handle("/", SrsHttpFileServer("/tmp"))
|
||||
// http.Handle("/", SrsHttpFileServer("static-dir"))
|
||||
class SrsHttpFileServer : public ISrsHttpHandler
|
||||
{
|
||||
protected:
|
||||
std::string dir;
|
||||
public:
|
||||
SrsHttpFileServer(std::string root_dir);
|
||||
virtual ~SrsHttpFileServer();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
private:
|
||||
/**
|
||||
* serve the file by specified path
|
||||
*/
|
||||
virtual int serve_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
||||
virtual int serve_flv_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
||||
virtual int serve_mp4_file(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath);
|
||||
protected:
|
||||
/**
|
||||
* when access flv file with x.flv?start=xxx
|
||||
*/
|
||||
virtual int serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
||||
/**
|
||||
* when access mp4 file with x.mp4?range=start-end
|
||||
* @param start the start offset in bytes.
|
||||
* @param end the end offset in bytes. -1 to end of file.
|
||||
* @remark response data in [start, end].
|
||||
*/
|
||||
virtual int serve_mp4_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||
protected:
|
||||
/**
|
||||
* copy the fs to response writer in size bytes.
|
||||
*/
|
||||
virtual int copy(ISrsHttpResponseWriter* w, SrsFileReader* fs, SrsHttpMessage* r, int size);
|
||||
};
|
||||
|
||||
// the mux entry for server mux.
|
||||
// the matcher info, for example, the pattern and handler.
|
||||
class SrsHttpMuxEntry
|
||||
{
|
||||
public:
|
||||
bool explicit_match;
|
||||
ISrsHttpHandler* handler;
|
||||
std::string pattern;
|
||||
bool enabled;
|
||||
public:
|
||||
SrsHttpMuxEntry();
|
||||
virtual ~SrsHttpMuxEntry();
|
||||
};
|
||||
|
||||
/**
|
||||
* the hijacker for http pattern match.
|
||||
*/
|
||||
class ISrsHttpMatchHijacker
|
||||
{
|
||||
public:
|
||||
ISrsHttpMatchHijacker();
|
||||
virtual ~ISrsHttpMatchHijacker();
|
||||
public:
|
||||
/**
|
||||
* when match the request failed, no handler to process request.
|
||||
* @param request the http request message to match the handler.
|
||||
* @param ph the already matched handler, hijack can rewrite it.
|
||||
*/
|
||||
virtual int hijack(SrsHttpMessage* request, ISrsHttpHandler** ph) = 0;
|
||||
};
|
||||
|
||||
// ServeMux is an HTTP request multiplexer.
|
||||
// It matches the URL of each incoming request against a list of registered
|
||||
// patterns and calls the handler for the pattern that
|
||||
// most closely matches the URL.
|
||||
//
|
||||
// Patterns name fixed, rooted paths, like "/favicon.ico",
|
||||
// or rooted subtrees, like "/images/" (note the trailing slash).
|
||||
// Longer patterns take precedence over shorter ones, so that
|
||||
// if there are handlers registered for both "/images/"
|
||||
// and "/images/thumbnails/", the latter handler will be
|
||||
// called for paths beginning "/images/thumbnails/" and the
|
||||
// former will receive requests for any other paths in the
|
||||
// "/images/" subtree.
|
||||
//
|
||||
// Note that since a pattern ending in a slash names a rooted subtree,
|
||||
// the pattern "/" matches all paths not matched by other registered
|
||||
// patterns, not just the URL with Path == "/".
|
||||
//
|
||||
// Patterns may optionally begin with a host name, restricting matches to
|
||||
// URLs on that host only. Host-specific patterns take precedence over
|
||||
// general patterns, so that a handler might register for the two patterns
|
||||
// "/codesearch" and "codesearch.google.com/" without also taking over
|
||||
// requests for "http://www.google.com/".
|
||||
//
|
||||
// ServeMux also takes care of sanitizing the URL request path,
|
||||
// redirecting any request containing . or .. elements to an
|
||||
// equivalent .- and ..-free URL.
|
||||
class SrsHttpServeMux
|
||||
{
|
||||
private:
|
||||
// the pattern handler, to handle the http request.
|
||||
std::map<std::string, SrsHttpMuxEntry*> entries;
|
||||
// the vhost handler.
|
||||
// when find the handler to process the request,
|
||||
// append the matched vhost when pattern not starts with /,
|
||||
// for example, for pattern /live/livestream.flv of vhost ossrs.net,
|
||||
// the path will rewrite to ossrs.net/live/livestream.flv
|
||||
std::map<std::string, ISrsHttpHandler*> vhosts;
|
||||
// all hijackers for http match.
|
||||
// for example, the hstrs(http stream trigger rtmp source)
|
||||
// can hijack and install handler when request incoming and no handler.
|
||||
std::vector<ISrsHttpMatchHijacker*> hijackers;
|
||||
public:
|
||||
SrsHttpServeMux();
|
||||
virtual ~SrsHttpServeMux();
|
||||
public:
|
||||
/**
|
||||
* initialize the http serve mux.
|
||||
*/
|
||||
virtual int initialize();
|
||||
/**
|
||||
* hijack the http match.
|
||||
*/
|
||||
virtual void hijack(ISrsHttpMatchHijacker* h);
|
||||
virtual void unhijack(ISrsHttpMatchHijacker* h);
|
||||
public:
|
||||
// Handle registers the handler for the given pattern.
|
||||
// If a handler already exists for pattern, Handle panics.
|
||||
virtual int handle(std::string pattern, ISrsHttpHandler* handler);
|
||||
// interface ISrsHttpHandler
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
private:
|
||||
virtual int find_handler(SrsHttpMessage* r, ISrsHttpHandler** ph);
|
||||
virtual int match(SrsHttpMessage* r, ISrsHttpHandler** ph);
|
||||
virtual bool path_match(std::string pattern, std::string path);
|
||||
};
|
||||
|
||||
/**
|
||||
* response writer use st socket
|
||||
*/
|
||||
class SrsHttpResponseWriter : public ISrsHttpResponseWriter
|
||||
{
|
||||
private:
|
||||
SrsStSocket* skt;
|
||||
SrsHttpHeader* hdr;
|
||||
private:
|
||||
// reply header has been (logically) written
|
||||
bool header_wrote;
|
||||
// status code passed to WriteHeader
|
||||
int status;
|
||||
private:
|
||||
// explicitly-declared Content-Length; or -1
|
||||
int64_t content_length;
|
||||
// number of bytes written in body
|
||||
int64_t written;
|
||||
private:
|
||||
// wroteHeader tells whether the header's been written to "the
|
||||
// wire" (or rather: w.conn.buf). this is unlike
|
||||
// (*response).wroteHeader, which tells only whether it was
|
||||
// logically written.
|
||||
bool header_sent;
|
||||
public:
|
||||
SrsHttpResponseWriter(SrsStSocket* io);
|
||||
virtual ~SrsHttpResponseWriter();
|
||||
public:
|
||||
virtual int final_request();
|
||||
virtual SrsHttpHeader* header();
|
||||
virtual int write(char* data, int size);
|
||||
virtual void write_header(int code);
|
||||
virtual int send_header(char* data, int size);
|
||||
};
|
||||
|
||||
/**
|
||||
* response reader use st socket.
|
||||
*/
|
||||
class SrsHttpResponseReader : virtual public ISrsHttpResponseReader
|
||||
{
|
||||
private:
|
||||
SrsStSocket* skt;
|
||||
SrsHttpMessage* owner;
|
||||
SrsFastBuffer* buffer;
|
||||
bool is_eof;
|
||||
// the left bytes in chunk.
|
||||
int nb_left_chunk;
|
||||
// the number of bytes of current chunk.
|
||||
int nb_chunk;
|
||||
// already read total bytes.
|
||||
int64_t nb_total_read;
|
||||
public:
|
||||
SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io);
|
||||
virtual ~SrsHttpResponseReader();
|
||||
public:
|
||||
/**
|
||||
* initialize the response reader with buffer.
|
||||
*/
|
||||
virtual int initialize(SrsFastBuffer* buffer);
|
||||
// interface ISrsHttpResponseReader
|
||||
public:
|
||||
virtual bool eof();
|
||||
virtual int read(char* data, int nb_data, int* nb_read);
|
||||
private:
|
||||
virtual int read_chunked(char* data, int nb_data, int* nb_read);
|
||||
virtual int read_specified(char* data, int nb_data, int* nb_read);
|
||||
};
|
||||
|
||||
// for http header.
|
||||
typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
||||
|
||||
// A Request represents an HTTP request received by a server
|
||||
// or to be sent by a client.
|
||||
//
|
||||
// The field semantics differ slightly between client and server
|
||||
// usage. In addition to the notes on the fields below, see the
|
||||
// documentation for Request.Write and RoundTripper.
|
||||
/**
|
||||
* the http message, request or response.
|
||||
*/
|
||||
class SrsHttpMessage
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* parsed url.
|
||||
*/
|
||||
std::string _url;
|
||||
/**
|
||||
* the extension of file, for example, .flv
|
||||
*/
|
||||
std::string _ext;
|
||||
/**
|
||||
* parsed http header.
|
||||
*/
|
||||
http_parser _header;
|
||||
/**
|
||||
* body object, reader object.
|
||||
* @remark, user can get body in string by get_body().
|
||||
*/
|
||||
SrsHttpResponseReader* _body;
|
||||
/**
|
||||
* whether the body is chunked.
|
||||
*/
|
||||
bool chunked;
|
||||
/**
|
||||
* whether the request indicates should keep alive
|
||||
* for the http connection.
|
||||
*/
|
||||
bool keep_alive;
|
||||
/**
|
||||
* uri parser
|
||||
*/
|
||||
SrsHttpUri* _uri;
|
||||
/**
|
||||
* use a buffer to read and send ts file.
|
||||
*/
|
||||
// TODO: FIXME: remove it.
|
||||
char* _http_ts_send_buffer;
|
||||
// http headers
|
||||
std::vector<SrsHttpHeaderField> _headers;
|
||||
// the query map
|
||||
std::map<std::string, std::string> _query;
|
||||
// the transport connection, can be NULL.
|
||||
SrsConnection* conn;
|
||||
public:
|
||||
SrsHttpMessage(SrsStSocket* io, SrsConnection* c);
|
||||
virtual ~SrsHttpMessage();
|
||||
public:
|
||||
/**
|
||||
* set the original messages, then update the message.
|
||||
*/
|
||||
virtual int update(std::string url, http_parser* header,
|
||||
SrsFastBuffer* body, std::vector<SrsHttpHeaderField>& headers
|
||||
);
|
||||
public:
|
||||
virtual char* http_ts_send_buffer();
|
||||
virtual SrsConnection* connection();
|
||||
public:
|
||||
virtual u_int8_t method();
|
||||
virtual u_int16_t status_code();
|
||||
/**
|
||||
* method helpers.
|
||||
*/
|
||||
virtual std::string method_str();
|
||||
virtual bool is_http_get();
|
||||
virtual bool is_http_put();
|
||||
virtual bool is_http_post();
|
||||
virtual bool is_http_delete();
|
||||
virtual bool is_http_options();
|
||||
/**
|
||||
* whether body is chunked encoding, for reader only.
|
||||
*/
|
||||
virtual bool is_chunked();
|
||||
/**
|
||||
* whether should keep the connection alive.
|
||||
*/
|
||||
virtual bool is_keep_alive();
|
||||
/**
|
||||
* the uri contains the host and path.
|
||||
*/
|
||||
virtual std::string uri();
|
||||
/**
|
||||
* the url maybe the path.
|
||||
*/
|
||||
virtual std::string url();
|
||||
virtual std::string host();
|
||||
virtual std::string path();
|
||||
virtual std::string ext();
|
||||
public:
|
||||
/**
|
||||
* read body to string.
|
||||
* @remark for small http body.
|
||||
*/
|
||||
virtual int body_read_all(std::string& body);
|
||||
/**
|
||||
* get the body reader, to read one by one.
|
||||
* @remark when body is very large, or chunked, use this.
|
||||
*/
|
||||
virtual ISrsHttpResponseReader* body_reader();
|
||||
/**
|
||||
* the content length, -1 for chunked or not set.
|
||||
*/
|
||||
virtual int64_t content_length();
|
||||
/**
|
||||
* get the param in query string,
|
||||
* for instance, query is "start=100&end=200",
|
||||
* then query_get("start") is "100", and query_get("end") is "200"
|
||||
*/
|
||||
virtual std::string query_get(std::string key);
|
||||
/**
|
||||
* get the headers.
|
||||
*/
|
||||
virtual int request_header_count();
|
||||
virtual std::string request_header_key_at(int index);
|
||||
virtual std::string request_header_value_at(int index);
|
||||
virtual std::string get_request_header(std::string name);
|
||||
public:
|
||||
/**
|
||||
* convert the http message to a request.
|
||||
* @remark user must free the return request.
|
||||
*/
|
||||
virtual SrsRequest* to_request(std::string vhost);
|
||||
};
|
||||
|
||||
/**
|
||||
* wrapper for http-parser,
|
||||
* provides HTTP message originted service.
|
||||
*/
|
||||
class SrsHttpParser
|
||||
{
|
||||
private:
|
||||
http_parser_settings settings;
|
||||
http_parser parser;
|
||||
// the global parse buffer.
|
||||
SrsFastBuffer* buffer;
|
||||
private:
|
||||
// http parse data, reset before parse message.
|
||||
bool expect_field_name;
|
||||
std::string field_name;
|
||||
std::string field_value;
|
||||
SrsHttpParseState state;
|
||||
http_parser header;
|
||||
std::string url;
|
||||
std::vector<SrsHttpHeaderField> headers;
|
||||
int header_parsed;
|
||||
public:
|
||||
SrsHttpParser();
|
||||
virtual ~SrsHttpParser();
|
||||
public:
|
||||
/**
|
||||
* initialize the http parser with specified type,
|
||||
* one parser can only parse request or response messages.
|
||||
*/
|
||||
virtual int initialize(enum http_parser_type type);
|
||||
/**
|
||||
* always parse a http message,
|
||||
* that is, the *ppmsg always NOT-NULL when return success.
|
||||
* or error and *ppmsg must be NULL.
|
||||
* @remark, if success, *ppmsg always NOT-NULL, *ppmsg always is_complete().
|
||||
*/
|
||||
virtual int parse_message(SrsStSocket* skt, SrsConnection* conn, SrsHttpMessage** ppmsg);
|
||||
private:
|
||||
/**
|
||||
* parse the HTTP message to member field: msg.
|
||||
*/
|
||||
virtual int parse_message_imp(SrsStSocket* skt);
|
||||
private:
|
||||
static int on_message_begin(http_parser* parser);
|
||||
static int on_headers_complete(http_parser* parser);
|
||||
static int on_message_complete(http_parser* parser);
|
||||
static int on_url(http_parser* parser, const char* at, size_t length);
|
||||
static int on_header_field(http_parser* parser, const char* at, size_t length);
|
||||
static int on_header_value(http_parser* parser, const char* at, size_t length);
|
||||
static int on_body(http_parser* parser, const char* at, size_t length);
|
||||
};
|
||||
|
||||
/**
|
||||
* used to resolve the http uri.
|
||||
*/
|
||||
class SrsHttpUri
|
||||
{
|
||||
private:
|
||||
std::string url;
|
||||
std::string schema;
|
||||
std::string host;
|
||||
int port;
|
||||
std::string path;
|
||||
std::string query;
|
||||
public:
|
||||
SrsHttpUri();
|
||||
virtual ~SrsHttpUri();
|
||||
public:
|
||||
/**
|
||||
* initialize the http uri.
|
||||
*/
|
||||
virtual int initialize(std::string _url);
|
||||
public:
|
||||
virtual const char* get_url();
|
||||
virtual const char* get_schema();
|
||||
virtual const char* get_host();
|
||||
virtual int get_port();
|
||||
virtual const char* get_path();
|
||||
virtual const char* get_query();
|
||||
private:
|
||||
/**
|
||||
* get the parsed url field.
|
||||
* @return return empty string if not set.
|
||||
*/
|
||||
virtual std::string get_uri_field(std::string uri, http_parser_url* hp_u, http_parser_url_fields field);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -39,6 +39,7 @@ using namespace std;
|
|||
#include <srs_rtmp_sdk.hpp>
|
||||
#include <srs_app_dvr.hpp>
|
||||
#include <srs_app_config.hpp>
|
||||
#include <srs_app_http_conn.hpp>
|
||||
|
||||
SrsGoApiRoot::SrsGoApiRoot()
|
||||
{
|
||||
|
@ -48,7 +49,7 @@ SrsGoApiRoot::~SrsGoApiRoot()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiRoot::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiRoot::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -59,7 +60,7 @@ int SrsGoApiRoot::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< SRS_JOBJECT_END
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiApi::SrsGoApiApi()
|
||||
|
@ -70,7 +71,7 @@ SrsGoApiApi::~SrsGoApiApi()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiApi::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiApi::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -81,7 +82,7 @@ int SrsGoApiApi::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< SRS_JOBJECT_END
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiV1::SrsGoApiV1()
|
||||
|
@ -92,7 +93,7 @@ SrsGoApiV1::~SrsGoApiV1()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiV1::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiV1::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -112,7 +113,7 @@ int SrsGoApiV1::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< SRS_JOBJECT_END
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiVersion::SrsGoApiVersion()
|
||||
|
@ -123,7 +124,7 @@ SrsGoApiVersion::~SrsGoApiVersion()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiVersion::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiVersion::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -137,7 +138,7 @@ int SrsGoApiVersion::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< SRS_JOBJECT_END
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiSummaries::SrsGoApiSummaries()
|
||||
|
@ -148,11 +149,11 @@ SrsGoApiSummaries::~SrsGoApiSummaries()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
srs_api_dump_summaries(ss);
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiRusages::SrsGoApiRusages()
|
||||
|
@ -163,7 +164,7 @@ SrsGoApiRusages::~SrsGoApiRusages()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiRusages::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* req)
|
||||
int SrsGoApiRusages::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* req)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -193,7 +194,7 @@ int SrsGoApiRusages::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* req)
|
|||
<< SRS_JOBJECT_END
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiSelfProcStats::SrsGoApiSelfProcStats()
|
||||
|
@ -204,7 +205,7 @@ SrsGoApiSelfProcStats::~SrsGoApiSelfProcStats()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -263,7 +264,7 @@ int SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage*
|
|||
<< SRS_JOBJECT_END
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiSystemProcStats::SrsGoApiSystemProcStats()
|
||||
|
@ -274,7 +275,7 @@ SrsGoApiSystemProcStats::~SrsGoApiSystemProcStats()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -298,7 +299,7 @@ int SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessag
|
|||
<< SRS_JOBJECT_END
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiMemInfos::SrsGoApiMemInfos()
|
||||
|
@ -309,7 +310,7 @@ SrsGoApiMemInfos::~SrsGoApiMemInfos()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -334,7 +335,7 @@ int SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< SRS_JOBJECT_END
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiAuthors::SrsGoApiAuthors()
|
||||
|
@ -345,7 +346,7 @@ SrsGoApiAuthors::~SrsGoApiAuthors()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -359,7 +360,7 @@ int SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< SRS_JOBJECT_END
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiRequests::SrsGoApiRequests()
|
||||
|
@ -370,9 +371,9 @@ SrsGoApiRequests::~SrsGoApiRequests()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
SrsHttpMessage* req = r;
|
||||
ISrsHttpMessage* req = r;
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
|
@ -420,7 +421,7 @@ int SrsGoApiRequests::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< SRS_JOBJECT_END
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiVhosts::SrsGoApiVhosts()
|
||||
|
@ -431,7 +432,7 @@ SrsGoApiVhosts::~SrsGoApiVhosts()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream data;
|
||||
SrsStatistic* stat = SrsStatistic::instance();
|
||||
|
@ -445,7 +446,7 @@ int SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< SRS_JFIELD_ORG("vhosts", data.str())
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiStreams::SrsGoApiStreams()
|
||||
|
@ -456,7 +457,7 @@ SrsGoApiStreams::~SrsGoApiStreams()
|
|||
{
|
||||
}
|
||||
|
||||
int SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream data;
|
||||
SrsStatistic* stat = SrsStatistic::instance();
|
||||
|
@ -470,7 +471,7 @@ int SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< SRS_JFIELD_ORG("streams", data.str())
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
return srs_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsHttpApi::SrsHttpApi(IConnectionManager* cm, st_netfd_t fd, SrsHttpServeMux* m)
|
||||
|
@ -529,7 +530,7 @@ int SrsHttpApi::do_cycle()
|
|||
|
||||
// process http messages.
|
||||
for (;;) {
|
||||
SrsHttpMessage* req = NULL;
|
||||
ISrsHttpMessage* req = NULL;
|
||||
|
||||
// get a http message
|
||||
if ((ret = parser->parse_message(&skt, this, &req)) != ERROR_SUCCESS) {
|
||||
|
@ -540,7 +541,7 @@ int SrsHttpApi::do_cycle()
|
|||
srs_assert(req);
|
||||
|
||||
// always free it in this scope.
|
||||
SrsAutoFree(SrsHttpMessage, req);
|
||||
SrsAutoFree(ISrsHttpMessage, req);
|
||||
|
||||
// TODO: FIXME: use the post body.
|
||||
std::string res;
|
||||
|
@ -566,7 +567,7 @@ int SrsHttpApi::do_cycle()
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpApi::process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
int SrsHttpApi::process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
|
|
|
@ -33,13 +33,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#ifdef SRS_AUTO_HTTP_API
|
||||
|
||||
class SrsStSocket;
|
||||
class SrsHttpMessage;
|
||||
class ISrsHttpMessage;
|
||||
class SrsHttpParser;
|
||||
class SrsHttpHandler;
|
||||
|
||||
#include <srs_app_st.hpp>
|
||||
#include <srs_app_conn.hpp>
|
||||
#include <srs_app_http.hpp>
|
||||
#include <srs_http_stack.hpp>
|
||||
|
||||
// for http root.
|
||||
class SrsGoApiRoot : public ISrsHttpHandler
|
||||
|
@ -48,7 +48,7 @@ public:
|
|||
SrsGoApiRoot();
|
||||
virtual ~SrsGoApiRoot();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiApi : public ISrsHttpHandler
|
||||
|
@ -57,7 +57,7 @@ public:
|
|||
SrsGoApiApi();
|
||||
virtual ~SrsGoApiApi();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiV1 : public ISrsHttpHandler
|
||||
|
@ -66,7 +66,7 @@ public:
|
|||
SrsGoApiV1();
|
||||
virtual ~SrsGoApiV1();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiVersion : public ISrsHttpHandler
|
||||
|
@ -75,7 +75,7 @@ public:
|
|||
SrsGoApiVersion();
|
||||
virtual ~SrsGoApiVersion();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiSummaries : public ISrsHttpHandler
|
||||
|
@ -84,7 +84,7 @@ public:
|
|||
SrsGoApiSummaries();
|
||||
virtual ~SrsGoApiSummaries();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiRusages : public ISrsHttpHandler
|
||||
|
@ -93,7 +93,7 @@ public:
|
|||
SrsGoApiRusages();
|
||||
virtual ~SrsGoApiRusages();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiSelfProcStats : public ISrsHttpHandler
|
||||
|
@ -102,7 +102,7 @@ public:
|
|||
SrsGoApiSelfProcStats();
|
||||
virtual ~SrsGoApiSelfProcStats();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiSystemProcStats : public ISrsHttpHandler
|
||||
|
@ -111,7 +111,7 @@ public:
|
|||
SrsGoApiSystemProcStats();
|
||||
virtual ~SrsGoApiSystemProcStats();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiMemInfos : public ISrsHttpHandler
|
||||
|
@ -120,7 +120,7 @@ public:
|
|||
SrsGoApiMemInfos();
|
||||
virtual ~SrsGoApiMemInfos();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiAuthors : public ISrsHttpHandler
|
||||
|
@ -129,7 +129,7 @@ public:
|
|||
SrsGoApiAuthors();
|
||||
virtual ~SrsGoApiAuthors();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiRequests : public ISrsHttpHandler
|
||||
|
@ -138,7 +138,7 @@ public:
|
|||
SrsGoApiRequests();
|
||||
virtual ~SrsGoApiRequests();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiVhosts : public ISrsHttpHandler
|
||||
|
@ -147,7 +147,7 @@ public:
|
|||
SrsGoApiVhosts();
|
||||
virtual ~SrsGoApiVhosts();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiStreams : public ISrsHttpHandler
|
||||
|
@ -156,7 +156,7 @@ public:
|
|||
SrsGoApiStreams();
|
||||
virtual ~SrsGoApiStreams();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsHttpApi : public SrsConnection
|
||||
|
@ -177,7 +177,7 @@ public:
|
|||
protected:
|
||||
virtual int do_cycle();
|
||||
private:
|
||||
virtual int process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,13 +29,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
using namespace std;
|
||||
|
||||
#include <srs_app_http.hpp>
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_app_st_socket.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_app_utility.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_app_http_conn.hpp>
|
||||
|
||||
SrsHttpClient::SrsHttpClient()
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ int SrsHttpClient::initialize(string h, int p, int64_t t_us)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpClient::post(string path, string req, SrsHttpMessage** ppmsg)
|
||||
int SrsHttpClient::post(string path, string req, ISrsHttpMessage** ppmsg)
|
||||
{
|
||||
*ppmsg = NULL;
|
||||
|
||||
|
@ -104,7 +104,7 @@ int SrsHttpClient::post(string path, string req, SrsHttpMessage** ppmsg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
ISrsHttpMessage* msg = NULL;
|
||||
if ((ret = parser->parse_message(skt, NULL, &msg)) != ERROR_SUCCESS) {
|
||||
srs_error("parse http post response failed. ret=%d", ret);
|
||||
return ret;
|
||||
|
@ -117,7 +117,7 @@ int SrsHttpClient::post(string path, string req, SrsHttpMessage** ppmsg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpClient::get(string path, std::string req, SrsHttpMessage** ppmsg)
|
||||
int SrsHttpClient::get(string path, std::string req, ISrsHttpMessage** ppmsg)
|
||||
{
|
||||
*ppmsg = NULL;
|
||||
|
||||
|
@ -150,7 +150,7 @@ int SrsHttpClient::get(string path, std::string req, SrsHttpMessage** ppmsg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
ISrsHttpMessage* msg = NULL;
|
||||
if ((ret = parser->parse_message(skt, NULL, &msg)) != ERROR_SUCCESS) {
|
||||
srs_error("parse http post response failed. ret=%d", ret);
|
||||
return ret;
|
||||
|
|
|
@ -37,7 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
class SrsHttpUri;
|
||||
class SrsHttpParser;
|
||||
class SrsHttpMessage;
|
||||
class ISrsHttpMessage;
|
||||
class SrsStSocket;
|
||||
|
||||
// the default timeout for http client.
|
||||
|
@ -73,14 +73,14 @@ public:
|
|||
* @param req the data post to uri. empty string to ignore.
|
||||
* @param ppmsg output the http message to read the response.
|
||||
*/
|
||||
virtual int post(std::string path, std::string req, SrsHttpMessage** ppmsg);
|
||||
virtual int post(std::string path, std::string req, ISrsHttpMessage** ppmsg);
|
||||
/**
|
||||
* to get data from the uri.
|
||||
* @param the path to request on.
|
||||
* @param req the data post to uri. empty string to ignore.
|
||||
* @param ppmsg output the http message to read the response.
|
||||
*/
|
||||
virtual int get(std::string path, std::string req, SrsHttpMessage** ppmsg);
|
||||
virtual int get(std::string path, std::string req, ISrsHttpMessage** ppmsg);
|
||||
private:
|
||||
virtual void disconnect();
|
||||
virtual int connect();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,14 +30,22 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_SERVER
|
||||
#ifdef SRS_AUTO_HTTP_PARSER
|
||||
#include <http_parser.h>
|
||||
#endif
|
||||
|
||||
#if defined(SRS_AUTO_HTTP_PARSER) || defined(SRS_AUTO_HTTP_SERVER)
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <srs_app_st.hpp>
|
||||
#include <srs_app_conn.hpp>
|
||||
#include <srs_app_http.hpp>
|
||||
#include <srs_http_stack.hpp>
|
||||
#include <srs_app_reload.hpp>
|
||||
#include <srs_kernel_file.hpp>
|
||||
#include <srs_app_thread.hpp>
|
||||
#include <srs_app_conn.hpp>
|
||||
|
||||
class SrsServer;
|
||||
class SrsSource;
|
||||
|
@ -49,10 +57,313 @@ class SrsAacEncoder;
|
|||
class SrsMp3Encoder;
|
||||
class SrsFlvEncoder;
|
||||
class SrsHttpParser;
|
||||
class SrsHttpMessage;
|
||||
class ISrsHttpMessage;
|
||||
class SrsHttpHandler;
|
||||
class SrsMessageQueue;
|
||||
class SrsSharedPtrMessage;
|
||||
class SrsRequest;
|
||||
class SrsFastBuffer;
|
||||
class SrsHttpUri;
|
||||
class SrsConnection;
|
||||
class SrsHttpMessage;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_PARSER
|
||||
|
||||
/**
|
||||
* response writer use st socket
|
||||
*/
|
||||
class SrsHttpResponseWriter : public ISrsHttpResponseWriter
|
||||
{
|
||||
private:
|
||||
SrsStSocket* skt;
|
||||
SrsHttpHeader* hdr;
|
||||
private:
|
||||
// reply header has been (logically) written
|
||||
bool header_wrote;
|
||||
// status code passed to WriteHeader
|
||||
int status;
|
||||
private:
|
||||
// explicitly-declared Content-Length; or -1
|
||||
int64_t content_length;
|
||||
// number of bytes written in body
|
||||
int64_t written;
|
||||
private:
|
||||
// wroteHeader tells whether the header's been written to "the
|
||||
// wire" (or rather: w.conn.buf). this is unlike
|
||||
// (*response).wroteHeader, which tells only whether it was
|
||||
// logically written.
|
||||
bool header_sent;
|
||||
public:
|
||||
SrsHttpResponseWriter(SrsStSocket* io);
|
||||
virtual ~SrsHttpResponseWriter();
|
||||
public:
|
||||
virtual int final_request();
|
||||
virtual SrsHttpHeader* header();
|
||||
virtual int write(char* data, int size);
|
||||
virtual void write_header(int code);
|
||||
virtual int send_header(char* data, int size);
|
||||
};
|
||||
|
||||
/**
|
||||
* response reader use st socket.
|
||||
*/
|
||||
class SrsHttpResponseReader : virtual public ISrsHttpResponseReader
|
||||
{
|
||||
private:
|
||||
SrsStSocket* skt;
|
||||
SrsHttpMessage* owner;
|
||||
SrsFastBuffer* buffer;
|
||||
bool is_eof;
|
||||
// the left bytes in chunk.
|
||||
int nb_left_chunk;
|
||||
// the number of bytes of current chunk.
|
||||
int nb_chunk;
|
||||
// already read total bytes.
|
||||
int64_t nb_total_read;
|
||||
public:
|
||||
SrsHttpResponseReader(SrsHttpMessage* msg, SrsStSocket* io);
|
||||
virtual ~SrsHttpResponseReader();
|
||||
public:
|
||||
/**
|
||||
* initialize the response reader with buffer.
|
||||
*/
|
||||
virtual int initialize(SrsFastBuffer* buffer);
|
||||
// interface ISrsHttpResponseReader
|
||||
public:
|
||||
virtual bool eof();
|
||||
virtual int read(char* data, int nb_data, int* nb_read);
|
||||
private:
|
||||
virtual int read_chunked(char* data, int nb_data, int* nb_read);
|
||||
virtual int read_specified(char* data, int nb_data, int* nb_read);
|
||||
};
|
||||
|
||||
// for http header.
|
||||
typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
||||
|
||||
// A Request represents an HTTP request received by a server
|
||||
// or to be sent by a client.
|
||||
//
|
||||
// The field semantics differ slightly between client and server
|
||||
// usage. In addition to the notes on the fields below, see the
|
||||
// documentation for Request.Write and RoundTripper.
|
||||
/**
|
||||
* the http message, request or response.
|
||||
*/
|
||||
class SrsHttpMessage : public ISrsHttpMessage
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* parsed url.
|
||||
*/
|
||||
std::string _url;
|
||||
/**
|
||||
* the extension of file, for example, .flv
|
||||
*/
|
||||
std::string _ext;
|
||||
/**
|
||||
* parsed http header.
|
||||
*/
|
||||
http_parser _header;
|
||||
/**
|
||||
* body object, reader object.
|
||||
* @remark, user can get body in string by get_body().
|
||||
*/
|
||||
SrsHttpResponseReader* _body;
|
||||
/**
|
||||
* whether the body is chunked.
|
||||
*/
|
||||
bool chunked;
|
||||
/**
|
||||
* whether the request indicates should keep alive
|
||||
* for the http connection.
|
||||
*/
|
||||
bool keep_alive;
|
||||
/**
|
||||
* uri parser
|
||||
*/
|
||||
SrsHttpUri* _uri;
|
||||
/**
|
||||
* use a buffer to read and send ts file.
|
||||
*/
|
||||
// TODO: FIXME: remove it.
|
||||
char* _http_ts_send_buffer;
|
||||
// http headers
|
||||
std::vector<SrsHttpHeaderField> _headers;
|
||||
// the query map
|
||||
std::map<std::string, std::string> _query;
|
||||
// the transport connection, can be NULL.
|
||||
SrsConnection* conn;
|
||||
public:
|
||||
SrsHttpMessage(SrsStSocket* io, SrsConnection* c);
|
||||
virtual ~SrsHttpMessage();
|
||||
public:
|
||||
/**
|
||||
* set the original messages, then update the message.
|
||||
*/
|
||||
virtual int update(std::string url, http_parser* header,
|
||||
SrsFastBuffer* body, std::vector<SrsHttpHeaderField>& headers
|
||||
);
|
||||
private:
|
||||
virtual SrsConnection* connection();
|
||||
public:
|
||||
virtual u_int8_t method();
|
||||
virtual u_int16_t status_code();
|
||||
/**
|
||||
* method helpers.
|
||||
*/
|
||||
virtual std::string method_str();
|
||||
virtual bool is_http_get();
|
||||
virtual bool is_http_put();
|
||||
virtual bool is_http_post();
|
||||
virtual bool is_http_delete();
|
||||
virtual bool is_http_options();
|
||||
/**
|
||||
* whether body is chunked encoding, for reader only.
|
||||
*/
|
||||
virtual bool is_chunked();
|
||||
/**
|
||||
* whether should keep the connection alive.
|
||||
*/
|
||||
virtual bool is_keep_alive();
|
||||
/**
|
||||
* the uri contains the host and path.
|
||||
*/
|
||||
virtual std::string uri();
|
||||
/**
|
||||
* the url maybe the path.
|
||||
*/
|
||||
virtual std::string url();
|
||||
virtual std::string host();
|
||||
virtual std::string path();
|
||||
virtual std::string ext();
|
||||
public:
|
||||
/**
|
||||
* read body to string.
|
||||
* @remark for small http body.
|
||||
*/
|
||||
virtual int body_read_all(std::string& body);
|
||||
/**
|
||||
* get the body reader, to read one by one.
|
||||
* @remark when body is very large, or chunked, use this.
|
||||
*/
|
||||
virtual ISrsHttpResponseReader* body_reader();
|
||||
/**
|
||||
* the content length, -1 for chunked or not set.
|
||||
*/
|
||||
virtual int64_t content_length();
|
||||
/**
|
||||
* get the param in query string,
|
||||
* for instance, query is "start=100&end=200",
|
||||
* then query_get("start") is "100", and query_get("end") is "200"
|
||||
*/
|
||||
virtual std::string query_get(std::string key);
|
||||
/**
|
||||
* get the headers.
|
||||
*/
|
||||
virtual int request_header_count();
|
||||
virtual std::string request_header_key_at(int index);
|
||||
virtual std::string request_header_value_at(int index);
|
||||
virtual std::string get_request_header(std::string name);
|
||||
public:
|
||||
/**
|
||||
* convert the http message to a request.
|
||||
* @remark user must free the return request.
|
||||
*/
|
||||
virtual SrsRequest* to_request(std::string vhost);
|
||||
};
|
||||
|
||||
/**
|
||||
* wrapper for http-parser,
|
||||
* provides HTTP message originted service.
|
||||
*/
|
||||
class SrsHttpParser
|
||||
{
|
||||
private:
|
||||
http_parser_settings settings;
|
||||
http_parser parser;
|
||||
// the global parse buffer.
|
||||
SrsFastBuffer* buffer;
|
||||
private:
|
||||
// http parse data, reset before parse message.
|
||||
bool expect_field_name;
|
||||
std::string field_name;
|
||||
std::string field_value;
|
||||
SrsHttpParseState state;
|
||||
http_parser header;
|
||||
std::string url;
|
||||
std::vector<SrsHttpHeaderField> headers;
|
||||
int header_parsed;
|
||||
public:
|
||||
SrsHttpParser();
|
||||
virtual ~SrsHttpParser();
|
||||
public:
|
||||
/**
|
||||
* initialize the http parser with specified type,
|
||||
* one parser can only parse request or response messages.
|
||||
*/
|
||||
virtual int initialize(enum http_parser_type type);
|
||||
/**
|
||||
* always parse a http message,
|
||||
* that is, the *ppmsg always NOT-NULL when return success.
|
||||
* or error and *ppmsg must be NULL.
|
||||
* @remark, if success, *ppmsg always NOT-NULL, *ppmsg always is_complete().
|
||||
*/
|
||||
virtual int parse_message(SrsStSocket* skt, SrsConnection* conn, ISrsHttpMessage** ppmsg);
|
||||
private:
|
||||
/**
|
||||
* parse the HTTP message to member field: msg.
|
||||
*/
|
||||
virtual int parse_message_imp(SrsStSocket* skt);
|
||||
private:
|
||||
static int on_message_begin(http_parser* parser);
|
||||
static int on_headers_complete(http_parser* parser);
|
||||
static int on_message_complete(http_parser* parser);
|
||||
static int on_url(http_parser* parser, const char* at, size_t length);
|
||||
static int on_header_field(http_parser* parser, const char* at, size_t length);
|
||||
static int on_header_value(http_parser* parser, const char* at, size_t length);
|
||||
static int on_body(http_parser* parser, const char* at, size_t length);
|
||||
};
|
||||
|
||||
/**
|
||||
* used to resolve the http uri.
|
||||
*/
|
||||
class SrsHttpUri
|
||||
{
|
||||
private:
|
||||
std::string url;
|
||||
std::string schema;
|
||||
std::string host;
|
||||
int port;
|
||||
std::string path;
|
||||
std::string query;
|
||||
public:
|
||||
SrsHttpUri();
|
||||
virtual ~SrsHttpUri();
|
||||
public:
|
||||
/**
|
||||
* initialize the http uri.
|
||||
*/
|
||||
virtual int initialize(std::string _url);
|
||||
public:
|
||||
virtual const char* get_url();
|
||||
virtual const char* get_schema();
|
||||
virtual const char* get_host();
|
||||
virtual int get_port();
|
||||
virtual const char* get_path();
|
||||
virtual const char* get_query();
|
||||
private:
|
||||
/**
|
||||
* get the parsed url field.
|
||||
* @return return empty string if not set.
|
||||
*/
|
||||
virtual std::string get_uri_field(std::string uri, http_parser_url* hp_u, http_parser_url_fields field);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_SERVER
|
||||
|
||||
/**
|
||||
* the flv vod stream supports flv?start=offset-bytes.
|
||||
|
@ -66,8 +377,8 @@ public:
|
|||
SrsVodStream(std::string root_dir);
|
||||
virtual ~SrsVodStream();
|
||||
protected:
|
||||
virtual int serve_flv_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int offset);
|
||||
virtual int serve_mp4_stream(ISrsHttpResponseWriter* w, SrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||
virtual int serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath, int offset);
|
||||
virtual int serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -75,20 +386,20 @@ protected:
|
|||
* for example, the audio stream cache to make android(weixin) happy.
|
||||
* we start a thread to shrink the queue.
|
||||
*/
|
||||
class SrsStreamCache : public ISrsThreadHandler
|
||||
class SrsStreamCache : public ISrsEndlessThreadHandler
|
||||
{
|
||||
private:
|
||||
SrsMessageQueue* queue;
|
||||
SrsSource* source;
|
||||
SrsRequest* req;
|
||||
SrsThread* pthread;
|
||||
SrsEndlessThread* pthread;
|
||||
public:
|
||||
SrsStreamCache(SrsSource* s, SrsRequest* r);
|
||||
virtual ~SrsStreamCache();
|
||||
public:
|
||||
virtual int start();
|
||||
virtual int dump_cache(SrsConsumer* consumer);
|
||||
// interface ISrsThreadHandler.
|
||||
// interface ISrsEndlessThreadHandler.
|
||||
public:
|
||||
virtual int cycle();
|
||||
};
|
||||
|
@ -243,7 +554,7 @@ public:
|
|||
SrsLiveStream(SrsSource* s, SrsRequest* r, SrsStreamCache* c);
|
||||
virtual ~SrsLiveStream();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
private:
|
||||
virtual int streaming_send_messages(ISrsStreamEncoder* enc, SrsSharedPtrMessage** msgs, int nb_msgs);
|
||||
};
|
||||
|
@ -289,7 +600,7 @@ public:
|
|||
public:
|
||||
virtual void set_m3u8(std::string v);
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -305,7 +616,7 @@ public:
|
|||
public:
|
||||
virtual void set_ts(std::string v);
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -358,14 +669,14 @@ public:
|
|||
virtual int hls_update_m3u8(SrsRequest* r, std::string m3u8);
|
||||
virtual int hls_update_ts(SrsRequest* r, std::string uri, std::string ts);
|
||||
virtual void unmount_hls(SrsRequest* r);
|
||||
// interface ISrsThreadHandler.
|
||||
// interface ISrsReloadHandler.
|
||||
public:
|
||||
virtual int on_reload_vhost_http_updated();
|
||||
virtual int on_reload_vhost_http_remux_updated();
|
||||
virtual int on_reload_vhost_hls(std::string vhost);
|
||||
// interface ISrsHttpMatchHijacker
|
||||
public:
|
||||
virtual int hijack(SrsHttpMessage* request, ISrsHttpHandler** ph);
|
||||
virtual int hijack(ISrsHttpMessage* request, ISrsHttpHandler** ph);
|
||||
private:
|
||||
virtual int initialize_static_file();
|
||||
virtual int initialize_flv_streaming();
|
||||
|
@ -392,9 +703,9 @@ protected:
|
|||
// when got http message,
|
||||
// for the static service or api, discard any body.
|
||||
// for the stream caster, for instance, http flv streaming, may discard the flv header or not.
|
||||
virtual int on_got_http_message(SrsHttpMessage* msg) = 0;
|
||||
virtual int on_got_http_message(ISrsHttpMessage* msg) = 0;
|
||||
private:
|
||||
virtual int process_request(ISrsHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
virtual int process_request(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsStaticHttpConn : public SrsHttpConn
|
||||
|
@ -403,7 +714,7 @@ public:
|
|||
SrsStaticHttpConn(IConnectionManager* cm, st_netfd_t fd, SrsHttpServeMux* m);
|
||||
virtual ~SrsStaticHttpConn();
|
||||
public:
|
||||
virtual int on_got_http_message(SrsHttpMessage* msg);
|
||||
virtual int on_got_http_message(ISrsHttpMessage* msg);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -31,13 +31,13 @@ using namespace std;
|
|||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_rtmp_sdk.hpp>
|
||||
#include <srs_app_st_socket.hpp>
|
||||
#include <srs_app_http.hpp>
|
||||
#include <srs_app_json.hpp>
|
||||
#include <srs_app_dvr.hpp>
|
||||
#include <srs_app_http_client.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_app_config.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_app_http_conn.hpp>
|
||||
|
||||
#define SRS_HTTP_RESPONSE_OK SRS_XSTR(ERROR_SUCCESS)
|
||||
|
||||
|
@ -371,11 +371,11 @@ int SrsHttpHooks::on_hls_notify(std::string url, SrsRequest* req, std::string ts
|
|||
}
|
||||
srs_warn("GET %s", path.c_str());
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
ISrsHttpMessage* msg = NULL;
|
||||
if ((ret = http.get(path.c_str(), "", &msg)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
SrsAutoFree(SrsHttpMessage, msg);
|
||||
SrsAutoFree(ISrsHttpMessage, msg);
|
||||
|
||||
int nb_buf = srs_min(nb_notify, SRS_HTTP_READ_BUFFER);
|
||||
char* buf = new char[nb_buf];
|
||||
|
@ -416,11 +416,11 @@ int SrsHttpHooks::do_post(std::string url, std::string req, int& code, string& r
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
ISrsHttpMessage* msg = NULL;
|
||||
if ((ret = http.post(uri.get_path(), req, &msg)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
SrsAutoFree(SrsHttpMessage, msg);
|
||||
SrsAutoFree(ISrsHttpMessage, msg);
|
||||
|
||||
code = msg->status_code();
|
||||
if ((ret = msg->body_read_all(res)) != ERROR_SUCCESS) {
|
||||
|
|
|
@ -55,7 +55,7 @@ SrsIngester::SrsIngester()
|
|||
{
|
||||
_srs_config->subscribe(this);
|
||||
|
||||
pthread = new SrsThread("ingest", this, SRS_AUTO_INGESTER_SLEEP_US, true);
|
||||
pthread = new SrsReusableThread("ingest", this, SRS_AUTO_INGESTER_SLEEP_US);
|
||||
pprint = SrsPithyPrint::create_ingester();
|
||||
}
|
||||
|
||||
|
|
|
@ -59,12 +59,12 @@ public:
|
|||
* encode with FFMPEG(optional),
|
||||
* push to SRS(or any RTMP server) over RTMP.
|
||||
*/
|
||||
class SrsIngester : public ISrsThreadHandler, public ISrsReloadHandler
|
||||
class SrsIngester : public ISrsReusableThreadHandler, public ISrsReloadHandler
|
||||
{
|
||||
private:
|
||||
std::vector<SrsIngesterFFMPEG*> ingesters;
|
||||
private:
|
||||
SrsThread* pthread;
|
||||
SrsReusableThread* pthread;
|
||||
SrsPithyPrint* pprint;
|
||||
public:
|
||||
SrsIngester();
|
||||
|
@ -72,7 +72,7 @@ public:
|
|||
public:
|
||||
virtual int start();
|
||||
virtual void stop();
|
||||
// interface ISrsThreadHandler.
|
||||
// interface ISrsReusableThreadHandler.
|
||||
public:
|
||||
virtual int cycle();
|
||||
virtual void on_thread_stop();
|
||||
|
|
|
@ -135,27 +135,34 @@ public:
|
|||
};
|
||||
|
||||
/**
|
||||
* to statistic the kbps of io.
|
||||
* itself can be a statistic source, for example, used for SRS bytes stat.
|
||||
* there are two usage scenarios:
|
||||
* 1. connections to calc kbps by sample():
|
||||
* SrsKbps* kbps = ...;
|
||||
* kbps->set_io(in, out)
|
||||
* kbps->sample()
|
||||
* kbps->get_xxx_kbps().
|
||||
* the connections know how many bytes already send/recv.
|
||||
* 2. server to calc kbps by add_delta():
|
||||
* SrsKbps* kbps = ...;
|
||||
* kbps->set_io(NULL, NULL)
|
||||
* for each connection in connections:
|
||||
* IKbpsDelta* delta = connection; // where connection implements IKbpsDelta
|
||||
* delta->resample()
|
||||
* kbps->add_delta(delta)
|
||||
* delta->cleanup()
|
||||
* kbps->sample()
|
||||
* kbps->get_xxx_kbps().
|
||||
* the server never know how many bytes already send/recv, for the connection maybe closed.
|
||||
*/
|
||||
* to statistic the kbps of io.
|
||||
* itself can be a statistic source, for example, used for SRS bytes stat.
|
||||
* there are some usage scenarios:
|
||||
* 1. connections to calc kbps by sample():
|
||||
* SrsKbps* kbps = ...;
|
||||
* kbps->set_io(in, out)
|
||||
* kbps->sample()
|
||||
* kbps->get_xxx_kbps().
|
||||
* the connections know how many bytes already send/recv.
|
||||
* 2. server to calc kbps by add_delta():
|
||||
* SrsKbps* kbps = ...;
|
||||
* kbps->set_io(NULL, NULL)
|
||||
* for each connection in connections:
|
||||
* IKbpsDelta* delta = connection; // where connection implements IKbpsDelta
|
||||
* delta->resample()
|
||||
* kbps->add_delta(delta)
|
||||
* delta->cleanup()
|
||||
* kbps->sample()
|
||||
* kbps->get_xxx_kbps().
|
||||
* 3. kbps used as IKbpsDelta, to provides delta bytes:
|
||||
* SrsKbps* kbps = ...;
|
||||
* kbps->set_io(in, out);
|
||||
* IKbpsDelta* delta = (IKbpsDelta*)kbps;
|
||||
* delta->resample();
|
||||
* printf("delta is %d/%d", delta->get_send_bytes_delta(), delta->get_recv_bytes_delta());
|
||||
* delta->cleanup();
|
||||
* the server never know how many bytes already send/recv, for the connection maybe closed.
|
||||
*/
|
||||
class SrsKbps : public virtual ISrsProtocolStatistic, public virtual IKbpsDelta
|
||||
{
|
||||
private:
|
||||
|
|
|
@ -79,7 +79,7 @@ SrsUdpListener::SrsUdpListener(ISrsUdpHandler* h, string i, int p)
|
|||
nb_buf = SRS_UDP_MAX_PACKET_SIZE;
|
||||
buf = new char[nb_buf];
|
||||
|
||||
pthread = new SrsThread("udp", this, 0, true);
|
||||
pthread = new SrsReusableThread("udp", this);
|
||||
}
|
||||
|
||||
SrsUdpListener::~SrsUdpListener()
|
||||
|
@ -156,26 +156,24 @@ int SrsUdpListener::listen()
|
|||
int SrsUdpListener::cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// TODO: FIXME: support ipv6, @see man 7 ipv6
|
||||
sockaddr_in from;
|
||||
int nb_from = sizeof(sockaddr_in);
|
||||
int nread = 0;
|
||||
|
||||
if ((nread = st_recvfrom(_stfd, buf, nb_buf, (sockaddr*)&from, &nb_from, ST_UTIME_NO_TIMEOUT)) <= 0) {
|
||||
srs_warn("ignore recv udp packet failed, nread=%d", nread);
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (pthread->can_loop()) {
|
||||
// TODO: FIXME: support ipv6, @see man 7 ipv6
|
||||
sockaddr_in from;
|
||||
int nb_from = sizeof(sockaddr_in);
|
||||
int nread = 0;
|
||||
if ((ret = handler->on_udp_packet(&from, buf, nread)) != ERROR_SUCCESS) {
|
||||
srs_warn("handle udp packet failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((nread = st_recvfrom(_stfd, buf, nb_buf, (sockaddr*)&from, &nb_from, ST_UTIME_NO_TIMEOUT)) <= 0) {
|
||||
srs_warn("ignore recv udp packet failed, nread=%d", nread);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((ret = handler->on_udp_packet(&from, buf, nread)) != ERROR_SUCCESS) {
|
||||
srs_warn("handle udp packet failed. ret=%d", ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SRS_UDP_PACKET_RECV_CYCLE_INTERVAL_MS > 0) {
|
||||
st_usleep(SRS_UDP_PACKET_RECV_CYCLE_INTERVAL_MS * 1000);
|
||||
}
|
||||
if (SRS_UDP_PACKET_RECV_CYCLE_INTERVAL_MS > 0) {
|
||||
st_usleep(SRS_UDP_PACKET_RECV_CYCLE_INTERVAL_MS * 1000);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -190,7 +188,7 @@ SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p)
|
|||
_fd = -1;
|
||||
_stfd = NULL;
|
||||
|
||||
pthread = new SrsThread("tcp", this, 0, true);
|
||||
pthread = new SrsReusableThread("tcp", this);
|
||||
}
|
||||
|
||||
SrsTcpListener::~SrsTcpListener()
|
||||
|
|
|
@ -82,12 +82,12 @@ public:
|
|||
/**
|
||||
* bind udp port, start thread to recv packet and handler it.
|
||||
*/
|
||||
class SrsUdpListener : public ISrsThreadHandler
|
||||
class SrsUdpListener : public ISrsReusableThreadHandler
|
||||
{
|
||||
private:
|
||||
int _fd;
|
||||
st_netfd_t _stfd;
|
||||
SrsThread* pthread;
|
||||
SrsReusableThread* pthread;
|
||||
private:
|
||||
char* buf;
|
||||
int nb_buf;
|
||||
|
@ -103,7 +103,7 @@ public:
|
|||
virtual st_netfd_t stfd();
|
||||
public:
|
||||
virtual int listen();
|
||||
// interface ISrsThreadHandler.
|
||||
// interface ISrsReusableThreadHandler.
|
||||
public:
|
||||
virtual int cycle();
|
||||
};
|
||||
|
@ -111,12 +111,12 @@ public:
|
|||
/**
|
||||
* bind and listen tcp port, use handler to process the client.
|
||||
*/
|
||||
class SrsTcpListener : public ISrsThreadHandler
|
||||
class SrsTcpListener : public ISrsReusableThreadHandler
|
||||
{
|
||||
private:
|
||||
int _fd;
|
||||
st_netfd_t _stfd;
|
||||
SrsThread* pthread;
|
||||
SrsReusableThread* pthread;
|
||||
private:
|
||||
ISrsTcpHandler* handler;
|
||||
std::string ip;
|
||||
|
@ -128,7 +128,7 @@ public:
|
|||
virtual int fd();
|
||||
public:
|
||||
virtual int listen();
|
||||
// interface ISrsThreadHandler.
|
||||
// interface ISrsReusableThreadHandler.
|
||||
public:
|
||||
virtual int cycle();
|
||||
};
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
virtual void trace(const char* tag, int context_id, const char* fmt, ...);
|
||||
virtual void warn(const char* tag, int context_id, const char* fmt, ...);
|
||||
virtual void error(const char* tag, int context_id, const char* fmt, ...);
|
||||
// interface ISrsThreadHandler.
|
||||
// interface ISrsReloadHandler.
|
||||
public:
|
||||
virtual int on_reload_log_tank();
|
||||
virtual int on_reload_log_level();
|
||||
|
|
|
@ -50,7 +50,7 @@ SrsRecvThread::SrsRecvThread(ISrsMessageHandler* msg_handler, SrsRtmpServer* rtm
|
|||
timeout = timeout_ms;
|
||||
handler = msg_handler;
|
||||
rtmp = rtmp_sdk;
|
||||
trd = new SrsThread("recv", this, 0, true);
|
||||
trd = new SrsReusableThread2("recv", this);
|
||||
}
|
||||
|
||||
SrsRecvThread::~SrsRecvThread()
|
||||
|
@ -72,11 +72,16 @@ void SrsRecvThread::stop()
|
|||
trd->stop();
|
||||
}
|
||||
|
||||
void SrsRecvThread::stop_loop()
|
||||
{
|
||||
trd->interrupt();
|
||||
}
|
||||
|
||||
int SrsRecvThread::cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
while (trd->can_loop()) {
|
||||
while (!trd->interrupted()) {
|
||||
if (!handler->can_handle()) {
|
||||
st_usleep(timeout * 1000);
|
||||
continue;
|
||||
|
@ -96,7 +101,7 @@ int SrsRecvThread::cycle()
|
|||
}
|
||||
|
||||
// we use no timeout to recv, should never got any error.
|
||||
trd->stop_loop();
|
||||
trd->interrupt();
|
||||
|
||||
// notice the handler got a recv error.
|
||||
handler->on_recv_error(ret);
|
||||
|
@ -109,11 +114,6 @@ int SrsRecvThread::cycle()
|
|||
return ret;
|
||||
}
|
||||
|
||||
void SrsRecvThread::stop_loop()
|
||||
{
|
||||
trd->stop_loop();
|
||||
}
|
||||
|
||||
void SrsRecvThread::on_thread_start()
|
||||
{
|
||||
// the multiple messages writev improve performance large,
|
||||
|
|
|
@ -79,10 +79,10 @@ public:
|
|||
/**
|
||||
* the recv thread, use message handler to handle each received message.
|
||||
*/
|
||||
class SrsRecvThread : public ISrsThreadHandler
|
||||
class SrsRecvThread : public ISrsReusableThread2Handler
|
||||
{
|
||||
protected:
|
||||
SrsThread* trd;
|
||||
SrsReusableThread2* trd;
|
||||
ISrsMessageHandler* handler;
|
||||
SrsRtmpServer* rtmp;
|
||||
int timeout;
|
||||
|
@ -92,9 +92,10 @@ public:
|
|||
public:
|
||||
virtual int start();
|
||||
virtual void stop();
|
||||
virtual int cycle();
|
||||
virtual void stop_loop();
|
||||
// interface ISrsReusableThread2Handler
|
||||
public:
|
||||
virtual int cycle();
|
||||
virtual void on_thread_start();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
|
|
|
@ -41,7 +41,6 @@ using namespace std;
|
|||
#include <srs_app_config.hpp>
|
||||
#include <srs_app_refer.hpp>
|
||||
#include <srs_app_hls.hpp>
|
||||
#include <srs_app_http.hpp>
|
||||
#include <srs_app_bandwidth.hpp>
|
||||
#include <srs_app_st_socket.hpp>
|
||||
#include <srs_app_http_hooks.hpp>
|
||||
|
|
|
@ -192,7 +192,7 @@ SrsRtspConn::SrsRtspConn(SrsRtspCaster* c, st_netfd_t fd, std::string o)
|
|||
stfd = fd;
|
||||
skt = new SrsStSocket(fd);
|
||||
rtsp = new SrsRtspStack(skt);
|
||||
trd = new SrsThread("rtsp", this, 0, false);
|
||||
trd = new SrsOneCycleThread("rtsp", this);
|
||||
|
||||
req = NULL;
|
||||
io = NULL;
|
||||
|
@ -210,7 +210,6 @@ SrsRtspConn::SrsRtspConn(SrsRtspCaster* c, st_netfd_t fd, std::string o)
|
|||
SrsRtspConn::~SrsRtspConn()
|
||||
{
|
||||
srs_close_stfd(stfd);
|
||||
trd->stop();
|
||||
|
||||
srs_freep(video_rtp);
|
||||
srs_freep(audio_rtp);
|
||||
|
@ -219,7 +218,9 @@ SrsRtspConn::~SrsRtspConn()
|
|||
srs_freep(skt);
|
||||
srs_freep(rtsp);
|
||||
|
||||
close();
|
||||
srs_freep(client);
|
||||
srs_freep(io);
|
||||
srs_freep(req);
|
||||
|
||||
srs_freep(vjitter);
|
||||
srs_freep(ajitter);
|
||||
|
@ -412,9 +413,6 @@ int SrsRtspConn::cycle()
|
|||
srs_warn("client disconnect peer. ret=%d", ret);
|
||||
}
|
||||
|
||||
// terminate thread in the thread cycle itself.
|
||||
trd->stop_loop();
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -763,14 +761,6 @@ int SrsRtspConn::connect_app(string ep_server, string ep_port)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void SrsRtspConn::close()
|
||||
{
|
||||
srs_freep(client);
|
||||
srs_freep(io);
|
||||
srs_freep(req);
|
||||
srs_close_stfd(stfd);
|
||||
}
|
||||
|
||||
SrsRtspCaster::SrsRtspCaster(SrsConfDirective* c)
|
||||
{
|
||||
// TODO: FIXME: support reload.
|
||||
|
|
|
@ -113,7 +113,7 @@ public:
|
|||
/**
|
||||
* the rtsp connection serve the fd.
|
||||
*/
|
||||
class SrsRtspConn : public ISrsThreadHandler
|
||||
class SrsRtspConn : public ISrsOneCycleThreadHandler
|
||||
{
|
||||
private:
|
||||
std::string output_template;
|
||||
|
@ -136,7 +136,7 @@ private:
|
|||
SrsStSocket* skt;
|
||||
SrsRtspStack* rtsp;
|
||||
SrsRtspCaster* caster;
|
||||
SrsThread* trd;
|
||||
SrsOneCycleThread* trd;
|
||||
private:
|
||||
SrsRequest* req;
|
||||
SrsStSocket* io;
|
||||
|
@ -163,7 +163,7 @@ private:
|
|||
// internal methods
|
||||
public:
|
||||
virtual int on_rtp_packet(SrsRtpPacket* pkt, int stream_id);
|
||||
// interface ISrsThreadHandler
|
||||
// interface ISrsOneCycleThreadHandler
|
||||
public:
|
||||
virtual int cycle();
|
||||
virtual void on_thread_stop();
|
||||
|
@ -182,8 +182,6 @@ private:
|
|||
// @remark ignore when not connected, reconnect when disconnected.
|
||||
virtual int connect();
|
||||
virtual int connect_app(std::string ep_server, std::string ep_port);
|
||||
// close the connected io and rtmp to ready to be re-connect.
|
||||
virtual void close();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -367,13 +367,12 @@ SrsSignalManager::SrsSignalManager(SrsServer* server)
|
|||
|
||||
_server = server;
|
||||
sig_pipe[0] = sig_pipe[1] = -1;
|
||||
pthread = new SrsThread("signal", this, 0, true);
|
||||
pthread = new SrsEndlessThread("signal", this);
|
||||
signal_read_stfd = NULL;
|
||||
}
|
||||
|
||||
SrsSignalManager::~SrsSignalManager()
|
||||
{
|
||||
pthread->stop();
|
||||
srs_freep(pthread);
|
||||
|
||||
srs_close_stfd(signal_read_stfd);
|
||||
|
|
|
@ -179,7 +179,7 @@ public:
|
|||
* convert signal to io,
|
||||
* @see: st-1.9/docs/notes.html
|
||||
*/
|
||||
class SrsSignalManager : public ISrsThreadHandler
|
||||
class SrsSignalManager : public ISrsEndlessThreadHandler
|
||||
{
|
||||
private:
|
||||
/* Per-process pipe which is used as a signal queue. */
|
||||
|
@ -188,14 +188,14 @@ private:
|
|||
st_netfd_t signal_read_stfd;
|
||||
private:
|
||||
SrsServer* _server;
|
||||
SrsThread* pthread;
|
||||
SrsEndlessThread* pthread;
|
||||
public:
|
||||
SrsSignalManager(SrsServer* server);
|
||||
virtual ~SrsSignalManager();
|
||||
public:
|
||||
virtual int initialize();
|
||||
virtual int start();
|
||||
// interface ISrsThreadHandler.
|
||||
// interface ISrsEndlessThreadHandler.
|
||||
public:
|
||||
virtual int cycle();
|
||||
private:
|
||||
|
|
|
@ -167,6 +167,7 @@ public:
|
|||
* sample the kbps, add delta bytes of conn.
|
||||
* use kbps_sample() to get all result of kbps stat.
|
||||
*/
|
||||
// TODO: FIXME: the add delta must use IKbpsDelta interface instead.
|
||||
virtual void kbps_add_delta(SrsConnection* conn);
|
||||
/**
|
||||
* calc the result for all kbps.
|
||||
|
|
|
@ -26,206 +26,512 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
|
||||
ISrsThreadHandler::ISrsThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsThreadHandler::~ISrsThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsThreadHandler::on_thread_start()
|
||||
{
|
||||
}
|
||||
|
||||
int ISrsThreadHandler::on_before_cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ISrsThreadHandler::on_end_cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ISrsThreadHandler::on_thread_stop()
|
||||
{
|
||||
}
|
||||
|
||||
SrsThread::SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable)
|
||||
{
|
||||
_name = name;
|
||||
handler = thread_handler;
|
||||
cycle_interval_us = interval_us;
|
||||
namespace internal {
|
||||
ISrsThreadHandler::ISrsThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
tid = NULL;
|
||||
loop = false;
|
||||
really_terminated = true;
|
||||
_cid = -1;
|
||||
_joinable = joinable;
|
||||
ISrsThreadHandler::~ISrsThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
// in start(), the thread cycle method maybe stop and remove the thread itself,
|
||||
// and the thread start() is waiting for the _cid, and segment fault then.
|
||||
// @see https://github.com/simple-rtmp-server/srs/issues/110
|
||||
// thread will set _cid, callback on_thread_start(), then wait for the can_run signal.
|
||||
can_run = false;
|
||||
}
|
||||
|
||||
SrsThread::~SrsThread()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
int SrsThread::cid()
|
||||
{
|
||||
return _cid;
|
||||
}
|
||||
|
||||
int SrsThread::start()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
void ISrsThreadHandler::on_thread_start()
|
||||
{
|
||||
}
|
||||
|
||||
if(tid) {
|
||||
srs_info("thread %s already running.", _name);
|
||||
int ISrsThreadHandler::on_before_cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if((tid = st_thread_create(thread_fun, this, (_joinable? 1:0), 0)) == NULL){
|
||||
ret = ERROR_ST_CREATE_CYCLE_THREAD;
|
||||
srs_error("st_thread_create failed. ret=%d", ret);
|
||||
int ISrsThreadHandler::on_end_cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// we set to loop to true for thread to run.
|
||||
loop = true;
|
||||
|
||||
// wait for cid to ready, for parent thread to get the cid.
|
||||
while (_cid < 0 && loop) {
|
||||
st_usleep(10 * 1000);
|
||||
void ISrsThreadHandler::on_thread_stop()
|
||||
{
|
||||
}
|
||||
|
||||
// now, cycle thread can run.
|
||||
can_run = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsThread::stop()
|
||||
{
|
||||
if (tid) {
|
||||
loop = false;
|
||||
|
||||
// the interrupt will cause the socket to read/write error,
|
||||
// which will terminate the cycle thread.
|
||||
st_thread_interrupt(tid);
|
||||
|
||||
// when joinable, wait util quit.
|
||||
if (_joinable) {
|
||||
// wait the thread to exit.
|
||||
int ret = st_thread_join(tid, NULL);
|
||||
if (ret) {
|
||||
srs_warn("core: ignore join thread failed.");
|
||||
}
|
||||
|
||||
// wait the thread actually terminated.
|
||||
// sometimes the thread join return -1, for example,
|
||||
// when thread use st_recvfrom, the thread join return -1.
|
||||
// so here, we use a variable to ensure the thread stopped.
|
||||
while (!really_terminated) {
|
||||
st_usleep(10 * 1000);
|
||||
|
||||
if (really_terminated) {
|
||||
break;
|
||||
}
|
||||
srs_warn("core: wait thread to actually terminated");
|
||||
}
|
||||
}
|
||||
SrsThread::SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable)
|
||||
{
|
||||
_name = name;
|
||||
handler = thread_handler;
|
||||
cycle_interval_us = interval_us;
|
||||
|
||||
tid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool SrsThread::can_loop()
|
||||
{
|
||||
return loop;
|
||||
}
|
||||
|
||||
void SrsThread::stop_loop()
|
||||
{
|
||||
loop = false;
|
||||
}
|
||||
|
||||
void SrsThread::thread_cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
_srs_context->generate_id();
|
||||
srs_info("thread %s cycle start", _name);
|
||||
|
||||
_cid = _srs_context->get_id();
|
||||
|
||||
srs_assert(handler);
|
||||
handler->on_thread_start();
|
||||
|
||||
// thread is running now.
|
||||
really_terminated = false;
|
||||
|
||||
// wait for cid to ready, for parent thread to get the cid.
|
||||
while (!can_run && loop) {
|
||||
st_usleep(10 * 1000);
|
||||
}
|
||||
|
||||
while (loop) {
|
||||
if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) {
|
||||
srs_warn("thread %s on before cycle failed, ignored and retry, ret=%d", _name, ret);
|
||||
goto failed;
|
||||
}
|
||||
srs_info("thread %s on before cycle success");
|
||||
loop = false;
|
||||
really_terminated = true;
|
||||
_cid = -1;
|
||||
_joinable = joinable;
|
||||
|
||||
if ((ret = handler->cycle()) != ERROR_SUCCESS) {
|
||||
if (!srs_is_client_gracefully_close(ret)) {
|
||||
srs_warn("thread %s cycle failed, ignored and retry, ret=%d", _name, ret);
|
||||
// in start(), the thread cycle method maybe stop and remove the thread itself,
|
||||
// and the thread start() is waiting for the _cid, and segment fault then.
|
||||
// @see https://github.com/simple-rtmp-server/srs/issues/110
|
||||
// thread will set _cid, callback on_thread_start(), then wait for the can_run signal.
|
||||
can_run = false;
|
||||
}
|
||||
|
||||
SrsThread::~SrsThread()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
int SrsThread::cid()
|
||||
{
|
||||
return _cid;
|
||||
}
|
||||
|
||||
int SrsThread::start()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if(tid) {
|
||||
srs_info("thread %s already running.", _name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if((tid = st_thread_create(thread_fun, this, (_joinable? 1:0), 0)) == NULL){
|
||||
ret = ERROR_ST_CREATE_CYCLE_THREAD;
|
||||
srs_error("st_thread_create failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// we set to loop to true for thread to run.
|
||||
loop = true;
|
||||
|
||||
// wait for cid to ready, for parent thread to get the cid.
|
||||
while (_cid < 0 && loop) {
|
||||
st_usleep(10 * 1000);
|
||||
}
|
||||
|
||||
// now, cycle thread can run.
|
||||
can_run = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsThread::stop()
|
||||
{
|
||||
if (tid) {
|
||||
loop = false;
|
||||
|
||||
// the interrupt will cause the socket to read/write error,
|
||||
// which will terminate the cycle thread.
|
||||
st_thread_interrupt(tid);
|
||||
|
||||
// when joinable, wait util quit.
|
||||
if (_joinable) {
|
||||
// wait the thread to exit.
|
||||
int ret = st_thread_join(tid, NULL);
|
||||
if (ret) {
|
||||
srs_warn("core: ignore join thread failed.");
|
||||
}
|
||||
|
||||
// wait the thread actually terminated.
|
||||
// sometimes the thread join return -1, for example,
|
||||
// when thread use st_recvfrom, the thread join return -1.
|
||||
// so here, we use a variable to ensure the thread stopped.
|
||||
while (!really_terminated) {
|
||||
st_usleep(10 * 1000);
|
||||
|
||||
if (really_terminated) {
|
||||
break;
|
||||
}
|
||||
srs_warn("core: wait thread to actually terminated");
|
||||
}
|
||||
}
|
||||
goto failed;
|
||||
}
|
||||
srs_info("thread %s cycle success", _name);
|
||||
|
||||
if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) {
|
||||
srs_warn("thread %s on end cycle failed, ignored and retry, ret=%d", _name, ret);
|
||||
goto failed;
|
||||
}
|
||||
srs_info("thread %s on end cycle success", _name);
|
||||
|
||||
failed:
|
||||
if (!loop) {
|
||||
break;
|
||||
}
|
||||
|
||||
// to improve performance, donot sleep when interval is zero.
|
||||
// @see: https://github.com/simple-rtmp-server/srs/issues/237
|
||||
if (cycle_interval_us != 0) {
|
||||
st_usleep(cycle_interval_us);
|
||||
|
||||
tid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// readly terminated now.
|
||||
really_terminated = true;
|
||||
bool SrsThread::can_loop()
|
||||
{
|
||||
return loop;
|
||||
}
|
||||
|
||||
handler->on_thread_stop();
|
||||
srs_info("thread %s cycle finished", _name);
|
||||
void SrsThread::stop_loop()
|
||||
{
|
||||
loop = false;
|
||||
}
|
||||
|
||||
void SrsThread::thread_cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
_srs_context->generate_id();
|
||||
srs_info("thread %s cycle start", _name);
|
||||
|
||||
_cid = _srs_context->get_id();
|
||||
|
||||
srs_assert(handler);
|
||||
handler->on_thread_start();
|
||||
|
||||
// thread is running now.
|
||||
really_terminated = false;
|
||||
|
||||
// wait for cid to ready, for parent thread to get the cid.
|
||||
while (!can_run && loop) {
|
||||
st_usleep(10 * 1000);
|
||||
}
|
||||
|
||||
while (loop) {
|
||||
if ((ret = handler->on_before_cycle()) != ERROR_SUCCESS) {
|
||||
srs_warn("thread %s on before cycle failed, ignored and retry, ret=%d", _name, ret);
|
||||
goto failed;
|
||||
}
|
||||
srs_info("thread %s on before cycle success");
|
||||
|
||||
if ((ret = handler->cycle()) != ERROR_SUCCESS) {
|
||||
if (!srs_is_client_gracefully_close(ret)) {
|
||||
srs_warn("thread %s cycle failed, ignored and retry, ret=%d", _name, ret);
|
||||
}
|
||||
goto failed;
|
||||
}
|
||||
srs_info("thread %s cycle success", _name);
|
||||
|
||||
if ((ret = handler->on_end_cycle()) != ERROR_SUCCESS) {
|
||||
srs_warn("thread %s on end cycle failed, ignored and retry, ret=%d", _name, ret);
|
||||
goto failed;
|
||||
}
|
||||
srs_info("thread %s on end cycle success", _name);
|
||||
|
||||
failed:
|
||||
if (!loop) {
|
||||
break;
|
||||
}
|
||||
|
||||
// to improve performance, donot sleep when interval is zero.
|
||||
// @see: https://github.com/simple-rtmp-server/srs/issues/237
|
||||
if (cycle_interval_us != 0) {
|
||||
st_usleep(cycle_interval_us);
|
||||
}
|
||||
}
|
||||
|
||||
// readly terminated now.
|
||||
really_terminated = true;
|
||||
|
||||
handler->on_thread_stop();
|
||||
srs_info("thread %s cycle finished", _name);
|
||||
}
|
||||
|
||||
void* SrsThread::thread_fun(void* arg)
|
||||
{
|
||||
SrsThread* obj = (SrsThread*)arg;
|
||||
srs_assert(obj);
|
||||
|
||||
obj->thread_cycle();
|
||||
|
||||
st_thread_exit(NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void* SrsThread::thread_fun(void* arg)
|
||||
ISrsEndlessThreadHandler::ISrsEndlessThreadHandler()
|
||||
{
|
||||
SrsThread* obj = (SrsThread*)arg;
|
||||
srs_assert(obj);
|
||||
|
||||
obj->thread_cycle();
|
||||
|
||||
st_thread_exit(NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsEndlessThreadHandler::~ISrsEndlessThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsEndlessThreadHandler::on_thread_start()
|
||||
{
|
||||
}
|
||||
|
||||
int ISrsEndlessThreadHandler::on_before_cycle()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int ISrsEndlessThreadHandler::on_end_cycle()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void ISrsEndlessThreadHandler::on_thread_stop()
|
||||
{
|
||||
}
|
||||
|
||||
SrsEndlessThread::SrsEndlessThread(const char* n, ISrsEndlessThreadHandler* h)
|
||||
{
|
||||
handler = h;
|
||||
pthread = new internal::SrsThread(n, this, 0, false);
|
||||
}
|
||||
|
||||
SrsEndlessThread::~SrsEndlessThread()
|
||||
{
|
||||
pthread->stop();
|
||||
srs_freep(pthread);
|
||||
}
|
||||
|
||||
int SrsEndlessThread::start()
|
||||
{
|
||||
return pthread->start();
|
||||
}
|
||||
|
||||
int SrsEndlessThread::cycle()
|
||||
{
|
||||
return handler->cycle();
|
||||
}
|
||||
|
||||
void SrsEndlessThread::on_thread_start()
|
||||
{
|
||||
handler->on_thread_start();
|
||||
}
|
||||
|
||||
int SrsEndlessThread::on_before_cycle()
|
||||
{
|
||||
return handler->on_before_cycle();
|
||||
}
|
||||
|
||||
int SrsEndlessThread::on_end_cycle()
|
||||
{
|
||||
return handler->on_end_cycle();
|
||||
}
|
||||
|
||||
void SrsEndlessThread::on_thread_stop()
|
||||
{
|
||||
handler->on_thread_stop();
|
||||
}
|
||||
|
||||
ISrsOneCycleThreadHandler::ISrsOneCycleThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsOneCycleThreadHandler::~ISrsOneCycleThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsOneCycleThreadHandler::on_thread_start()
|
||||
{
|
||||
}
|
||||
|
||||
int ISrsOneCycleThreadHandler::on_before_cycle()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int ISrsOneCycleThreadHandler::on_end_cycle()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void ISrsOneCycleThreadHandler::on_thread_stop()
|
||||
{
|
||||
}
|
||||
|
||||
SrsOneCycleThread::SrsOneCycleThread(const char* n, ISrsOneCycleThreadHandler* h)
|
||||
{
|
||||
handler = h;
|
||||
pthread = new internal::SrsThread(n, this, 0, false);
|
||||
}
|
||||
|
||||
SrsOneCycleThread::~SrsOneCycleThread()
|
||||
{
|
||||
pthread->stop();
|
||||
srs_freep(pthread);
|
||||
}
|
||||
|
||||
int SrsOneCycleThread::start()
|
||||
{
|
||||
return pthread->start();
|
||||
}
|
||||
|
||||
int SrsOneCycleThread::cycle()
|
||||
{
|
||||
int ret = handler->cycle();
|
||||
pthread->stop_loop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsOneCycleThread::on_thread_start()
|
||||
{
|
||||
handler->on_thread_start();
|
||||
}
|
||||
|
||||
int SrsOneCycleThread::on_before_cycle()
|
||||
{
|
||||
return handler->on_before_cycle();
|
||||
}
|
||||
|
||||
int SrsOneCycleThread::on_end_cycle()
|
||||
{
|
||||
return handler->on_end_cycle();
|
||||
}
|
||||
|
||||
void SrsOneCycleThread::on_thread_stop()
|
||||
{
|
||||
handler->on_thread_stop();
|
||||
}
|
||||
|
||||
ISrsReusableThreadHandler::ISrsReusableThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsReusableThreadHandler::~ISrsReusableThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsReusableThreadHandler::on_thread_start()
|
||||
{
|
||||
}
|
||||
|
||||
int ISrsReusableThreadHandler::on_before_cycle()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int ISrsReusableThreadHandler::on_end_cycle()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void ISrsReusableThreadHandler::on_thread_stop()
|
||||
{
|
||||
}
|
||||
|
||||
SrsReusableThread::SrsReusableThread(const char* n, ISrsReusableThreadHandler* h, int64_t interval_us)
|
||||
{
|
||||
handler = h;
|
||||
pthread = new internal::SrsThread(n, this, interval_us, true);
|
||||
}
|
||||
|
||||
SrsReusableThread::~SrsReusableThread()
|
||||
{
|
||||
pthread->stop();
|
||||
srs_freep(pthread);
|
||||
}
|
||||
|
||||
int SrsReusableThread::start()
|
||||
{
|
||||
return pthread->start();
|
||||
}
|
||||
|
||||
void SrsReusableThread::stop()
|
||||
{
|
||||
pthread->stop();
|
||||
}
|
||||
|
||||
int SrsReusableThread::cid()
|
||||
{
|
||||
return pthread->cid();
|
||||
}
|
||||
|
||||
int SrsReusableThread::cycle()
|
||||
{
|
||||
return handler->cycle();
|
||||
}
|
||||
|
||||
void SrsReusableThread::on_thread_start()
|
||||
{
|
||||
handler->on_thread_start();
|
||||
}
|
||||
|
||||
int SrsReusableThread::on_before_cycle()
|
||||
{
|
||||
return handler->on_before_cycle();
|
||||
}
|
||||
|
||||
int SrsReusableThread::on_end_cycle()
|
||||
{
|
||||
return handler->on_end_cycle();
|
||||
}
|
||||
|
||||
void SrsReusableThread::on_thread_stop()
|
||||
{
|
||||
handler->on_thread_stop();
|
||||
}
|
||||
|
||||
ISrsReusableThread2Handler::ISrsReusableThread2Handler()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsReusableThread2Handler::~ISrsReusableThread2Handler()
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsReusableThread2Handler::on_thread_start()
|
||||
{
|
||||
}
|
||||
|
||||
int ISrsReusableThread2Handler::on_before_cycle()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int ISrsReusableThread2Handler::on_end_cycle()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void ISrsReusableThread2Handler::on_thread_stop()
|
||||
{
|
||||
}
|
||||
|
||||
SrsReusableThread2::SrsReusableThread2(const char* n, ISrsReusableThread2Handler* h, int64_t interval_us)
|
||||
{
|
||||
handler = h;
|
||||
pthread = new internal::SrsThread(n, this, interval_us, true);
|
||||
}
|
||||
|
||||
SrsReusableThread2::~SrsReusableThread2()
|
||||
{
|
||||
pthread->stop();
|
||||
srs_freep(pthread);
|
||||
}
|
||||
|
||||
int SrsReusableThread2::start()
|
||||
{
|
||||
return pthread->start();
|
||||
}
|
||||
|
||||
void SrsReusableThread2::stop()
|
||||
{
|
||||
pthread->stop();
|
||||
}
|
||||
|
||||
int SrsReusableThread2::cid()
|
||||
{
|
||||
return pthread->cid();
|
||||
}
|
||||
|
||||
void SrsReusableThread2::interrupt()
|
||||
{
|
||||
pthread->stop_loop();
|
||||
}
|
||||
|
||||
bool SrsReusableThread2::interrupted()
|
||||
{
|
||||
return !pthread->can_loop();
|
||||
}
|
||||
|
||||
int SrsReusableThread2::cycle()
|
||||
{
|
||||
return handler->cycle();
|
||||
}
|
||||
|
||||
void SrsReusableThread2::on_thread_start()
|
||||
{
|
||||
handler->on_thread_start();
|
||||
}
|
||||
|
||||
int SrsReusableThread2::on_before_cycle()
|
||||
{
|
||||
return handler->on_before_cycle();
|
||||
}
|
||||
|
||||
int SrsReusableThread2::on_end_cycle()
|
||||
{
|
||||
return handler->on_end_cycle();
|
||||
}
|
||||
|
||||
void SrsReusableThread2::on_thread_stop()
|
||||
{
|
||||
handler->on_thread_stop();
|
||||
}
|
||||
|
||||
|
|
|
@ -31,189 +31,421 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#include <srs_app_st.hpp>
|
||||
|
||||
// the internal classes, user should never use it.
|
||||
// user should use the public classes at the bellow:
|
||||
// @see SrsEndlessThread, SrsOneCycleThread, SrsReusableThread
|
||||
namespace internal {
|
||||
/**
|
||||
* the handler for the thread, callback interface.
|
||||
* the thread model defines as:
|
||||
* handler->on_thread_start()
|
||||
* while loop:
|
||||
* handler->on_before_cycle()
|
||||
* handler->cycle()
|
||||
* handler->on_end_cycle()
|
||||
* if !loop then break for user stop thread.
|
||||
* sleep(CycleIntervalMilliseconds)
|
||||
* handler->on_thread_stop()
|
||||
* when stop, the thread will interrupt the st_thread,
|
||||
* which will cause the socket to return error and
|
||||
* terminate the cycle thread.
|
||||
*
|
||||
* @remark why should check can_loop() in cycle method?
|
||||
* when thread interrupt, the socket maybe not got EINT,
|
||||
* espectially on st_usleep(), so the cycle must check the loop,
|
||||
* when handler->cycle() has loop itself, for example:
|
||||
* while (true):
|
||||
* if (read_from_socket(skt) < 0) break;
|
||||
* if thread stop when read_from_socket, it's ok, the loop will break,
|
||||
* but when thread stop interrupt the s_usleep(0), then the loop is
|
||||
* death loop.
|
||||
* in a word, the handler->cycle() must:
|
||||
* while (pthread->can_loop()):
|
||||
* if (read_from_socket(skt) < 0) break;
|
||||
* check the loop, then it works.
|
||||
*
|
||||
* @remark why should use stop_loop() to terminate thread in itself?
|
||||
* in the thread itself, that is the cycle method,
|
||||
* if itself want to terminate the thread, should never use stop(),
|
||||
* but use stop_loop() to set the loop to false and terminate normally.
|
||||
*
|
||||
* @remark when should set the interval_us, and when not?
|
||||
* the cycle will invoke util cannot loop, eventhough the return code of cycle is error,
|
||||
* so the interval_us used to sleep for each cycle.
|
||||
*/
|
||||
class ISrsThreadHandler
|
||||
{
|
||||
public:
|
||||
ISrsThreadHandler();
|
||||
virtual ~ISrsThreadHandler();
|
||||
public:
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int cycle() = 0;
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
|
||||
/**
|
||||
* provides servies from st_thread_t,
|
||||
* for common thread usage.
|
||||
*/
|
||||
class SrsThread
|
||||
{
|
||||
private:
|
||||
st_thread_t tid;
|
||||
int _cid;
|
||||
bool loop;
|
||||
bool can_run;
|
||||
bool really_terminated;
|
||||
bool _joinable;
|
||||
const char* _name;
|
||||
private:
|
||||
ISrsThreadHandler* handler;
|
||||
int64_t cycle_interval_us;
|
||||
public:
|
||||
/**
|
||||
* initialize the thread.
|
||||
* @param name, human readable name for st debug.
|
||||
* @param thread_handler, the cycle handler for the thread.
|
||||
* @param interval_us, the sleep interval when cycle finished.
|
||||
* @param joinable, if joinable, other thread must stop the thread.
|
||||
* @remark if joinable, thread never quit itself, or memory leak.
|
||||
* @see: https://github.com/simple-rtmp-server/srs/issues/78
|
||||
* @remark about st debug, see st-1.9/README, _st_iterate_threads_flag
|
||||
*/
|
||||
/**
|
||||
* TODO: FIXME: maybe all thread must be reap by others threads,
|
||||
* @see: https://github.com/simple-rtmp-server/srs/issues/77
|
||||
*/
|
||||
SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable);
|
||||
virtual ~SrsThread();
|
||||
public:
|
||||
/**
|
||||
* get the context id. @see: ISrsThreadContext.get_id().
|
||||
* used for parent thread to get the id.
|
||||
* @remark when start thread, parent thread will block and wait for this id ready.
|
||||
*/
|
||||
virtual int cid();
|
||||
/**
|
||||
* start the thread, invoke the cycle of handler util
|
||||
* user stop the thread.
|
||||
* @remark ignore any error of cycle of handler.
|
||||
* @remark user can start multiple times, ignore if already started.
|
||||
* @remark wait for the cid is set by thread pfn.
|
||||
*/
|
||||
virtual int start();
|
||||
/**
|
||||
* stop the thread, wait for the thread to terminate.
|
||||
* @remark user can stop multiple times, ignore if already stopped.
|
||||
*/
|
||||
virtual void stop();
|
||||
public:
|
||||
/**
|
||||
* whether the thread should loop,
|
||||
* used for handler->cycle() which has a loop method,
|
||||
* to check this method, break if false.
|
||||
*/
|
||||
virtual bool can_loop();
|
||||
/**
|
||||
* for the loop thread to stop the loop.
|
||||
* other thread can directly use stop() to stop loop and wait for quit.
|
||||
* this stop loop method only set loop to false.
|
||||
*/
|
||||
virtual void stop_loop();
|
||||
private:
|
||||
virtual void thread_cycle();
|
||||
static void* thread_fun(void* arg);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* the handler for the thread, callback interface.
|
||||
* the thread model defines as:
|
||||
* handler->on_thread_start()
|
||||
* while loop:
|
||||
* handler->on_before_cycle()
|
||||
* handler->cycle()
|
||||
* handler->on_end_cycle()
|
||||
* if !loop then break for user stop thread.
|
||||
* sleep(CycleIntervalMilliseconds)
|
||||
* handler->on_thread_stop()
|
||||
* when stop, the thread will interrupt the st_thread,
|
||||
* which will cause the socket to return error and
|
||||
* terminate the cycle thread.
|
||||
*
|
||||
* Usage 1: loop thread never quit.
|
||||
* the endless thread is a loop thread never quit.
|
||||
* user can create thread always running util server terminate.
|
||||
* the step to create a thread never stop:
|
||||
* 1. create SrsThread field, with joinable false.
|
||||
* 1. create SrsEndlessThread field.
|
||||
* for example:
|
||||
* class SrsStreamCache : public ISrsThreadHandler {
|
||||
* public: SrsStreamCache() { pthread = new SrsThread("http-stream", this, SRS_AUTO_STREAM_SLEEP_US, false); }
|
||||
* class SrsStreamCache : public ISrsEndlessThreadHandler {
|
||||
* public: SrsStreamCache() { pthread = new SrsEndlessThread("http-stream", this); }
|
||||
* public: virtual int cycle() {
|
||||
* // check status, start ffmpeg when stopped.
|
||||
* // do some work never end.
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* Usage 2: stop by other thread.
|
||||
* user can create thread and stop then start again and again,
|
||||
* generally must provides a start and stop method, @see SrsIngester.
|
||||
* the step to create a thread stop by other thread:
|
||||
* 1. create SrsThread field, with joinable true.
|
||||
* 2. must use stop to stop and join the thread.
|
||||
* for example:
|
||||
* class SrsIngester : public ISrsThreadHandler {
|
||||
* public: SrsIngester() { pthread = new SrsThread("ingest", this, SRS_AUTO_INGESTER_SLEEP_US, true); }
|
||||
* public: virtual int start() { return pthread->start(); }
|
||||
* public: virtual void stop() { pthread->stop(); }
|
||||
* public: virtual int cycle() {
|
||||
* // check status, start ffmpeg when stopped.
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* Usage 3: stop by thread itself.
|
||||
* @remark user must use block method in cycle method, for example, sleep or socket io.
|
||||
*/
|
||||
class ISrsEndlessThreadHandler
|
||||
{
|
||||
public:
|
||||
ISrsEndlessThreadHandler();
|
||||
virtual ~ISrsEndlessThreadHandler();
|
||||
public:
|
||||
/**
|
||||
* the cycle method for the common thread.
|
||||
* @remark user must use block method in cycle method, for example, sleep or socket io.
|
||||
*/
|
||||
virtual int cycle() = 0;
|
||||
public:
|
||||
/**
|
||||
* other callback for handler.
|
||||
* @remark all callback is optional, handler can ignore it.
|
||||
*/
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
class SrsEndlessThread : public internal::ISrsThreadHandler
|
||||
{
|
||||
private:
|
||||
internal::SrsThread* pthread;
|
||||
ISrsEndlessThreadHandler* handler;
|
||||
public:
|
||||
SrsEndlessThread(const char* n, ISrsEndlessThreadHandler* h);
|
||||
virtual ~SrsEndlessThread();
|
||||
public:
|
||||
/**
|
||||
* for the endless thread, never quit.
|
||||
*/
|
||||
virtual int start();
|
||||
// interface internal::ISrsThreadHandler
|
||||
public:
|
||||
virtual int cycle();
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
|
||||
/**
|
||||
* the one cycle thread is a thread do the cycle only one time,
|
||||
* that is, the thread will quit when return from the cycle.
|
||||
* user can create thread which stop itself,
|
||||
* generally only need to provides a start method,
|
||||
* the object will destroy itself then terminate the thread, @see SrsConnection
|
||||
* 1. create SrsThread field, with joinable false.
|
||||
* 2. owner stop thread loop, destroy itself when thread stop.
|
||||
* 1. create SrsThread field
|
||||
* 2. the thread quit when return from cycle.
|
||||
* for example:
|
||||
* class SrsConnection : public ISrsThreadHandler {
|
||||
* public: SrsConnection() { pthread = new SrsThread("conn", this, 0, false); }
|
||||
* class SrsConnection : public ISrsOneCycleThreadHandler {
|
||||
* public: SrsConnection() { pthread = new SrsOneCycleThread("conn", this); }
|
||||
* public: virtual int start() { return pthread->start(); }
|
||||
* public: virtual int cycle() {
|
||||
* // serve client.
|
||||
* // set loop to stop to quit, stop thread itself.
|
||||
* pthread->stop_loop();
|
||||
* }
|
||||
* public: virtual int on_thread_stop() {
|
||||
* public: virtual void on_thread_stop() {
|
||||
* // remove the connection in thread itself.
|
||||
* server->remove(this);
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* Usage 4: loop in the cycle method.
|
||||
* user can use loop code in the cycle method, @see SrsForwarder
|
||||
* 1. create SrsThread field, with or without joinable is ok.
|
||||
* 2. loop code in cycle method, check the can_loop() for thread to quit.
|
||||
* for example:
|
||||
* class SrsForwarder : public ISrsThreadHandler {
|
||||
* public: virtual int cycle() {
|
||||
* while (pthread->can_loop()) {
|
||||
* // read msgs from queue and forward to server.
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* @remark why should check can_loop() in cycle method?
|
||||
* when thread interrupt, the socket maybe not got EINT,
|
||||
* espectially on st_usleep(), so the cycle must check the loop,
|
||||
* when handler->cycle() has loop itself, for example:
|
||||
* while (true):
|
||||
* if (read_from_socket(skt) < 0) break;
|
||||
* if thread stop when read_from_socket, it's ok, the loop will break,
|
||||
* but when thread stop interrupt the s_usleep(0), then the loop is
|
||||
* death loop.
|
||||
* in a word, the handler->cycle() must:
|
||||
* while (pthread->can_loop()):
|
||||
* if (read_from_socket(skt) < 0) break;
|
||||
* check the loop, then it works.
|
||||
*
|
||||
* @remark why should use stop_loop() to terminate thread in itself?
|
||||
* in the thread itself, that is the cycle method,
|
||||
* if itself want to terminate the thread, should never use stop(),
|
||||
* but use stop_loop() to set the loop to false and terminate normally.
|
||||
*
|
||||
* @remark when should set the interval_us, and when not?
|
||||
* the cycle will invoke util cannot loop, eventhough the return code of cycle is error,
|
||||
* so the interval_us used to sleep for each cycle.
|
||||
*/
|
||||
class ISrsThreadHandler
|
||||
class ISrsOneCycleThreadHandler
|
||||
{
|
||||
public:
|
||||
ISrsThreadHandler();
|
||||
virtual ~ISrsThreadHandler();
|
||||
ISrsOneCycleThreadHandler();
|
||||
virtual ~ISrsOneCycleThreadHandler();
|
||||
public:
|
||||
/**
|
||||
* the cycle method for the one cycle thread.
|
||||
*/
|
||||
virtual int cycle() = 0;
|
||||
public:
|
||||
/**
|
||||
* other callback for handler.
|
||||
* @remark all callback is optional, handler can ignore it.
|
||||
*/
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
class SrsOneCycleThread : public internal::ISrsThreadHandler
|
||||
{
|
||||
private:
|
||||
internal::SrsThread* pthread;
|
||||
ISrsOneCycleThreadHandler* handler;
|
||||
public:
|
||||
SrsOneCycleThread(const char* n, ISrsOneCycleThreadHandler* h);
|
||||
virtual ~SrsOneCycleThread();
|
||||
public:
|
||||
/**
|
||||
* for the one cycle thread, quit when cycle return.
|
||||
*/
|
||||
virtual int start();
|
||||
// interface internal::ISrsThreadHandler
|
||||
public:
|
||||
virtual int cycle();
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int cycle() = 0;
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
|
||||
/**
|
||||
* provides servies from st_thread_t,
|
||||
* for common thread usage.
|
||||
*/
|
||||
class SrsThread
|
||||
* the reuse thread is a thread stop and start by other thread.
|
||||
* user can create thread and stop then start again and again,
|
||||
* generally must provides a start and stop method, @see SrsIngester.
|
||||
* the step to create a thread stop by other thread:
|
||||
* 1. create SrsReusableThread field.
|
||||
* 2. must manually stop the thread when started it.
|
||||
* for example:
|
||||
* class SrsIngester : public ISrsReusableThreadHandler {
|
||||
* public: SrsIngester() { pthread = new SrsReusableThread("ingest", this, SRS_AUTO_INGESTER_SLEEP_US); }
|
||||
* public: virtual int start() { return pthread->start(); }
|
||||
* public: virtual void stop() { pthread->stop(); }
|
||||
* public: virtual int cycle() {
|
||||
* // check status, start ffmpeg when stopped.
|
||||
* }
|
||||
* };
|
||||
*/
|
||||
class ISrsReusableThreadHandler
|
||||
{
|
||||
public:
|
||||
ISrsReusableThreadHandler();
|
||||
virtual ~ISrsReusableThreadHandler();
|
||||
public:
|
||||
/**
|
||||
* the cycle method for the one cycle thread.
|
||||
* @remark when the cycle has its inner loop, it must check whether
|
||||
* the thread is interrupted.
|
||||
*/
|
||||
virtual int cycle() = 0;
|
||||
public:
|
||||
/**
|
||||
* other callback for handler.
|
||||
* @remark all callback is optional, handler can ignore it.
|
||||
*/
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
class SrsReusableThread : public internal::ISrsThreadHandler
|
||||
{
|
||||
private:
|
||||
st_thread_t tid;
|
||||
int _cid;
|
||||
bool loop;
|
||||
bool can_run;
|
||||
bool really_terminated;
|
||||
bool _joinable;
|
||||
const char* _name;
|
||||
private:
|
||||
ISrsThreadHandler* handler;
|
||||
int64_t cycle_interval_us;
|
||||
internal::SrsThread* pthread;
|
||||
ISrsReusableThreadHandler* handler;
|
||||
public:
|
||||
SrsReusableThread(const char* n, ISrsReusableThreadHandler* h, int64_t interval_us = 0);
|
||||
virtual ~SrsReusableThread();
|
||||
public:
|
||||
/**
|
||||
* initialize the thread.
|
||||
* @param name, human readable name for st debug.
|
||||
* @param thread_handler, the cycle handler for the thread.
|
||||
* @param interval_us, the sleep interval when cycle finished.
|
||||
* @param joinable, if joinable, other thread must stop the thread.
|
||||
* @remark if joinable, thread never quit itself, or memory leak.
|
||||
* @see: https://github.com/simple-rtmp-server/srs/issues/78
|
||||
* @remark about st debug, see st-1.9/README, _st_iterate_threads_flag
|
||||
*/
|
||||
/**
|
||||
* TODO: FIXME: maybe all thread must be reap by others threads,
|
||||
* @see: https://github.com/simple-rtmp-server/srs/issues/77
|
||||
*/
|
||||
SrsThread(const char* name, ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable);
|
||||
virtual ~SrsThread();
|
||||
public:
|
||||
/**
|
||||
* get the context id. @see: ISrsThreadContext.get_id().
|
||||
* used for parent thread to get the id.
|
||||
* @remark when start thread, parent thread will block and wait for this id ready.
|
||||
*/
|
||||
virtual int cid();
|
||||
/**
|
||||
* start the thread, invoke the cycle of handler util
|
||||
* user stop the thread.
|
||||
* @remark ignore any error of cycle of handler.
|
||||
* @remark user can start multiple times, ignore if already started.
|
||||
* @remark wait for the cid is set by thread pfn.
|
||||
*/
|
||||
* for the reusable thread, start and stop by user.
|
||||
*/
|
||||
virtual int start();
|
||||
/**
|
||||
* stop the thread, wait for the thread to terminate.
|
||||
* @remark user can stop multiple times, ignore if already stopped.
|
||||
*/
|
||||
* stop the thread, wait for the thread to terminate.
|
||||
* @remark user can stop multiple times, ignore if already stopped.
|
||||
*/
|
||||
virtual void stop();
|
||||
public:
|
||||
/**
|
||||
* whether the thread should loop,
|
||||
* used for handler->cycle() which has a loop method,
|
||||
* to check this method, break if false.
|
||||
*/
|
||||
virtual bool can_loop();
|
||||
* get the context id. @see: ISrsThreadContext.get_id().
|
||||
* used for parent thread to get the id.
|
||||
* @remark when start thread, parent thread will block and wait for this id ready.
|
||||
*/
|
||||
virtual int cid();
|
||||
// interface internal::ISrsThreadHandler
|
||||
public:
|
||||
virtual int cycle();
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
|
||||
/**
|
||||
* the reuse thread is a thread stop and start by other thread.
|
||||
* the version 2, is the thread cycle has its inner loop, which should
|
||||
* check the intterrupt, and should interrupt thread when the inner loop want
|
||||
* to quit the thread.
|
||||
* user can create thread and stop then start again and again,
|
||||
* generally must provides a start and stop method, @see SrsIngester.
|
||||
* the step to create a thread stop by other thread:
|
||||
* 1. create SrsReusableThread field.
|
||||
* 2. must manually stop the thread when started it.
|
||||
* for example:
|
||||
* class SrsIngester : public ISrsReusableThreadHandler {
|
||||
* public: SrsIngester() { pthread = new SrsReusableThread("ingest", this, SRS_AUTO_INGESTER_SLEEP_US); }
|
||||
* public: virtual int start() { return pthread->start(); }
|
||||
* public: virtual void stop() { pthread->stop(); }
|
||||
* public: virtual int cycle() {
|
||||
* while (!pthread->interrupted()) {
|
||||
* // quit thread when error.
|
||||
* if (ret != ERROR_SUCCESS) {
|
||||
* pthread->interrupt();
|
||||
* }
|
||||
*
|
||||
* // do something.
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*/
|
||||
class ISrsReusableThread2Handler
|
||||
{
|
||||
public:
|
||||
ISrsReusableThread2Handler();
|
||||
virtual ~ISrsReusableThread2Handler();
|
||||
public:
|
||||
/**
|
||||
* for the loop thread to stop the loop.
|
||||
* other thread can directly use stop() to stop loop and wait for quit.
|
||||
* this stop loop method only set loop to false.
|
||||
*/
|
||||
virtual void stop_loop();
|
||||
* the cycle method for the one cycle thread.
|
||||
* @remark when the cycle has its inner loop, it must check whether
|
||||
* the thread is interrupted.
|
||||
*/
|
||||
virtual int cycle() = 0;
|
||||
public:
|
||||
/**
|
||||
* other callback for handler.
|
||||
* @remark all callback is optional, handler can ignore it.
|
||||
*/
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
class SrsReusableThread2 : public internal::ISrsThreadHandler
|
||||
{
|
||||
private:
|
||||
virtual void thread_cycle();
|
||||
static void* thread_fun(void* arg);
|
||||
internal::SrsThread* pthread;
|
||||
ISrsReusableThread2Handler* handler;
|
||||
public:
|
||||
SrsReusableThread2(const char* n, ISrsReusableThread2Handler* h, int64_t interval_us = 0);
|
||||
virtual ~SrsReusableThread2();
|
||||
public:
|
||||
/**
|
||||
* for the reusable thread, start and stop by user.
|
||||
*/
|
||||
virtual int start();
|
||||
/**
|
||||
* stop the thread, wait for the thread to terminate.
|
||||
* @remark user can stop multiple times, ignore if already stopped.
|
||||
*/
|
||||
virtual void stop();
|
||||
public:
|
||||
/**
|
||||
* get the context id. @see: ISrsThreadContext.get_id().
|
||||
* used for parent thread to get the id.
|
||||
* @remark when start thread, parent thread will block and wait for this id ready.
|
||||
*/
|
||||
virtual int cid();
|
||||
/**
|
||||
* interrupt the thread to stop loop.
|
||||
* we only set the loop flag to false, not really interrupt the thread.
|
||||
*/
|
||||
virtual void interrupt();
|
||||
/**
|
||||
* whether the thread is interrupted,
|
||||
* for the cycle has its loop, the inner loop should quit when thread
|
||||
* is interrupted.
|
||||
*/
|
||||
virtual bool interrupted();
|
||||
// interface internal::ISrsThreadHandler
|
||||
public:
|
||||
virtual int cycle();
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,7 +39,6 @@ using namespace std;
|
|||
#include <srs_kernel_stream.hpp>
|
||||
#include <srs_kernel_ts.hpp>
|
||||
#include <srs_app_http_client.hpp>
|
||||
#include <srs_app_http.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_app_st.hpp>
|
||||
#include <srs_rtmp_utility.hpp>
|
||||
|
@ -47,6 +46,7 @@ using namespace std;
|
|||
#include <srs_app_utility.hpp>
|
||||
#include <srs_rtmp_amf0.hpp>
|
||||
#include <srs_raw_avc.hpp>
|
||||
#include <srs_app_http_conn.hpp>
|
||||
|
||||
// pre-declare
|
||||
int proxy_hls2rtmp(std::string hls, std::string rtmp);
|
||||
|
@ -383,14 +383,14 @@ int SrsIngestSrsInput::parseM3u8(SrsHttpUri* url, double& td, double& duration)
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
ISrsHttpMessage* msg = NULL;
|
||||
if ((ret = client.get(url->get_path(), "", &msg)) != ERROR_SUCCESS) {
|
||||
srs_error("HTTP GET %s failed. ret=%d", url->get_url(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_assert(msg);
|
||||
SrsAutoFree(SrsHttpMessage, msg);
|
||||
SrsAutoFree(ISrsHttpMessage, msg);
|
||||
|
||||
std::string body;
|
||||
if ((ret = msg->body_read_all(body)) != ERROR_SUCCESS) {
|
||||
|
@ -605,14 +605,14 @@ int SrsIngestSrsInput::SrsTsPiece::fetch(string m3u8)
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpMessage* msg = NULL;
|
||||
ISrsHttpMessage* msg = NULL;
|
||||
if ((ret = client.get(uri.get_path(), "", &msg)) != ERROR_SUCCESS) {
|
||||
srs_error("HTTP GET %s failed. ret=%d", uri.get_url(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_assert(msg);
|
||||
SrsAutoFree(SrsHttpMessage, msg);
|
||||
SrsAutoFree(ISrsHttpMessage, msg);
|
||||
|
||||
if ((ret = msg->body_read_all(body)) != ERROR_SUCCESS) {
|
||||
srs_error("read ts failed. ret=%d", ret);
|
||||
|
|
738
trunk/src/protocol/srs_http_stack.cpp
Normal file
738
trunk/src/protocol/srs_http_stack.cpp
Normal file
|
@ -0,0 +1,738 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 SRS(simple-rtmp-server)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <srs_http_stack.hpp>
|
||||
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
#include <srs_kernel_file.hpp>
|
||||
|
||||
#define SRS_HTTP_DEFAULT_PAGE "index.html"
|
||||
|
||||
// get the status text of code.
|
||||
string srs_generate_http_status_text(int status)
|
||||
{
|
||||
static std::map<int, std::string> _status_map;
|
||||
if (_status_map.empty()) {
|
||||
_status_map[SRS_CONSTS_HTTP_Continue ] = SRS_CONSTS_HTTP_Continue_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_SwitchingProtocols ] = SRS_CONSTS_HTTP_SwitchingProtocols_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_OK ] = SRS_CONSTS_HTTP_OK_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_Created ] = SRS_CONSTS_HTTP_Created_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_Accepted ] = SRS_CONSTS_HTTP_Accepted_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_NonAuthoritativeInformation ] = SRS_CONSTS_HTTP_NonAuthoritativeInformation_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_NoContent ] = SRS_CONSTS_HTTP_NoContent_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_ResetContent ] = SRS_CONSTS_HTTP_ResetContent_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_PartialContent ] = SRS_CONSTS_HTTP_PartialContent_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_MultipleChoices ] = SRS_CONSTS_HTTP_MultipleChoices_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_MovedPermanently ] = SRS_CONSTS_HTTP_MovedPermanently_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_Found ] = SRS_CONSTS_HTTP_Found_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_SeeOther ] = SRS_CONSTS_HTTP_SeeOther_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_NotModified ] = SRS_CONSTS_HTTP_NotModified_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_UseProxy ] = SRS_CONSTS_HTTP_UseProxy_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_TemporaryRedirect ] = SRS_CONSTS_HTTP_TemporaryRedirect_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_BadRequest ] = SRS_CONSTS_HTTP_BadRequest_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_Unauthorized ] = SRS_CONSTS_HTTP_Unauthorized_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_PaymentRequired ] = SRS_CONSTS_HTTP_PaymentRequired_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_Forbidden ] = SRS_CONSTS_HTTP_Forbidden_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_NotFound ] = SRS_CONSTS_HTTP_NotFound_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_MethodNotAllowed ] = SRS_CONSTS_HTTP_MethodNotAllowed_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_NotAcceptable ] = SRS_CONSTS_HTTP_NotAcceptable_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_ProxyAuthenticationRequired ] = SRS_CONSTS_HTTP_ProxyAuthenticationRequired_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_RequestTimeout ] = SRS_CONSTS_HTTP_RequestTimeout_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_Conflict ] = SRS_CONSTS_HTTP_Conflict_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_Gone ] = SRS_CONSTS_HTTP_Gone_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_LengthRequired ] = SRS_CONSTS_HTTP_LengthRequired_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_PreconditionFailed ] = SRS_CONSTS_HTTP_PreconditionFailed_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_RequestEntityTooLarge ] = SRS_CONSTS_HTTP_RequestEntityTooLarge_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_RequestURITooLarge ] = SRS_CONSTS_HTTP_RequestURITooLarge_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_UnsupportedMediaType ] = SRS_CONSTS_HTTP_UnsupportedMediaType_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable ] = SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_ExpectationFailed ] = SRS_CONSTS_HTTP_ExpectationFailed_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_InternalServerError ] = SRS_CONSTS_HTTP_InternalServerError_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_NotImplemented ] = SRS_CONSTS_HTTP_NotImplemented_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_BadGateway ] = SRS_CONSTS_HTTP_BadGateway_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_ServiceUnavailable ] = SRS_CONSTS_HTTP_ServiceUnavailable_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_GatewayTimeout ] = SRS_CONSTS_HTTP_GatewayTimeout_str ;
|
||||
_status_map[SRS_CONSTS_HTTP_HTTPVersionNotSupported ] = SRS_CONSTS_HTTP_HTTPVersionNotSupported_str ;
|
||||
}
|
||||
|
||||
std::string status_text;
|
||||
if (_status_map.find(status) == _status_map.end()) {
|
||||
status_text = "Status Unknown";
|
||||
} else {
|
||||
status_text = _status_map[status];
|
||||
}
|
||||
|
||||
return status_text;
|
||||
}
|
||||
|
||||
// bodyAllowedForStatus reports whether a given response status code
|
||||
// permits a body. See RFC2616, section 4.4.
|
||||
bool srs_go_http_body_allowd(int status)
|
||||
{
|
||||
if (status >= 100 && status <= 199) {
|
||||
return false;
|
||||
} else if (status == 204 || status == 304) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// DetectContentType implements the algorithm described
|
||||
// at http://mimesniff.spec.whatwg.org/ to determine the
|
||||
// Content-Type of the given data. It considers at most the
|
||||
// first 512 bytes of data. DetectContentType always returns
|
||||
// a valid MIME type: if it cannot determine a more specific one, it
|
||||
// returns "application/octet-stream".
|
||||
string srs_go_http_detect(char* data, int size)
|
||||
{
|
||||
// detect only when data specified.
|
||||
if (data) {
|
||||
}
|
||||
return "application/octet-stream"; // fallback
|
||||
}
|
||||
|
||||
// Error replies to the request with the specified error message and HTTP code.
|
||||
// The error message should be plain text.
|
||||
int srs_go_http_error(ISrsHttpResponseWriter* w, int code, string error)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
w->header()->set_content_type("text/plain; charset=utf-8");
|
||||
w->header()->set_content_length(error.length());
|
||||
w->write_header(code);
|
||||
w->write((char*)error.data(), (int)error.length());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int srs_http_response_json(ISrsHttpResponseWriter* w, string data)
|
||||
{
|
||||
SrsHttpHeader* h = w->header();
|
||||
|
||||
h->set_content_length(data.length());
|
||||
h->set_content_type("application/json");
|
||||
|
||||
return w->write((char*)data.data(), (int)data.length());
|
||||
}
|
||||
|
||||
SrsHttpHeader::SrsHttpHeader()
|
||||
{
|
||||
}
|
||||
|
||||
SrsHttpHeader::~SrsHttpHeader()
|
||||
{
|
||||
}
|
||||
|
||||
void SrsHttpHeader::set(string key, string value)
|
||||
{
|
||||
headers[key] = value;
|
||||
}
|
||||
|
||||
string SrsHttpHeader::get(string key)
|
||||
{
|
||||
std::string v;
|
||||
|
||||
if (headers.find(key) != headers.end()) {
|
||||
v = headers[key];
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
int64_t SrsHttpHeader::content_length()
|
||||
{
|
||||
std::string cl = get("Content-Length");
|
||||
|
||||
if (cl.empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int64_t)::atof(cl.c_str());
|
||||
}
|
||||
|
||||
void SrsHttpHeader::set_content_length(int64_t size)
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "%"PRId64, size);
|
||||
set("Content-Length", buf);
|
||||
}
|
||||
|
||||
string SrsHttpHeader::content_type()
|
||||
{
|
||||
return get("Content-Type");
|
||||
}
|
||||
|
||||
void SrsHttpHeader::set_content_type(string ct)
|
||||
{
|
||||
set("Content-Type", ct);
|
||||
}
|
||||
|
||||
void SrsHttpHeader::write(stringstream& ss)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
for (it = headers.begin(); it != headers.end(); ++it) {
|
||||
ss << it->first << ": " << it->second << SRS_HTTP_CRLF;
|
||||
}
|
||||
}
|
||||
|
||||
ISrsHttpResponseWriter::ISrsHttpResponseWriter()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsHttpResponseWriter::~ISrsHttpResponseWriter()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsHttpResponseReader::ISrsHttpResponseReader()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsHttpResponseReader::~ISrsHttpResponseReader()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsHttpHandler::ISrsHttpHandler()
|
||||
{
|
||||
entry = NULL;
|
||||
}
|
||||
|
||||
ISrsHttpHandler::~ISrsHttpHandler()
|
||||
{
|
||||
}
|
||||
|
||||
SrsHttpRedirectHandler::SrsHttpRedirectHandler(string u, int c)
|
||||
{
|
||||
url = u;
|
||||
code = c;
|
||||
}
|
||||
|
||||
SrsHttpRedirectHandler::~SrsHttpRedirectHandler()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsHttpRedirectHandler::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
// TODO: FIXME: implements it.
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpNotFoundHandler::SrsHttpNotFoundHandler()
|
||||
{
|
||||
}
|
||||
|
||||
SrsHttpNotFoundHandler::~SrsHttpNotFoundHandler()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsHttpNotFoundHandler::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
return srs_go_http_error(w, SRS_CONSTS_HTTP_NotFound, SRS_CONSTS_HTTP_NotFound_str);
|
||||
}
|
||||
|
||||
SrsHttpFileServer::SrsHttpFileServer(string root_dir)
|
||||
{
|
||||
dir = root_dir;
|
||||
}
|
||||
|
||||
SrsHttpFileServer::~SrsHttpFileServer()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsHttpFileServer::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
string upath = r->path();
|
||||
|
||||
// add default pages.
|
||||
if (srs_string_ends_with(upath, "/")) {
|
||||
upath += SRS_HTTP_DEFAULT_PAGE;
|
||||
}
|
||||
|
||||
string fullpath = dir + "/";
|
||||
|
||||
// remove the virtual directory.
|
||||
srs_assert(entry);
|
||||
size_t pos = entry->pattern.find("/");
|
||||
if (upath.length() > entry->pattern.length() && pos != string::npos) {
|
||||
fullpath += upath.substr(entry->pattern.length() - pos);
|
||||
} else {
|
||||
fullpath += upath;
|
||||
}
|
||||
|
||||
// stat current dir, if exists, return error.
|
||||
if (!srs_path_exists(fullpath)) {
|
||||
srs_warn("http miss file=%s, pattern=%s, upath=%s",
|
||||
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
||||
return SrsHttpNotFoundHandler().serve_http(w, r);
|
||||
}
|
||||
srs_trace("http match file=%s, pattern=%s, upath=%s",
|
||||
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
||||
|
||||
// handle file according to its extension.
|
||||
// use vod stream for .flv/.fhv
|
||||
if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) {
|
||||
return serve_flv_file(w, r, fullpath);
|
||||
} else if (srs_string_ends_with(fullpath, ".mp4")) {
|
||||
return serve_mp4_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
// serve common static file.
|
||||
return serve_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
int SrsHttpFileServer::serve_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// open the target file.
|
||||
SrsFileReader fs;
|
||||
|
||||
if ((ret = fs.open(fullpath)) != ERROR_SUCCESS) {
|
||||
srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t length = fs.filesize();
|
||||
|
||||
// unset the content length to encode in chunked encoding.
|
||||
w->header()->set_content_length(length);
|
||||
|
||||
static std::map<std::string, std::string> _mime;
|
||||
if (_mime.empty()) {
|
||||
_mime[".ts"] = "video/MP2T";
|
||||
_mime[".flv"] = "video/x-flv";
|
||||
_mime[".m4v"] = "video/x-m4v";
|
||||
_mime[".3gpp"] = "video/3gpp";
|
||||
_mime[".3gp"] = "video/3gpp";
|
||||
_mime[".mp4"] = "video/mp4";
|
||||
_mime[".aac"] = "audio/x-aac";
|
||||
_mime[".mp3"] = "audio/mpeg";
|
||||
_mime[".m4a"] = "audio/x-m4a";
|
||||
_mime[".ogg"] = "audio/ogg";
|
||||
// @see hls-m3u8-draft-pantos-http-live-streaming-12.pdf, page 5.
|
||||
_mime[".m3u8"] = "application/vnd.apple.mpegurl"; // application/x-mpegURL
|
||||
_mime[".rss"] = "application/rss+xml";
|
||||
_mime[".json"] = "application/json";
|
||||
_mime[".swf"] = "application/x-shockwave-flash";
|
||||
_mime[".doc"] = "application/msword";
|
||||
_mime[".zip"] = "application/zip";
|
||||
_mime[".rar"] = "application/x-rar-compressed";
|
||||
_mime[".xml"] = "text/xml";
|
||||
_mime[".html"] = "text/html";
|
||||
_mime[".js"] = "text/javascript";
|
||||
_mime[".css"] = "text/css";
|
||||
_mime[".ico"] = "image/x-icon";
|
||||
_mime[".png"] = "image/png";
|
||||
_mime[".jpeg"] = "image/jpeg";
|
||||
_mime[".jpg"] = "image/jpeg";
|
||||
_mime[".gif"] = "image/gif";
|
||||
}
|
||||
|
||||
if (true) {
|
||||
size_t pos;
|
||||
std::string ext = fullpath;
|
||||
if ((pos = ext.rfind(".")) != string::npos) {
|
||||
ext = ext.substr(pos);
|
||||
}
|
||||
|
||||
if (_mime.find(ext) == _mime.end()) {
|
||||
w->header()->set_content_type("application/octet-stream");
|
||||
} else {
|
||||
w->header()->set_content_type(_mime[ext]);
|
||||
}
|
||||
}
|
||||
|
||||
// write body.
|
||||
int64_t left = length;
|
||||
if ((ret = copy(w, &fs, r, (int)left)) != ERROR_SUCCESS) {
|
||||
if (!srs_is_client_gracefully_close(ret)) {
|
||||
srs_error("read file=%s size=%d failed, ret=%d", fullpath.c_str(), left, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return w->final_request();
|
||||
}
|
||||
|
||||
int SrsHttpFileServer::serve_flv_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath)
|
||||
{
|
||||
std::string start = r->query_get("start");
|
||||
if (start.empty()) {
|
||||
return serve_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
int offset = ::atoi(start.c_str());
|
||||
if (offset <= 0) {
|
||||
return serve_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
return serve_flv_stream(w, r, fullpath, offset);
|
||||
}
|
||||
|
||||
int SrsHttpFileServer::serve_mp4_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath)
|
||||
{
|
||||
// for flash to request mp4 range in query string.
|
||||
// for example, http://digitalprimates.net/dash/DashTest.html?url=http://dashdemo.edgesuite.net/digitalprimates/nexus/oops-20120802-manifest.mpd
|
||||
std::string range = r->query_get("range");
|
||||
// or, use bytes to request range,
|
||||
// for example, http://dashas.castlabs.com/demo/try.html
|
||||
if (range.empty()) {
|
||||
range = r->query_get("bytes");
|
||||
}
|
||||
|
||||
// rollback to serve whole file.
|
||||
size_t pos = string::npos;
|
||||
if (range.empty() || (pos = range.find("-")) == string::npos) {
|
||||
return serve_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
// parse the start in query string
|
||||
int start = 0;
|
||||
if (pos > 0) {
|
||||
start = ::atoi(range.substr(0, pos).c_str());
|
||||
}
|
||||
|
||||
// parse end in query string.
|
||||
int end = -1;
|
||||
if (pos < range.length() - 1) {
|
||||
end = ::atoi(range.substr(pos + 1).c_str());
|
||||
}
|
||||
|
||||
// invalid param, serve as whole mp4 file.
|
||||
if (start < 0 || (end != -1 && start > end)) {
|
||||
return serve_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
return serve_mp4_stream(w, r, fullpath, start, end);
|
||||
}
|
||||
|
||||
int SrsHttpFileServer::serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath, int offset)
|
||||
{
|
||||
return serve_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
int SrsHttpFileServer::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, string fullpath, int start, int end)
|
||||
{
|
||||
return serve_file(w, r, fullpath);
|
||||
}
|
||||
|
||||
int SrsHttpFileServer::copy(ISrsHttpResponseWriter* w, SrsFileReader* fs, ISrsHttpMessage* r, int size)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
int left = size;
|
||||
char* buf = r->http_ts_send_buffer();
|
||||
|
||||
while (left > 0) {
|
||||
ssize_t nread = -1;
|
||||
int max_read = srs_min(left, SRS_HTTP_TS_SEND_BUFFER_SIZE);
|
||||
if ((ret = fs->read(buf, max_read, &nread)) != ERROR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
left -= nread;
|
||||
if ((ret = w->write(buf, (int)nread)) != ERROR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsHttpMuxEntry::SrsHttpMuxEntry()
|
||||
{
|
||||
enabled = true;
|
||||
explicit_match = false;
|
||||
handler = NULL;
|
||||
}
|
||||
|
||||
SrsHttpMuxEntry::~SrsHttpMuxEntry()
|
||||
{
|
||||
srs_freep(handler);
|
||||
}
|
||||
|
||||
ISrsHttpMatchHijacker::ISrsHttpMatchHijacker()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsHttpMatchHijacker::~ISrsHttpMatchHijacker()
|
||||
{
|
||||
}
|
||||
|
||||
SrsHttpServeMux::SrsHttpServeMux()
|
||||
{
|
||||
}
|
||||
|
||||
SrsHttpServeMux::~SrsHttpServeMux()
|
||||
{
|
||||
std::map<std::string, SrsHttpMuxEntry*>::iterator it;
|
||||
for (it = entries.begin(); it != entries.end(); ++it) {
|
||||
SrsHttpMuxEntry* entry = it->second;
|
||||
srs_freep(entry);
|
||||
}
|
||||
entries.clear();
|
||||
|
||||
vhosts.clear();
|
||||
hijackers.clear();
|
||||
}
|
||||
|
||||
int SrsHttpServeMux::initialize()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
// TODO: FIXME: implements it.
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsHttpServeMux::hijack(ISrsHttpMatchHijacker* h)
|
||||
{
|
||||
std::vector<ISrsHttpMatchHijacker*>::iterator it = ::find(hijackers.begin(), hijackers.end(), h);
|
||||
if (it != hijackers.end()) {
|
||||
return;
|
||||
}
|
||||
hijackers.push_back(h);
|
||||
}
|
||||
|
||||
void SrsHttpServeMux::unhijack(ISrsHttpMatchHijacker* h)
|
||||
{
|
||||
std::vector<ISrsHttpMatchHijacker*>::iterator it = ::find(hijackers.begin(), hijackers.end(), h);
|
||||
if (it == hijackers.end()) {
|
||||
return;
|
||||
}
|
||||
hijackers.erase(it);
|
||||
}
|
||||
|
||||
int SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler* handler)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_assert(handler);
|
||||
|
||||
if (pattern.empty()) {
|
||||
ret = ERROR_HTTP_PATTERN_EMPTY;
|
||||
srs_error("http: empty pattern. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (entries.find(pattern) != entries.end()) {
|
||||
SrsHttpMuxEntry* exists = entries[pattern];
|
||||
if (exists->explicit_match) {
|
||||
ret = ERROR_HTTP_PATTERN_DUPLICATED;
|
||||
srs_error("http: multiple registrations for %s. ret=%d", pattern.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
std::string vhost = pattern;
|
||||
if (pattern.at(0) != '/') {
|
||||
if (pattern.find("/") != string::npos) {
|
||||
vhost = pattern.substr(0, pattern.find("/"));
|
||||
}
|
||||
vhosts[vhost] = handler;
|
||||
}
|
||||
|
||||
if (true) {
|
||||
SrsHttpMuxEntry* entry = new SrsHttpMuxEntry();
|
||||
entry->explicit_match = true;
|
||||
entry->handler = handler;
|
||||
entry->pattern = pattern;
|
||||
entry->handler->entry = entry;
|
||||
|
||||
if (entries.find(pattern) != entries.end()) {
|
||||
SrsHttpMuxEntry* exists = entries[pattern];
|
||||
srs_freep(exists);
|
||||
}
|
||||
entries[pattern] = entry;
|
||||
}
|
||||
|
||||
// Helpful behavior:
|
||||
// If pattern is /tree/, insert an implicit permanent redirect for /tree.
|
||||
// It can be overridden by an explicit registration.
|
||||
if (pattern != "/" && !pattern.empty() && pattern.at(pattern.length() - 1) == '/') {
|
||||
std::string rpattern = pattern.substr(0, pattern.length() - 1);
|
||||
SrsHttpMuxEntry* entry = NULL;
|
||||
|
||||
// free the exists not explicit entry
|
||||
if (entries.find(rpattern) != entries.end()) {
|
||||
SrsHttpMuxEntry* exists = entries[rpattern];
|
||||
if (!exists->explicit_match) {
|
||||
entry = exists;
|
||||
}
|
||||
}
|
||||
|
||||
// create implicit redirect.
|
||||
if (!entry || entry->explicit_match) {
|
||||
srs_freep(entry);
|
||||
|
||||
entry = new SrsHttpMuxEntry();
|
||||
entry->explicit_match = false;
|
||||
entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_MovedPermanently);
|
||||
entry->pattern = pattern;
|
||||
entry->handler->entry = entry;
|
||||
|
||||
entries[rpattern] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpServeMux::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
ISrsHttpHandler* h = NULL;
|
||||
if ((ret = find_handler(r, &h)) != ERROR_SUCCESS) {
|
||||
srs_error("find handler failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_assert(h);
|
||||
if ((ret = h->serve_http(w, r)) != ERROR_SUCCESS) {
|
||||
if (!srs_is_client_gracefully_close(ret)) {
|
||||
srs_error("handler serve http failed. ret=%d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpServeMux::find_handler(ISrsHttpMessage* r, ISrsHttpHandler** ph)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// TODO: FIXME: support the path . and ..
|
||||
if (r->url().find("..") != std::string::npos) {
|
||||
ret = ERROR_HTTP_URL_NOT_CLEAN;
|
||||
srs_error("htt url not canonical, url=%s. ret=%d", r->url().c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = match(r, ph)) != ERROR_SUCCESS) {
|
||||
srs_error("http match handler failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// always hijack.
|
||||
if (!hijackers.empty()) {
|
||||
// notice all hijacker the match failed.
|
||||
std::vector<ISrsHttpMatchHijacker*>::iterator it;
|
||||
for (it = hijackers.begin(); it != hijackers.end(); ++it) {
|
||||
ISrsHttpMatchHijacker* hijacker = *it;
|
||||
if ((ret = hijacker->hijack(r, ph)) != ERROR_SUCCESS) {
|
||||
srs_error("hijacker match failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*ph == NULL) {
|
||||
// TODO: FIXME: memory leak.
|
||||
*ph = new SrsHttpNotFoundHandler();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpServeMux::match(ISrsHttpMessage* r, ISrsHttpHandler** ph)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::string path = r->path();
|
||||
|
||||
// Host-specific pattern takes precedence over generic ones
|
||||
if (!vhosts.empty() && vhosts.find(r->host()) != vhosts.end()) {
|
||||
path = r->host() + path;
|
||||
}
|
||||
|
||||
int nb_matched = 0;
|
||||
ISrsHttpHandler* h = NULL;
|
||||
|
||||
std::map<std::string, SrsHttpMuxEntry*>::iterator it;
|
||||
for (it = entries.begin(); it != entries.end(); ++it) {
|
||||
std::string pattern = it->first;
|
||||
SrsHttpMuxEntry* entry = it->second;
|
||||
|
||||
if (!entry->enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!path_match(pattern, path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!h || (int)pattern.length() > nb_matched) {
|
||||
nb_matched = (int)pattern.length();
|
||||
h = entry->handler;
|
||||
}
|
||||
}
|
||||
|
||||
*ph = h;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool SrsHttpServeMux::path_match(string pattern, string path)
|
||||
{
|
||||
if (pattern.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int n = (int)pattern.length();
|
||||
|
||||
// not endswith '/', exactly match.
|
||||
if (pattern.at(n - 1) != '/') {
|
||||
return pattern == path;
|
||||
}
|
||||
|
||||
// endswith '/', match any,
|
||||
// for example, '/api/' match '/api/[N]'
|
||||
if ((int)path.length() >= n) {
|
||||
if (memcmp(pattern.data(), path.data(), n) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ISrsHttpMessage::ISrsHttpMessage()
|
||||
{
|
||||
_http_ts_send_buffer = new char[SRS_HTTP_TS_SEND_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
ISrsHttpMessage::~ISrsHttpMessage()
|
||||
{
|
||||
srs_freep(_http_ts_send_buffer);
|
||||
}
|
||||
|
||||
char* ISrsHttpMessage::http_ts_send_buffer()
|
||||
{
|
||||
return _http_ts_send_buffer;
|
||||
}
|
494
trunk/src/protocol/srs_http_stack.hpp
Normal file
494
trunk/src/protocol/srs_http_stack.hpp
Normal file
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 SRS(simple-rtmp-server)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SRS_PROTOCOL_HTTP_HPP
|
||||
#define SRS_PROTOCOL_HTTP_HPP
|
||||
|
||||
/*
|
||||
#include <srs_http_stack.hpp>
|
||||
*/
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class SrsFileReader;
|
||||
class SrsHttpHeader;
|
||||
class ISrsHttpMessage;
|
||||
class SrsHttpMuxEntry;
|
||||
class ISrsHttpResponseWriter;
|
||||
|
||||
// http specification
|
||||
// CR = <US-ASCII CR, carriage return (13)>
|
||||
#define SRS_HTTP_CR SRS_CONSTS_CR // 0x0D
|
||||
// LF = <US-ASCII LF, linefeed (10)>
|
||||
#define SRS_HTTP_LF SRS_CONSTS_LF // 0x0A
|
||||
// SP = <US-ASCII SP, space (32)>
|
||||
#define SRS_HTTP_SP ' ' // 0x20
|
||||
// HT = <US-ASCII HT, horizontal-tab (9)>
|
||||
#define SRS_HTTP_HT '\x09' // 0x09
|
||||
|
||||
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
|
||||
// protocol elements except the entity-body (see appendix 19.3 for
|
||||
// tolerant applications).
|
||||
#define SRS_HTTP_CRLF "\r\n" // 0x0D0A
|
||||
#define SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
|
||||
|
||||
// @see ISrsHttpMessage._http_ts_send_buffer
|
||||
#define SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
|
||||
|
||||
// for ead all of http body, read each time.
|
||||
#define SRS_HTTP_READ_CACHE_BYTES 4096
|
||||
|
||||
// default http listen port.
|
||||
#define SRS_DEFAULT_HTTP_PORT 80
|
||||
|
||||
// for http parser macros
|
||||
#define SRS_CONSTS_HTTP_OPTIONS HTTP_OPTIONS
|
||||
#define SRS_CONSTS_HTTP_GET HTTP_GET
|
||||
#define SRS_CONSTS_HTTP_POST HTTP_POST
|
||||
#define SRS_CONSTS_HTTP_PUT HTTP_PUT
|
||||
#define SRS_CONSTS_HTTP_DELETE HTTP_DELETE
|
||||
|
||||
// helper function: response in json format.
|
||||
extern int srs_http_response_json(ISrsHttpResponseWriter* w, std::string data);
|
||||
|
||||
// get the status text of code.
|
||||
extern std::string srs_generate_http_status_text(int status);
|
||||
|
||||
// bodyAllowedForStatus reports whether a given response status code
|
||||
// permits a body. See RFC2616, section 4.4.
|
||||
extern bool srs_go_http_body_allowd(int status);
|
||||
|
||||
// DetectContentType implements the algorithm described
|
||||
// at http://mimesniff.spec.whatwg.org/ to determine the
|
||||
// Content-Type of the given data. It considers at most the
|
||||
// first 512 bytes of data. DetectContentType always returns
|
||||
// a valid MIME type: if it cannot determine a more specific one, it
|
||||
// returns "application/octet-stream".
|
||||
extern std::string srs_go_http_detect(char* data, int size);
|
||||
|
||||
// state of message
|
||||
enum SrsHttpParseState {
|
||||
SrsHttpParseStateInit = 0,
|
||||
SrsHttpParseStateStart,
|
||||
SrsHttpParseStateHeaderComplete,
|
||||
SrsHttpParseStateMessageComplete
|
||||
};
|
||||
|
||||
// A Header represents the key-value pairs in an HTTP header.
|
||||
class SrsHttpHeader
|
||||
{
|
||||
private:
|
||||
std::map<std::string, std::string> headers;
|
||||
public:
|
||||
SrsHttpHeader();
|
||||
virtual ~SrsHttpHeader();
|
||||
public:
|
||||
// Add adds the key, value pair to the header.
|
||||
// It appends to any existing values associated with key.
|
||||
virtual void set(std::string key, std::string value);
|
||||
// Get gets the first value associated with the given key.
|
||||
// If there are no values associated with the key, Get returns "".
|
||||
// To access multiple values of a key, access the map directly
|
||||
// with CanonicalHeaderKey.
|
||||
virtual std::string get(std::string key);
|
||||
public:
|
||||
/**
|
||||
* get the content length. -1 if not set.
|
||||
*/
|
||||
virtual int64_t content_length();
|
||||
/**
|
||||
* set the content length by header "Content-Length"
|
||||
*/
|
||||
virtual void set_content_length(int64_t size);
|
||||
public:
|
||||
/**
|
||||
* get the content type. empty string if not set.
|
||||
*/
|
||||
virtual std::string content_type();
|
||||
/**
|
||||
* set the content type by header "Content-Type"
|
||||
*/
|
||||
virtual void set_content_type(std::string ct);
|
||||
public:
|
||||
/**
|
||||
* write all headers to string stream.
|
||||
*/
|
||||
virtual void write(std::stringstream& ss);
|
||||
};
|
||||
|
||||
// A ResponseWriter interface is used by an HTTP handler to
|
||||
// construct an HTTP response.
|
||||
// Usage 1, response with specified length content:
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// std::string msg = "Hello, HTTP!";
|
||||
// w->header()->set_content_type("text/plain; charset=utf-8");
|
||||
// w->header()->set_content_length(msg.length());
|
||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->final_request(); // optional flush.
|
||||
// Usage 2, response with HTTP code only, zero content length.
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// w->header()->set_content_length(0);
|
||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
// w->final_request();
|
||||
// Usage 3, response in chunked encoding.
|
||||
// ISrsHttpResponseWriter* w; // create or get response.
|
||||
// std::string msg = "Hello, HTTP!";
|
||||
// w->header()->set_content_type("application/octet-stream");
|
||||
// w->write_header(SRS_CONSTS_HTTP_OK);
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->write((char*)msg.data(), (int)msg.length());
|
||||
// w->final_request(); // required to end the chunked and flush.
|
||||
class ISrsHttpResponseWriter
|
||||
{
|
||||
public:
|
||||
ISrsHttpResponseWriter();
|
||||
virtual ~ISrsHttpResponseWriter();
|
||||
public:
|
||||
// when chunked mode,
|
||||
// final the request to complete the chunked encoding.
|
||||
// for no-chunked mode,
|
||||
// final to send request, for example, content-length is 0.
|
||||
virtual int final_request() = 0;
|
||||
|
||||
// Header returns the header map that will be sent by WriteHeader.
|
||||
// Changing the header after a call to WriteHeader (or Write) has
|
||||
// no effect.
|
||||
virtual SrsHttpHeader* header() = 0;
|
||||
|
||||
// Write writes the data to the connection as part of an HTTP reply.
|
||||
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
|
||||
// before writing the data. If the Header does not contain a
|
||||
// Content-Type line, Write adds a Content-Type set to the result of passing
|
||||
// the initial 512 bytes of written data to DetectContentType.
|
||||
// @param data, the data to send. NULL to flush header only.
|
||||
virtual int write(char* data, int size) = 0;
|
||||
|
||||
// WriteHeader sends an HTTP response header with status code.
|
||||
// If WriteHeader is not called explicitly, the first call to Write
|
||||
// will trigger an implicit WriteHeader(http.StatusOK).
|
||||
// Thus explicit calls to WriteHeader are mainly used to
|
||||
// send error codes.
|
||||
// @remark, user must set header then write or write_header.
|
||||
virtual void write_header(int code) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* the reader interface for http response.
|
||||
*/
|
||||
class ISrsHttpResponseReader
|
||||
{
|
||||
public:
|
||||
ISrsHttpResponseReader();
|
||||
virtual ~ISrsHttpResponseReader();
|
||||
public:
|
||||
/**
|
||||
* whether response read EOF.
|
||||
*/
|
||||
virtual bool eof() = 0;
|
||||
/**
|
||||
* read from the response body.
|
||||
* @param data, the buffer to read data buffer to.
|
||||
* @param nb_data, the max size of data buffer.
|
||||
* @param nb_read, the actual read size of bytes. NULL to ignore.
|
||||
* @remark when eof(), return error.
|
||||
*/
|
||||
virtual int read(char* data, int nb_data, int* nb_read) = 0;
|
||||
};
|
||||
|
||||
// Objects implementing the Handler interface can be
|
||||
// registered to serve a particular path or subtree
|
||||
// in the HTTP server.
|
||||
//
|
||||
// ServeHTTP should write reply headers and data to the ResponseWriter
|
||||
// and then return. Returning signals that the request is finished
|
||||
// and that the HTTP server can move on to the next request on
|
||||
// the connection.
|
||||
class ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsHttpMuxEntry* entry;
|
||||
public:
|
||||
ISrsHttpHandler();
|
||||
virtual ~ISrsHttpHandler();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) = 0;
|
||||
};
|
||||
|
||||
// Redirect to a fixed URL
|
||||
class SrsHttpRedirectHandler : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
std::string url;
|
||||
int code;
|
||||
public:
|
||||
SrsHttpRedirectHandler(std::string u, int c);
|
||||
virtual ~SrsHttpRedirectHandler();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
// NotFound replies to the request with an HTTP 404 not found error.
|
||||
class SrsHttpNotFoundHandler : public ISrsHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsHttpNotFoundHandler();
|
||||
virtual ~SrsHttpNotFoundHandler();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
// FileServer returns a handler that serves HTTP requests
|
||||
// with the contents of the file system rooted at root.
|
||||
//
|
||||
// To use the operating system's file system implementation,
|
||||
// use http.Dir:
|
||||
//
|
||||
// http.Handle("/", SrsHttpFileServer("/tmp"))
|
||||
// http.Handle("/", SrsHttpFileServer("static-dir"))
|
||||
class SrsHttpFileServer : public ISrsHttpHandler
|
||||
{
|
||||
protected:
|
||||
std::string dir;
|
||||
public:
|
||||
SrsHttpFileServer(std::string root_dir);
|
||||
virtual ~SrsHttpFileServer();
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
private:
|
||||
/**
|
||||
* serve the file by specified path
|
||||
*/
|
||||
virtual int serve_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath);
|
||||
virtual int serve_flv_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath);
|
||||
virtual int serve_mp4_file(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath);
|
||||
protected:
|
||||
/**
|
||||
* when access flv file with x.flv?start=xxx
|
||||
*/
|
||||
virtual int serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath, int offset);
|
||||
/**
|
||||
* when access mp4 file with x.mp4?range=start-end
|
||||
* @param start the start offset in bytes.
|
||||
* @param end the end offset in bytes. -1 to end of file.
|
||||
* @remark response data in [start, end].
|
||||
*/
|
||||
virtual int serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, std::string fullpath, int start, int end);
|
||||
protected:
|
||||
/**
|
||||
* copy the fs to response writer in size bytes.
|
||||
*/
|
||||
virtual int copy(ISrsHttpResponseWriter* w, SrsFileReader* fs, ISrsHttpMessage* r, int size);
|
||||
};
|
||||
|
||||
// the mux entry for server mux.
|
||||
// the matcher info, for example, the pattern and handler.
|
||||
class SrsHttpMuxEntry
|
||||
{
|
||||
public:
|
||||
bool explicit_match;
|
||||
ISrsHttpHandler* handler;
|
||||
std::string pattern;
|
||||
bool enabled;
|
||||
public:
|
||||
SrsHttpMuxEntry();
|
||||
virtual ~SrsHttpMuxEntry();
|
||||
};
|
||||
|
||||
/**
|
||||
* the hijacker for http pattern match.
|
||||
*/
|
||||
class ISrsHttpMatchHijacker
|
||||
{
|
||||
public:
|
||||
ISrsHttpMatchHijacker();
|
||||
virtual ~ISrsHttpMatchHijacker();
|
||||
public:
|
||||
/**
|
||||
* when match the request failed, no handler to process request.
|
||||
* @param request the http request message to match the handler.
|
||||
* @param ph the already matched handler, hijack can rewrite it.
|
||||
*/
|
||||
virtual int hijack(ISrsHttpMessage* request, ISrsHttpHandler** ph) = 0;
|
||||
};
|
||||
|
||||
// ServeMux is an HTTP request multiplexer.
|
||||
// It matches the URL of each incoming request against a list of registered
|
||||
// patterns and calls the handler for the pattern that
|
||||
// most closely matches the URL.
|
||||
//
|
||||
// Patterns name fixed, rooted paths, like "/favicon.ico",
|
||||
// or rooted subtrees, like "/images/" (note the trailing slash).
|
||||
// Longer patterns take precedence over shorter ones, so that
|
||||
// if there are handlers registered for both "/images/"
|
||||
// and "/images/thumbnails/", the latter handler will be
|
||||
// called for paths beginning "/images/thumbnails/" and the
|
||||
// former will receive requests for any other paths in the
|
||||
// "/images/" subtree.
|
||||
//
|
||||
// Note that since a pattern ending in a slash names a rooted subtree,
|
||||
// the pattern "/" matches all paths not matched by other registered
|
||||
// patterns, not just the URL with Path == "/".
|
||||
//
|
||||
// Patterns may optionally begin with a host name, restricting matches to
|
||||
// URLs on that host only. Host-specific patterns take precedence over
|
||||
// general patterns, so that a handler might register for the two patterns
|
||||
// "/codesearch" and "codesearch.google.com/" without also taking over
|
||||
// requests for "http://www.google.com/".
|
||||
//
|
||||
// ServeMux also takes care of sanitizing the URL request path,
|
||||
// redirecting any request containing . or .. elements to an
|
||||
// equivalent .- and ..-free URL.
|
||||
class SrsHttpServeMux
|
||||
{
|
||||
private:
|
||||
// the pattern handler, to handle the http request.
|
||||
std::map<std::string, SrsHttpMuxEntry*> entries;
|
||||
// the vhost handler.
|
||||
// when find the handler to process the request,
|
||||
// append the matched vhost when pattern not starts with /,
|
||||
// for example, for pattern /live/livestream.flv of vhost ossrs.net,
|
||||
// the path will rewrite to ossrs.net/live/livestream.flv
|
||||
std::map<std::string, ISrsHttpHandler*> vhosts;
|
||||
// all hijackers for http match.
|
||||
// for example, the hstrs(http stream trigger rtmp source)
|
||||
// can hijack and install handler when request incoming and no handler.
|
||||
std::vector<ISrsHttpMatchHijacker*> hijackers;
|
||||
public:
|
||||
SrsHttpServeMux();
|
||||
virtual ~SrsHttpServeMux();
|
||||
public:
|
||||
/**
|
||||
* initialize the http serve mux.
|
||||
*/
|
||||
virtual int initialize();
|
||||
/**
|
||||
* hijack the http match.
|
||||
*/
|
||||
virtual void hijack(ISrsHttpMatchHijacker* h);
|
||||
virtual void unhijack(ISrsHttpMatchHijacker* h);
|
||||
public:
|
||||
// Handle registers the handler for the given pattern.
|
||||
// If a handler already exists for pattern, Handle panics.
|
||||
virtual int handle(std::string pattern, ISrsHttpHandler* handler);
|
||||
// interface ISrsHttpHandler
|
||||
public:
|
||||
virtual int serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
private:
|
||||
virtual int find_handler(ISrsHttpMessage* r, ISrsHttpHandler** ph);
|
||||
virtual int match(ISrsHttpMessage* r, ISrsHttpHandler** ph);
|
||||
virtual bool path_match(std::string pattern, std::string path);
|
||||
};
|
||||
|
||||
// for http header.
|
||||
typedef std::pair<std::string, std::string> SrsHttpHeaderField;
|
||||
|
||||
// A Request represents an HTTP request received by a server
|
||||
// or to be sent by a client.
|
||||
//
|
||||
// The field semantics differ slightly between client and server
|
||||
// usage. In addition to the notes on the fields below, see the
|
||||
// documentation for Request.Write and RoundTripper.
|
||||
/**
|
||||
* the http message, request or response.
|
||||
*/
|
||||
class ISrsHttpMessage
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* use a buffer to read and send ts file.
|
||||
*/
|
||||
// TODO: FIXME: remove it.
|
||||
char* _http_ts_send_buffer;
|
||||
public:
|
||||
ISrsHttpMessage();
|
||||
virtual ~ISrsHttpMessage();
|
||||
public:
|
||||
/**
|
||||
* the http request level cache.
|
||||
*/
|
||||
virtual char* http_ts_send_buffer();
|
||||
public:
|
||||
virtual u_int8_t method() = 0;
|
||||
virtual u_int16_t status_code() = 0;
|
||||
/**
|
||||
* method helpers.
|
||||
*/
|
||||
virtual std::string method_str() = 0;
|
||||
virtual bool is_http_get() = 0;
|
||||
virtual bool is_http_put() = 0;
|
||||
virtual bool is_http_post() = 0;
|
||||
virtual bool is_http_delete() = 0;
|
||||
virtual bool is_http_options() = 0;
|
||||
public:
|
||||
/**
|
||||
* whether should keep the connection alive.
|
||||
*/
|
||||
virtual bool is_keep_alive() = 0;
|
||||
/**
|
||||
* the uri contains the host and path.
|
||||
*/
|
||||
virtual std::string uri() = 0;
|
||||
/**
|
||||
* the url maybe the path.
|
||||
*/
|
||||
virtual std::string url() = 0;
|
||||
virtual std::string host() = 0;
|
||||
virtual std::string path() = 0;
|
||||
virtual std::string ext() = 0;
|
||||
public:
|
||||
/**
|
||||
* read body to string.
|
||||
* @remark for small http body.
|
||||
*/
|
||||
virtual int body_read_all(std::string& body) = 0;
|
||||
/**
|
||||
* get the body reader, to read one by one.
|
||||
* @remark when body is very large, or chunked, use this.
|
||||
*/
|
||||
virtual ISrsHttpResponseReader* body_reader() = 0;
|
||||
/**
|
||||
* the content length, -1 for chunked or not set.
|
||||
*/
|
||||
virtual int64_t content_length() = 0;
|
||||
public:
|
||||
/**
|
||||
* get the param in query string,
|
||||
* for instance, query is "start=100&end=200",
|
||||
* then query_get("start") is "100", and query_get("end") is "200"
|
||||
*/
|
||||
virtual std::string query_get(std::string key) = 0;
|
||||
/**
|
||||
* get the headers.
|
||||
*/
|
||||
virtual int request_header_count() = 0;
|
||||
virtual std::string request_header_key_at(int index) = 0;
|
||||
virtual std::string request_header_value_at(int index) = 0;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue