diff --git a/api/include/events_objects.h b/api/include/events_objects.h index 5c464caf..e24a1603 100644 --- a/api/include/events_objects.h +++ b/api/include/events_objects.h @@ -136,6 +136,10 @@ API_EXPORT const char* API_CALL mk_tcp_session_local_ip(const mk_tcp_session ctx API_EXPORT uint16_t API_CALL mk_tcp_session_peer_port(const mk_tcp_session ctx); //TcpSession::get_local_port() API_EXPORT uint16_t API_CALL mk_tcp_session_local_port(const mk_tcp_session ctx); +//TcpSession::send() +API_EXPORT void API_CALL mk_tcp_session_send(const mk_tcp_session ctx,const char *data,int len); +//切换到该对象所在线程后再TcpSession::send() +API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx,const char *data,int len); ///////////////////////////////////////////HttpBody///////////////////////////////////////////// //HttpBody对象的C映射 diff --git a/api/include/mediakit.h b/api/include/mediakit.h index 2be7bd67..de08c278 100755 --- a/api/include/mediakit.h +++ b/api/include/mediakit.h @@ -35,5 +35,6 @@ #include "player.h" #include "pusher.h" #include "events.h" +#include "websocket.h" #endif /* MK_API_H_ */ diff --git a/api/include/websocket.h b/api/include/websocket.h new file mode 100644 index 00000000..a5d6fdcd --- /dev/null +++ b/api/include/websocket.h @@ -0,0 +1,105 @@ +/* + * MIT License + * + * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * 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 MK_WEBSOCKET_H +#define MK_WEBSOCKET_H + +#include "common.h" +#include "events_objects.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + /** + * 当websocket客户端连接服务器时触发 + * @param session 会话处理对象 + */ + void (API_CALL *on_mk_websocket_session_create)(mk_tcp_session session); + + /** + * session会话对象销毁时触发 + * 请在本回调中清理释放你的用户数据 + * 本事件中不能调用mk_tcp_session_send/mk_tcp_session_send_safe函数 + * @param session 会话处理对象 + */ + void (API_CALL *on_mk_websocket_session_destory)(mk_tcp_session session); + + /** + * 收到websocket客户端发过来的数据 + * @param session 会话处理对象 + * @param data 数据指针 + * @param len 数据长度 + */ + void (API_CALL *on_mk_websocket_session_data)(mk_tcp_session session,const char *data,int len); + + /** + * 每隔2秒的定时器,用于管理超时等任务 + * @param session 会话处理对象 + */ + void (API_CALL *on_mk_websocket_session_manager)(mk_tcp_session session); + + /** + * on_mk_websocket_session_destory之前触发on_mk_websocket_session_err + * 一般由于客户端断开tcp触发 + * 本事件中可以调用mk_tcp_session_send_safe函数 + * @param session 会话处理对象 + * @param code 错误代码 + * @param msg 错误提示 + */ + void (API_CALL *on_mk_websocket_session_err)(mk_tcp_session session,int code,const char *msg); +} mk_websocket_events; + +API_EXPORT void API_CALL mk_websocket_events_listen(const mk_websocket_events *events); + +/** + * 往websocket会话对象附着用户数据 + * @param session websocket会话对象 + * @param user_data 用户数据指针 + */ +API_EXPORT void API_CALL mk_websocket_session_set_user_data(mk_tcp_session session,void *user_data); + +/** + * 获取websocket会话对象上附着的用户数据 + * @param session websocket会话对象 + * @return 用户数据指针 + */ +API_EXPORT void* API_CALL mk_websocket_session_get_user_data(mk_tcp_session session,void *user_data); + +/** + * 开启websocket服务器,需要指出的是,websocket服务器包含了Http服务器的所有功能 + * 调用mk_websocket_server_start后不用再调用mk_http_server_start + * @param port 端口号,0则随机 + * @param ssl 是否为wss/ws + * @return 端口号,0代表失败 + */ +API_EXPORT uint16_t API_CALL mk_websocket_server_start(uint16_t port, int ssl); + +#ifdef __cplusplus +} +#endif +#endif //MK_WEBSOCKET_H diff --git a/api/source/events_objects.cpp b/api/source/events_objects.cpp index 4108d57e..41a8a982 100644 --- a/api/source/events_objects.cpp +++ b/api/source/events_objects.cpp @@ -254,6 +254,33 @@ API_EXPORT uint16_t API_CALL mk_tcp_session_local_port(const mk_tcp_session ctx) TcpSession *session = (TcpSession *)ctx; return session->get_local_port(); } +API_EXPORT void API_CALL mk_tcp_session_send(const mk_tcp_session ctx,const char *data,int len){ + assert(ctx && data); + if(!len){ + len = strlen(data); + } + TcpSession *session = (TcpSession *)ctx; + session->send(data,len); +} + +API_EXPORT void API_CALL mk_tcp_session_send_safe(const mk_tcp_session ctx,const char *data,int len){ + assert(ctx && data); + if(!len){ + len = strlen(data); + } + try { + weak_ptr weak_session = ((TcpSession *)ctx)->shared_from_this(); + string str = string(data,len); + ((TcpSession *)ctx)->async([weak_session,str](){ + auto session_session = weak_session.lock(); + if(session_session){ + session_session->send(str); + } + }); + }catch (std::exception &ex){ + WarnL << "can not got the strong pionter of this mk_tcp_session:" << ex.what(); + } +} ///////////////////////////////////////////HttpBody///////////////////////////////////////////// API_EXPORT mk_http_body API_CALL mk_http_body_from_string(const char *str,int len){ diff --git a/api/source/websocket.cpp b/api/source/websocket.cpp new file mode 100644 index 00000000..304963e1 --- /dev/null +++ b/api/source/websocket.cpp @@ -0,0 +1,105 @@ +/* + * MIT License + * + * Copyright (c) 2019 xiongziliang <771730766@qq.com> + * + * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit). + * + * 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 "websocket.h" +#include "Http/HttpSession.h" +#include "Http/WebSocketSession.h" +using namespace mediakit; + +static TcpServer::Ptr websocket_server[2]; +static mk_websocket_events s_events = {0}; + +class WebSocketSessionImp : public TcpSession { +public: + WebSocketSessionImp(const Socket::Ptr &pSock) : TcpSession(pSock){ + if(s_events.on_mk_websocket_session_create){ + s_events.on_mk_websocket_session_create(this); + } + } + + virtual ~WebSocketSessionImp(){ + if(s_events.on_mk_websocket_session_destory){ + s_events.on_mk_websocket_session_destory(this); + } + } + + void onRecv(const Buffer::Ptr &buffer) override { + if(s_events.on_mk_websocket_session_data){ + s_events.on_mk_websocket_session_data(this,buffer->data(),buffer->size()); + } + } + + void onError(const SockException &err) override{ + if(s_events.on_mk_websocket_session_err){ + s_events.on_mk_websocket_session_err(this,err.getErrCode(),err.what()); + } + } + + void onManager() override{ + if(s_events.on_mk_websocket_session_manager){ + s_events.on_mk_websocket_session_manager(this); + } + } + + void *_user_data; +}; + +API_EXPORT void API_CALL mk_websocket_events_listen(const mk_websocket_events *events){ + if(events){ + memcpy(&s_events,events, sizeof(s_events)); + }else{ + memset(&s_events,0,sizeof(s_events)); + } +} + +API_EXPORT void API_CALL mk_websocket_session_set_user_data(mk_tcp_session session,void *user_data){ + assert(session); + WebSocketSessionImp *obj = (WebSocketSessionImp *)session; + obj->_user_data = user_data; +} + +API_EXPORT void* API_CALL mk_websocket_session_get_user_data(mk_tcp_session session,void *user_data){ + assert(session); + WebSocketSessionImp *obj = (WebSocketSessionImp *)session; + return obj->_user_data; +} + +API_EXPORT uint16_t API_CALL mk_websocket_server_start(uint16_t port, int ssl){ + ssl = MAX(0,MIN(ssl,1)); + try { + websocket_server[ssl] = std::make_shared(); + if(ssl){ + websocket_server[ssl]->start>(port); + }else{ + websocket_server[ssl]->start>(port); + } + return websocket_server[ssl]->getPort(); + } catch (std::exception &ex) { + websocket_server[ssl].reset(); + WarnL << ex.what(); + return 0; + } +} \ No newline at end of file