diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index 0bccae544..f5052f76a 100755 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -131,6 +131,19 @@ vhost dev { } } } +# the http hook callback vhost, srs will invoke the hooks for specified events. +vhost hooks.callback.vhost.com { + # when client connect to vhost/app, call the hook, + # the request in the POST data string is a object encode by json: + # { + # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", + # "pageUrl": "http://www.test.com/live.html" + # } + # if valid, the hook must return HTTP code 200(Stauts OK) and response + # an int value specifies the error code(0 corresponding to success): + # 0 + on_connect http://127.0.0.1:8085/api/v1/clients; +} # the mirror filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction vhost mirror.transcode.vhost.com { transcode { diff --git a/trunk/src/core/srs_core_client.cpp b/trunk/src/core/srs_core_client.cpp index 86d7523ea..0faf861e6 100644 --- a/trunk/src/core/srs_core_client.cpp +++ b/trunk/src/core/srs_core_client.cpp @@ -37,6 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include #define SRS_PULSE_TIMEOUT_MS 100 #define SRS_SEND_TIMEOUT_US 5000000L @@ -51,6 +52,9 @@ SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd) res = new SrsResponse(); rtmp = new SrsRtmp(client_stfd); refer = new SrsRefer(); +#ifdef SRS_HTTP + http_hooks = new SrsHttpHooks(); +#endif } SrsClient::~SrsClient() @@ -60,6 +64,9 @@ SrsClient::~SrsClient() srs_freep(res); srs_freep(rtmp); srs_freep(refer); +#ifdef SRS_HTTP + srs_freep(http_hooks); +#endif } // TODO: return detail message when error for client. @@ -249,6 +256,11 @@ int SrsClient::check_vhost() srs_info("ignore the empty http callback: on_connect"); return ret; } + + if ((ret = http_hooks->on_connect(on_connect, ip, req)) != ERROR_SUCCESS) { + srs_error("hook client failed. ret=%d", ret); + return ret; + } #endif return ret; diff --git a/trunk/src/core/srs_core_client.hpp b/trunk/src/core/srs_core_client.hpp index ae2d19849..d951fbd88 100644 --- a/trunk/src/core/srs_core_client.hpp +++ b/trunk/src/core/srs_core_client.hpp @@ -39,6 +39,9 @@ class SrsSource; class SrsRefer; class SrsConsumer; class SrsCommonMessage; +#ifdef SRS_HTTP +class SrsHttpHooks; +#endif /** * the client provides the main logic control for RTMP clients. @@ -51,6 +54,9 @@ private: SrsResponse* res; SrsRtmp* rtmp; SrsRefer* refer; +#ifdef SRS_HTTP + SrsHttpHooks* http_hooks; +#endif public: SrsClient(SrsServer* srs_server, st_netfd_t client_stfd); virtual ~SrsClient(); diff --git a/trunk/src/core/srs_core_error.hpp b/trunk/src/core/srs_core_error.hpp index 291801208..411816f39 100644 --- a/trunk/src/core/srs_core_error.hpp +++ b/trunk/src/core/srs_core_error.hpp @@ -142,4 +142,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ERROR_ENCODER_OPEN 715 #define ERROR_ENCODER_DUP2 716 +#define ERROR_HTTP_PARSE_URI 800 +#define ERROR_HTTP_DATA_INVLIAD 801 + #endif \ No newline at end of file diff --git a/trunk/src/core/srs_core_http.cpp b/trunk/src/core/srs_core_http.cpp index e3a1b3320..2963dad3d 100644 --- a/trunk/src/core/srs_core_http.cpp +++ b/trunk/src/core/srs_core_http.cpp @@ -23,5 +23,179 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include +#include + +#include +#include +#include + #ifdef SRS_HTTP + +#define SRS_DEFAULT_HTTP_PORT 80 +#define SRS_HTTP_RESPONSE_OK "0" + +SrsHttpUri::SrsHttpUri() +{ + port = SRS_DEFAULT_HTTP_PORT; +} + +SrsHttpUri::~SrsHttpUri() +{ +} + +int SrsHttpUri::initialize(std::string _url) +{ + int ret = ERROR_SUCCESS; + + url = _url; + const char* purl = url.c_str(); + + http_parser_url hp_u; + if((ret = http_parser_parse_url(purl, url.length(), 0, &hp_u)) != 0){ + int code = ret; + ret = ERROR_HTTP_PARSE_URI; + + srs_error("parse url %s failed, code=%d, ret=%d", purl, code, ret); + return ret; + } + + std::string field = get_uri_field(url, &hp_u, UF_SCHEMA); + if(!field.empty()){ + schema = field; + } + + host = get_uri_field(url, &hp_u, UF_HOST); + + field = get_uri_field(url, &hp_u, UF_PORT); + if(!field.empty()){ + port = atoi(field.c_str()); + } + + path = get_uri_field(url, &hp_u, UF_PATH); + srs_info("parse url %s success", purl); + + return ret; +} + +const char* SrsHttpUri::get_url() +{ + return url.c_str(); +} + +const char* SrsHttpUri::get_schema() +{ + return schema.c_str(); +} + +const char* SrsHttpUri::get_host() +{ + return host.c_str(); +} + +int SrsHttpUri::get_port() +{ + return port; +} + +std::string SrsHttpUri::get_uri_field(std::string uri, http_parser_url* hp_u, http_parser_url_fields field) +{ + if((hp_u->field_set & (1 << field)) == 0){ + return ""; + } + + srs_verbose("uri field matched, off=%d, len=%d, value=%.*s", + hp_u->field_data[field].off, + hp_u->field_data[field].len, + hp_u->field_data[field].len, + uri.c_str() + hp_u->field_data[field].off); + + int offset = hp_u->field_data[field].off; + int len = hp_u->field_data[field].len; + + return uri.substr(offset, len); +} + +SrsHttpClient::SrsHttpClient() +{ +} + +SrsHttpClient::~SrsHttpClient() +{ +} + +int SrsHttpClient::post(SrsHttpUri* uri, std::string req, std::string& res) +{ + int ret = ERROR_SUCCESS; + return ret; +} + +SrsHttpHooks::SrsHttpHooks() +{ +} + +SrsHttpHooks::~SrsHttpHooks() +{ +} + +int SrsHttpHooks::on_connect(std::string url, std::string ip, SrsRequest* req) +{ + int ret = ERROR_SUCCESS; + + SrsHttpUri uri; + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) { + srs_error("http uri parse url failed. " + "url=%s, ret=%d", url.c_str(), ret); + return ret; + } + + std::string res; + std::string data; + /** + { + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", + "pageUrl": "http://www.test.com/live.html" + } + */ + data += "{"; + // ip + data += "\"ip\":"; + data += "\"" + ip + "\""; + data += ","; + // vhost + data += "\"vhost\":"; + data += "\"" + req->vhost + "\""; + data += ","; + data += ","; + // app + data += "\"vhost\":"; + data += "\"" + req->app + "\""; + data += ","; + // pageUrl + data += "\"vhost\":"; + data += "\"" + req->pageUrl + "\""; + //data += ","; + data += "}"; + + SrsHttpClient http; + if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) { + srs_error("http post uri failed. " + "url=%s, request=%s, response=%s, ret=%d", + url.c_str(), data.c_str(), res.c_str(), ret); + return ret; + } + + if (res.empty() || res != SRS_HTTP_RESPONSE_OK) { + ret = ERROR_HTTP_DATA_INVLIAD; + srs_error("http hook validate failed. " + "res=%s, ret=%d", res.c_str(), ret); + return ret; + } + + srs_trace("http hook on_connect success. " + "url=%s, request=%s, response=%s, ret=%d", + url.c_str(), data.c_str(), res.c_str(), ret); + + return ret; +} + #endif diff --git a/trunk/src/core/srs_core_http.hpp b/trunk/src/core/srs_core_http.hpp index c8f7be3d8..e9cf2e66e 100644 --- a/trunk/src/core/srs_core_http.hpp +++ b/trunk/src/core/srs_core_http.hpp @@ -29,7 +29,83 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +class SrsRequest; + +#include + #ifdef SRS_HTTP + +#include + +/** +* used to resolve the http uri. +*/ +class SrsHttpUri +{ +private: + std::string url; + std::string schema; + std::string host; + int port; + std::string path; +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(); +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); +}; + +/** +* http client to GET/POST/PUT/DELETE uri +*/ +class SrsHttpClient +{ +public: + SrsHttpClient(); + virtual ~SrsHttpClient(); +public: + /** + * to post data to the uri. + * @param req the data post to uri. + * @param res the response data from server. + */ + virtual int post(SrsHttpUri* uri, std::string req, std::string& res); +}; + +/** +* the http hooks, http callback api, +* for some event, such as on_connect, call +* a http api(hooks). +*/ +class SrsHttpHooks +{ +public: + SrsHttpHooks(); + virtual ~SrsHttpHooks(); +public: + /** + * on_connect hook, + * @param url the api server url, to valid the client. + * ignore if empty. + * @return valid failed or connect to the url failed. + */ + virtual int on_connect(std::string url, std::string ip, SrsRequest* req); +}; + #endif #endif \ No newline at end of file