mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
create http handler framework
This commit is contained in:
parent
eae9b94153
commit
341b5151d9
10 changed files with 244 additions and 9 deletions
|
@ -285,7 +285,7 @@ fi
|
||||||
#####################################################################################
|
#####################################################################################
|
||||||
function write_nginx_html5()
|
function write_nginx_html5()
|
||||||
{
|
{
|
||||||
cat<<END >> ${html_file}
|
cat<<END > ${html_file}
|
||||||
<video width="640" height="360"
|
<video width="640" height="360"
|
||||||
autoplay controls autobuffer
|
autoplay controls autobuffer
|
||||||
src="${hls_stream}"
|
src="${hls_stream}"
|
||||||
|
@ -398,7 +398,7 @@ if [ $__SRS_BUILD_NGINX = YES ]; then
|
||||||
ln -sf `pwd`/research/players/nginx_index.html ${SRS_OBJS}/nginx/html/index.html
|
ln -sf `pwd`/research/players/nginx_index.html ${SRS_OBJS}/nginx/html/index.html
|
||||||
else
|
else
|
||||||
rm -f ${SRS_OBJS}/nginx/html/index.html &&
|
rm -f ${SRS_OBJS}/nginx/html/index.html &&
|
||||||
cat<<END >> ${SRS_OBJS}/nginx/html/index.html
|
cat<<END > ${SRS_OBJS}/nginx/html/index.html
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
|
|
@ -32,11 +32,101 @@ using namespace std;
|
||||||
#include <srs_kernel_error.hpp>
|
#include <srs_kernel_error.hpp>
|
||||||
#include <srs_kernel_log.hpp>
|
#include <srs_kernel_log.hpp>
|
||||||
#include <srs_app_socket.hpp>
|
#include <srs_app_socket.hpp>
|
||||||
|
#include <srs_app_http_api.hpp>
|
||||||
|
#include <srs_app_http_conn.hpp>
|
||||||
|
|
||||||
#define SRS_DEFAULT_HTTP_PORT 80
|
#define SRS_DEFAULT_HTTP_PORT 80
|
||||||
|
|
||||||
#define SRS_HTTP_HEADER_BUFFER 1024
|
#define SRS_HTTP_HEADER_BUFFER 1024
|
||||||
|
|
||||||
|
SrsHttpHandler::SrsHttpHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpHandler::~SrsHttpHandler()
|
||||||
|
{
|
||||||
|
std::vector<SrsHttpHandler*>::iterator it;
|
||||||
|
for (it = handlers.begin(); it != handlers.end(); ++it) {
|
||||||
|
SrsHttpHandler* handler = *it;
|
||||||
|
srs_freep(handler);
|
||||||
|
}
|
||||||
|
handlers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpHandler::initialize()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SrsHttpHandler::can_handle(const char* /*path*/, int /*length*/)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpHandler::process_request(SrsSocket* /*skt*/, SrsHttpMessage* /*req*/, const char* /*path*/, int /*length*/)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHttpHandler::best_match(const char* path, int length, SrsHttpHandler** phandler, const char** pstart, int* plength)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// ensure cur is not NULL.
|
||||||
|
// ensure p not NULL and has bytes to parse.
|
||||||
|
if (!path || length <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* p = NULL;
|
||||||
|
for (p = path + 1; p - path < length && *p != __PATH_SEP; p++) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// whether the handler can handler the node.
|
||||||
|
int node_size = p - path;
|
||||||
|
if (!can_handle(path, node_size)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*phandler = this;
|
||||||
|
*pstart = path;
|
||||||
|
*plength = node_size;
|
||||||
|
|
||||||
|
std::vector<SrsHttpHandler*>::iterator it;
|
||||||
|
for (it = handlers.begin(); it != handlers.end(); ++it) {
|
||||||
|
SrsHttpHandler* handler = *it;
|
||||||
|
// matched, donot search.
|
||||||
|
if (handler->best_match(p, length - node_size, phandler, pstart, plength) == ERROR_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// whatever, donot loop.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*phandler == NULL) {
|
||||||
|
ret = ERROR_HTTP_HANDLER_MATCH_URL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpHandler* SrsHttpHandler::create_http_api()
|
||||||
|
{
|
||||||
|
return new SrsApiRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpHandler* SrsHttpHandler::create_http_stream()
|
||||||
|
{
|
||||||
|
// TODO: FIXME: use http stream handler instead.
|
||||||
|
return new SrsHttpHandler();
|
||||||
|
}
|
||||||
|
|
||||||
SrsHttpMessage::SrsHttpMessage()
|
SrsHttpMessage::SrsHttpMessage()
|
||||||
{
|
{
|
||||||
_body = new SrsBuffer();
|
_body = new SrsBuffer();
|
||||||
|
|
|
@ -32,6 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#ifdef SRS_HTTP_PARSER
|
#ifdef SRS_HTTP_PARSER
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <http_parser.h>
|
#include <http_parser.h>
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
class SrsBuffer;
|
class SrsBuffer;
|
||||||
class SrsRequest;
|
class SrsRequest;
|
||||||
class SrsSocket;
|
class SrsSocket;
|
||||||
|
class SrsHttpMessage;
|
||||||
|
|
||||||
// http specification
|
// http specification
|
||||||
// CR = <US-ASCII CR, carriage return (13)>
|
// CR = <US-ASCII CR, carriage return (13)>
|
||||||
|
@ -57,12 +59,58 @@ class SrsSocket;
|
||||||
#define __CRLF "\r\n" // 0x0D0A
|
#define __CRLF "\r\n" // 0x0D0A
|
||||||
#define __CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
|
#define __CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
|
||||||
|
|
||||||
|
// linux path seprator
|
||||||
|
#define __PATH_SEP '/'
|
||||||
|
|
||||||
|
// state of message
|
||||||
enum SrsHttpParseState {
|
enum SrsHttpParseState {
|
||||||
SrsHttpParseStateInit = 0,
|
SrsHttpParseStateInit = 0,
|
||||||
SrsHttpParseStateStart,
|
SrsHttpParseStateStart,
|
||||||
SrsHttpParseStateComplete
|
SrsHttpParseStateComplete
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource handler for HTTP RESTful api.
|
||||||
|
*/
|
||||||
|
class SrsHttpHandler
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* we use handler chain to process request.
|
||||||
|
*/
|
||||||
|
std::vector<SrsHttpHandler*> handlers;
|
||||||
|
public:
|
||||||
|
SrsHttpHandler();
|
||||||
|
virtual ~SrsHttpHandler();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* initialize the handler.
|
||||||
|
*/
|
||||||
|
virtual int initialize();
|
||||||
|
/**
|
||||||
|
* whether current handler can handle the specified path.
|
||||||
|
*/
|
||||||
|
virtual bool can_handle(const char* path, int length);
|
||||||
|
/**
|
||||||
|
* use the handler to process the request.
|
||||||
|
*/
|
||||||
|
virtual int process_request(SrsSocket* skt, SrsHttpMessage* req, const char* path, int length);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* find the best matched handler
|
||||||
|
*/
|
||||||
|
virtual int best_match(const char* path, int length, SrsHttpHandler** phandler, const char** pstart, int* plength);
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* create http api resource handler.
|
||||||
|
*/
|
||||||
|
static SrsHttpHandler* create_http_api();
|
||||||
|
/**
|
||||||
|
* create http stream resource handler.
|
||||||
|
*/
|
||||||
|
static SrsHttpHandler* create_http_stream();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the http message, request or response.
|
* the http message, request or response.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -34,10 +34,30 @@ using namespace std;
|
||||||
#include <srs_app_socket.hpp>
|
#include <srs_app_socket.hpp>
|
||||||
#include <srs_core_autofree.hpp>
|
#include <srs_core_autofree.hpp>
|
||||||
|
|
||||||
SrsHttpApi::SrsHttpApi(SrsServer* srs_server, st_netfd_t client_stfd)
|
SrsApiRoot::SrsApiRoot()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsApiRoot::~SrsApiRoot()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SrsApiRoot::can_handle(const char* /*path*/, int /*length*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsApiRoot::process_request(SrsSocket* /*skt*/, SrsHttpMessage* /*req*/, const char* /*path*/, int /*length*/)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHttpApi::SrsHttpApi(SrsServer* srs_server, st_netfd_t client_stfd, SrsHttpHandler* _handler)
|
||||||
: SrsConnection(srs_server, client_stfd)
|
: SrsConnection(srs_server, client_stfd)
|
||||||
{
|
{
|
||||||
parser = new SrsHttpParser();
|
parser = new SrsHttpParser();
|
||||||
|
handler = _handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpApi::~SrsHttpApi()
|
SrsHttpApi::~SrsHttpApi()
|
||||||
|
@ -93,6 +113,28 @@ int SrsHttpApi::process_request(SrsSocket* skt, SrsHttpMessage* req)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
// TODO: maybe need to parse the url.
|
||||||
|
std::string uri = req->url();
|
||||||
|
|
||||||
|
int length = 0;
|
||||||
|
const char* start = NULL;
|
||||||
|
SrsHttpHandler* p = NULL;
|
||||||
|
if ((ret = handler->best_match(uri.data(), uri.length(), &p, &start, &length)) != ERROR_SUCCESS) {
|
||||||
|
srs_warn("failed to find the best match handler for url. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if success, p and pstart should be valid.
|
||||||
|
srs_assert(p);
|
||||||
|
srs_assert(start);
|
||||||
|
srs_assert(length <= (int)uri.length());
|
||||||
|
|
||||||
|
// use handler to process request.
|
||||||
|
if ((ret = p->process_request(skt, req, start, length)) != ERROR_SUCCESS) {
|
||||||
|
srs_warn("handler failed to process http request. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (req->method() == HTTP_OPTIONS) {
|
if (req->method() == HTTP_OPTIONS) {
|
||||||
char data[] = "HTTP/1.1 200 OK" __CRLF
|
char data[] = "HTTP/1.1 200 OK" __CRLF
|
||||||
"Content-Length: 0"__CRLF
|
"Content-Length: 0"__CRLF
|
||||||
|
|
|
@ -35,16 +35,30 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
class SrsSocket;
|
class SrsSocket;
|
||||||
class SrsHttpMessage;
|
class SrsHttpMessage;
|
||||||
class SrsHttpParser;
|
class SrsHttpParser;
|
||||||
|
class SrsHttpHandler;
|
||||||
|
|
||||||
#include <srs_app_st.hpp>
|
#include <srs_app_st.hpp>
|
||||||
#include <srs_app_conn.hpp>
|
#include <srs_app_conn.hpp>
|
||||||
|
#include <srs_app_http.hpp>
|
||||||
|
|
||||||
|
// for http root.
|
||||||
|
class SrsApiRoot : public SrsHttpHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SrsApiRoot();
|
||||||
|
virtual ~SrsApiRoot();
|
||||||
|
public:
|
||||||
|
virtual bool can_handle(const char* path, int length);
|
||||||
|
virtual int process_request(SrsSocket* skt, SrsHttpMessage* req, const char* path, int length);
|
||||||
|
};
|
||||||
|
|
||||||
class SrsHttpApi : public SrsConnection
|
class SrsHttpApi : public SrsConnection
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsHttpParser* parser;
|
SrsHttpParser* parser;
|
||||||
|
SrsHttpHandler* handler;
|
||||||
public:
|
public:
|
||||||
SrsHttpApi(SrsServer* srs_server, st_netfd_t client_stfd);
|
SrsHttpApi(SrsServer* srs_server, st_netfd_t client_stfd, SrsHttpHandler* _handler);
|
||||||
virtual ~SrsHttpApi();
|
virtual ~SrsHttpApi();
|
||||||
protected:
|
protected:
|
||||||
virtual int do_cycle();
|
virtual int do_cycle();
|
||||||
|
|
|
@ -37,10 +37,11 @@ using namespace std;
|
||||||
|
|
||||||
#define SRS_HTTP_HEADER_BUFFER 1024
|
#define SRS_HTTP_HEADER_BUFFER 1024
|
||||||
|
|
||||||
SrsHttpConn::SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd)
|
SrsHttpConn::SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd, SrsHttpHandler* _handler)
|
||||||
: SrsConnection(srs_server, client_stfd)
|
: SrsConnection(srs_server, client_stfd)
|
||||||
{
|
{
|
||||||
parser = new SrsHttpParser();
|
parser = new SrsHttpParser();
|
||||||
|
handler = _handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpConn::~SrsHttpConn()
|
SrsHttpConn::~SrsHttpConn()
|
||||||
|
|
|
@ -40,13 +40,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
class SrsSocket;
|
class SrsSocket;
|
||||||
class SrsHttpParser;
|
class SrsHttpParser;
|
||||||
class SrsHttpMessage;
|
class SrsHttpMessage;
|
||||||
|
class SrsHttpHandler;
|
||||||
|
|
||||||
class SrsHttpConn : public SrsConnection
|
class SrsHttpConn : public SrsConnection
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsHttpParser* parser;
|
SrsHttpParser* parser;
|
||||||
|
SrsHttpHandler* handler;
|
||||||
public:
|
public:
|
||||||
SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd);
|
SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd, SrsHttpHandler* _handler);
|
||||||
virtual ~SrsHttpConn();
|
virtual ~SrsHttpConn();
|
||||||
protected:
|
protected:
|
||||||
virtual int do_cycle();
|
virtual int do_cycle();
|
||||||
|
|
|
@ -40,6 +40,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#include <srs_kernel_utility.hpp>
|
#include <srs_kernel_utility.hpp>
|
||||||
#include <srs_app_http_api.hpp>
|
#include <srs_app_http_api.hpp>
|
||||||
#include <srs_app_http_conn.hpp>
|
#include <srs_app_http_conn.hpp>
|
||||||
|
#include <srs_app_http.hpp>
|
||||||
|
|
||||||
#define SERVER_LISTEN_BACKLOG 512
|
#define SERVER_LISTEN_BACKLOG 512
|
||||||
#define SRS_TIME_RESOLUTION_MS 500
|
#define SRS_TIME_RESOLUTION_MS 500
|
||||||
|
@ -160,6 +161,13 @@ SrsServer::SrsServer()
|
||||||
|
|
||||||
srs_assert(_srs_config);
|
srs_assert(_srs_config);
|
||||||
_srs_config->subscribe(this);
|
_srs_config->subscribe(this);
|
||||||
|
|
||||||
|
#ifdef SRS_HTTP_API
|
||||||
|
http_api_handler = SrsHttpHandler::create_http_api();
|
||||||
|
#endif
|
||||||
|
#ifdef SRS_HTTP_SERVER
|
||||||
|
http_stream_handler = SrsHttpHandler::create_http_stream();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsServer::~SrsServer()
|
SrsServer::~SrsServer()
|
||||||
|
@ -176,11 +184,32 @@ SrsServer::~SrsServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
close_listeners();
|
close_listeners();
|
||||||
|
|
||||||
|
#ifdef SRS_HTTP_API
|
||||||
|
srs_freep(http_api_handler);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SRS_HTTP_SERVER
|
||||||
|
srs_freep(http_stream_handler);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsServer::initialize()
|
int SrsServer::initialize()
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
#ifdef SRS_HTTP_API
|
||||||
|
if ((ret = http_api_handler->initialize()) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SRS_HTTP_SERVER
|
||||||
|
if ((ret = http_stream_handler->initialize()) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,7 +472,7 @@ int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd)
|
||||||
conn = new SrsRtmpConn(this, client_stfd);
|
conn = new SrsRtmpConn(this, client_stfd);
|
||||||
} else if (type == SrsListenerHttpApi) {
|
} else if (type == SrsListenerHttpApi) {
|
||||||
#ifdef SRS_HTTP_API
|
#ifdef SRS_HTTP_API
|
||||||
conn = new SrsHttpApi(this, client_stfd);
|
conn = new SrsHttpApi(this, client_stfd, http_api_handler);
|
||||||
#else
|
#else
|
||||||
srs_warn("close http client for server not support http-api");
|
srs_warn("close http client for server not support http-api");
|
||||||
srs_close_stfd(client_stfd);
|
srs_close_stfd(client_stfd);
|
||||||
|
@ -451,7 +480,7 @@ int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd)
|
||||||
#endif
|
#endif
|
||||||
} else if (type == SrsListenerHttpStream) {
|
} else if (type == SrsListenerHttpStream) {
|
||||||
#ifdef SRS_HTTP_SERVER
|
#ifdef SRS_HTTP_SERVER
|
||||||
conn = new SrsHttpConn(this, client_stfd);
|
conn = new SrsHttpConn(this, client_stfd, http_stream_handler);
|
||||||
#else
|
#else
|
||||||
srs_warn("close http client for server not support http-server");
|
srs_warn("close http client for server not support http-server");
|
||||||
srs_close_stfd(client_stfd);
|
srs_close_stfd(client_stfd);
|
||||||
|
|
|
@ -38,6 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
class SrsServer;
|
class SrsServer;
|
||||||
class SrsConnection;
|
class SrsConnection;
|
||||||
|
class SrsHttpHandler;
|
||||||
|
|
||||||
// listener type for server to identify the connection,
|
// listener type for server to identify the connection,
|
||||||
// that is, use different type to process the connection.
|
// that is, use different type to process the connection.
|
||||||
|
@ -75,6 +76,13 @@ public:
|
||||||
class SrsServer : public ISrsReloadHandler
|
class SrsServer : public ISrsReloadHandler
|
||||||
{
|
{
|
||||||
friend class SrsListener;
|
friend class SrsListener;
|
||||||
|
private:
|
||||||
|
#ifdef SRS_HTTP_API
|
||||||
|
SrsHttpHandler* http_api_handler;
|
||||||
|
#endif
|
||||||
|
#ifdef SRS_HTTP_SERVER
|
||||||
|
SrsHttpHandler* http_stream_handler;
|
||||||
|
#endif
|
||||||
private:
|
private:
|
||||||
std::vector<SrsConnection*> conns;
|
std::vector<SrsConnection*> conns;
|
||||||
std::vector<SrsListener*> listeners;
|
std::vector<SrsListener*> listeners;
|
||||||
|
|
|
@ -157,6 +157,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#define ERROR_HTTP_PARSE_URI 800
|
#define ERROR_HTTP_PARSE_URI 800
|
||||||
#define ERROR_HTTP_DATA_INVLIAD 801
|
#define ERROR_HTTP_DATA_INVLIAD 801
|
||||||
#define ERROR_HTTP_PARSE_HEADER 802
|
#define ERROR_HTTP_PARSE_HEADER 802
|
||||||
|
#define ERROR_HTTP_HANDLER_MATCH_URL 803
|
||||||
|
|
||||||
// system control message,
|
// system control message,
|
||||||
// not an error, but special control logic.
|
// not an error, but special control logic.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue