diff --git a/src/Common/config.cpp b/src/Common/config.cpp index 73b2d405..b3cf7b07 100644 --- a/src/Common/config.cpp +++ b/src/Common/config.cpp @@ -24,6 +24,7 @@ * SOFTWARE. */ +#include #include "Common/config.h" #include "Util/util.h" #include "Util/onceToken.h" @@ -33,12 +34,20 @@ using namespace ZL::Network; namespace Config { -void loadIniConfig(){ - auto &ini = ZL::Util::mINI::Instance(); +bool loadIniConfig(const char *ini_path){ + string ini; + if(ini_path){ + ini = ini_path; + }else{ + ini = exePath() + ".ini"; + } try{ - ini.parseFile(exePath() + ".ini"); + mINI::Instance().parseFile(ini); + NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastUpdateConfig); + return true; }catch (std::exception &ex) { - ini.dumpFile(exePath() + ".ini"); + mINI::Instance().dumpFile(ini); + return false; } } ////////////广播名称/////////// @@ -51,7 +60,11 @@ const char kBroadcastOnRtspAuth[] = "kBroadcastOnRtspAuth"; const char kBroadcastMediaPlayed[] = "kBroadcastMediaPlayed"; const char kBroadcastRtmpPublish[] = "kBroadcastRtmpPublish"; const char kBroadcastFlowReport[] = "kBroadcastFlowReport"; -const char kFlowThreshold[] = "Broadcast.flowThreshold"; +const char kBroadcastUpdateConfig[] = "kBroadcastUpdateConfig"; +const char kBroadcastShellLogin[] = "kBroadcastShellLogin"; + +const char kFlowThreshold[] = "broadcast.flowThreshold"; + onceToken token([](){ mINI::Instance()[kFlowThreshold] = 1024; },nullptr); diff --git a/src/Common/config.h b/src/Common/config.h index 7c0738ac..0a40d3e6 100644 --- a/src/Common/config.h +++ b/src/Common/config.h @@ -29,13 +29,19 @@ #define COMMON_CONFIG_H #include "Util/mini.h" +#include "Util/onceToken.h" #include using namespace std; using namespace ZL::Util; namespace Config { -void loadIniConfig(); +//加载配置文件,如果配置文件不存在,那么会导出默认配置并生成配置文件 +//加载配置文件成功后会触发kBroadcastUpdateConfig广播 +//如果指定的文件名(ini_path)为空,那么会加载默认配置文件 +//默认配置文件名为 /path/to/your/exe.ini +//加载配置文件成功后返回true,否则返回false +bool loadIniConfig(const char *ini_path = nullptr); ////////////TCP最大连接数/////////// #define MAX_TCP_SESSION 100000 ////////////其他宏定义/////////// @@ -96,12 +102,22 @@ extern const char kBroadcastRtmpPublish[]; extern const char kBroadcastMediaPlayed[]; #define BroadcastMediaPlayedArgs const MediaInfo &args,const Broadcast::AuthInvoker &invoker +//shell登录鉴权 +extern const char kBroadcastShellLogin[]; +#define BroadcastShellLoginArgs const string &user_name,const string &passwd,const Broadcast::AuthInvoker &invoker + //停止rtsp/rtmp/http-flv会话后流量汇报事件广播 extern const char kBroadcastFlowReport[]; #define BroadcastFlowReportArgs const MediaInfo &args,const uint64_t &totalBytes //流量汇报事件流量阈值,单位KB,默认1MB extern const char kFlowThreshold[]; + +//更新配置文件事件广播,执行loadIniConfig函数加载配置文件成功后会触发该广播 +extern const char kBroadcastUpdateConfig[]; +#define BroadcastUpdateConfigArgs void +#define ReloadConfigTag ((void *)(0xFF)) + } //namespace Broadcast ////////////HTTP配置/////////// diff --git a/src/Device/PlayerProxy.cpp b/src/Device/PlayerProxy.cpp index 2ef3cc47..074fe814 100644 --- a/src/Device/PlayerProxy.cpp +++ b/src/Device/PlayerProxy.cpp @@ -131,6 +131,7 @@ void PlayerProxy::initMedia() { return; } m_pChn.reset(new DevChannel(m_strVhost.data(),m_strApp.data(),m_strSrc.data(),getDuration(),m_bEnableHls,m_bEnableMp4)); + m_pChn->setListener(shared_from_this()); if (containVideo()) { VideoInfo info; info.iFrameRate = getVideoFps(); @@ -146,6 +147,18 @@ void PlayerProxy::initMedia() { m_pChn->initAudio(info); } } +bool PlayerProxy::shutDown() { + //通知其停止推流 + weak_ptr weakSlef = dynamic_pointer_cast(shared_from_this()); + ASYNC_TRACE([weakSlef](){ + auto stronSelf = weakSlef.lock(); + if(stronSelf){ + stronSelf->m_pChn.reset(); + stronSelf->teardown(); + } + }); + return true; +} } /* namespace Player */ diff --git a/src/Device/PlayerProxy.h b/src/Device/PlayerProxy.h index 7a84e580..ac698f79 100644 --- a/src/Device/PlayerProxy.h +++ b/src/Device/PlayerProxy.h @@ -38,7 +38,7 @@ using namespace ZL::Player; namespace ZL { namespace DEV { -class PlayerProxy :public MediaPlayer, public std::enable_shared_from_this{ +class PlayerProxy :public MediaPlayer, public std::enable_shared_from_this , public MediaSourceEvent { public: typedef std::shared_ptr Ptr; @@ -54,7 +54,7 @@ public: virtual ~PlayerProxy(); void play(const char* strUrl) override; - + bool shutDown() override; private: bool m_bEnableHls; bool m_bEnableMp4; diff --git a/src/Shell/ShellCMD.cpp b/src/Shell/ShellCMD.cpp index aae1a4bc..5980e71f 100644 --- a/src/Shell/ShellCMD.cpp +++ b/src/Shell/ShellCMD.cpp @@ -3,56 +3,94 @@ // #include "Util/CMD.h" -#include "Rtsp/RtspMediaSource.h" -#include "Rtmp/RtmpMediaSource.h" +#include "Common/MediaSource.h" using namespace ZL::Util; -using namespace ZL::Rtsp; -using namespace ZL::Rtmp; +using namespace ZL::Media; namespace ZL { namespace Shell { -class CMD_rtsp: public CMD { + +class CMD_media: public CMD { public: - CMD_rtsp(){ - _parser.reset(new OptionParser(nullptr)); - (*_parser) << Option('l', "list", Option::ArgNone, nullptr,false, "list all media source of rtsp", - [](const std::shared_ptr &stream, const string &arg) { -// auto mediaSet = RtspMediaSource::getMediaSet(); -// for (auto &src : mediaSet) { -// (*stream) << "\t" << src << "\r\n"; -// } - return false; - }); + CMD_media(){ + _parser.reset(new OptionParser([](const std::shared_ptr &stream,mINI &ini){ + MediaSource::for_each_media([&](const string &schema, + const string &vhost, + const string &app, + const string &streamid, + const MediaSource::Ptr &media){ + if(!ini["schema"].empty() && ini["schema"] != schema){ + //筛选协议不匹配 + return; + } + if(!ini["vhost"].empty() && ini["vhost"] != vhost){ + //筛选虚拟主机不匹配 + return; + } + if(!ini["app"].empty() && ini["app"] != app){ + //筛选应用名不匹配 + return; + } + if(!ini["stream"].empty() && ini["stream"] != streamid){ + //流id不匹配 + return; + } + if(ini.find("list") != ini.end()){ + //列出源 + (*stream) << "\t" + << schema << "/" + << vhost << "/" + << app << "/" + << streamid + << "\r\n"; + return; + } + + if(ini.find("kick") != ini.end()){ + //踢出源 + do{ + if(!media) { + break; + } + if(!media->shutDown()) { + break; + } + (*stream) << "\t踢出成功:" + << schema << "/" + << vhost << "/" + << app << "/" + << streamid + << "\r\n"; + return; + }while(0); + (*stream) << "\t踢出失败:" + << schema << "/" + << vhost << "/" + << app << "/" + << streamid + << "\r\n"; + return; + } + + }); + })); + (*_parser) << Option('k', "kick", Option::ArgNone,nullptr,false, "踢出媒体源", nullptr); + (*_parser) << Option('l', "list", Option::ArgNone,nullptr,false, "列出媒体源", nullptr); + (*_parser) << Option('S', "schema", Option::ArgRequired,nullptr,false, "协议筛选", nullptr); + (*_parser) << Option('v', "vhost", Option::ArgRequired,nullptr,false, "虚拟主机筛选", nullptr); + (*_parser) << Option('a', "app", Option::ArgRequired,nullptr,false, "应用名筛选", nullptr); + (*_parser) << Option('s', "stream", Option::ArgRequired,nullptr,false, "流id筛选", nullptr); } - virtual ~CMD_rtsp() {} + virtual ~CMD_media() {} const char *description() const override { - return "查看rtsp服务器相关信息."; - } -}; -class CMD_rtmp: public CMD { -public: - CMD_rtmp(){ - _parser.reset(new OptionParser(nullptr)); - (*_parser) << Option('l', "list", Option::ArgNone,nullptr,false, "list all media source of rtmp", - [](const std::shared_ptr &stream, const string &arg) { -// auto mediaSet = RtmpMediaSource::getMediaSet(); -// for (auto &src : mediaSet) { -// (*stream) << "\t" << src << "\r\n"; -// } - return false; - }); - } - virtual ~CMD_rtmp() {} - const char *description() const override { - return "查看rtmp服务器相关信息."; + return "媒体源相关操作."; } }; static onceToken s_token([]() { - REGIST_CMD(rtmp); - REGIST_CMD(rtsp); + REGIST_CMD(media); }, nullptr); diff --git a/src/Shell/ShellSession.cpp b/src/Shell/ShellSession.cpp index a3fe4cd4..adcb60cf 100644 --- a/src/Shell/ShellSession.cpp +++ b/src/Shell/ShellSession.cpp @@ -28,14 +28,14 @@ #include "Common/config.h" #include "Util/CMD.h" #include "Util/onceToken.h" +#include "Util/NoticeCenter.h" +using namespace Config; using namespace ZL::Util; namespace ZL { namespace Shell { -unordered_map ShellSession::g_mapUser; - ShellSession::ShellSession(const std::shared_ptr &_th, const Socket::Ptr &_sock) : TcpLimitedSession(_th, _sock) { @@ -82,8 +82,9 @@ void ShellSession::onManager() { } inline bool ShellSession::onCommandLine(const string& line) { - if (m_requestCB) { - bool ret = m_requestCB(line); + auto loginInterceptor = m_loginInterceptor; + if (loginInterceptor) { + bool ret = loginInterceptor(line); return ret; } try { @@ -103,30 +104,55 @@ inline bool ShellSession::onCommandLine(const string& line) { inline void ShellSession::pleaseInputUser() { send("\033[0m"); send(StrPrinter << SERVER_NAME << " login: " << endl); - m_requestCB = [this](const string &line) { - m_strUserName=line; + m_loginInterceptor = [this](const string &user_name) { + m_strUserName=user_name; pleaseInputPasswd(); return true; }; } inline void ShellSession::pleaseInputPasswd() { send("Password: \033[8m"); - m_requestCB = [this](const string &passwd) { - if(!onAuth(m_strUserName, passwd)) { - send(StrPrinter - <<"\033[0mPermission denied," - <<" please try again.\r\n" - < weakSelf = dynamic_pointer_cast(shared_from_this()); + Broadcast::AuthInvoker invoker = [weakSelf,onAuth](const string &errMessage){ + auto strongSelf = weakSelf.lock(); + if(!strongSelf){ + return; + } + strongSelf->async([errMessage,weakSelf,onAuth](){ + auto strongSelf = weakSelf.lock(); + if(!strongSelf){ + return; + } + onAuth(errMessage); + }); + }; + + auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastShellLogin,m_strUserName,passwd,invoker); + if(!flag){ + //如果无人监听shell登录事件,那么默认shell无法登录 + onAuth("please listen kBroadcastShellLogin event"); + } return true; }; } @@ -135,14 +161,5 @@ inline void ShellSession::printShellPrefix() { send(StrPrinter << m_strUserName << "@" << SERVER_NAME << "# " << endl); } -inline bool ShellSession::onAuth(const string &user, const string &pwd) { - auto it = g_mapUser.find(user); - if (it == g_mapUser.end()) { - //WarnL << user << " " << pwd; - return false; - } - return it->second == pwd; -} - }/* namespace Shell */ } /* namespace ZL */ diff --git a/src/Shell/ShellSession.h b/src/Shell/ShellSession.h index f9382bdd..75247a1c 100644 --- a/src/Shell/ShellSession.h +++ b/src/Shell/ShellSession.h @@ -48,22 +48,16 @@ public: void onError(const SockException &err) override {}; void onManager() override; - static void addUser(const string &userName,const string &userPwd){ - g_mapUser[userName] = userPwd; - } private: inline bool onCommandLine(const string &); - inline bool onAuth(const string &user, const string &pwd); inline void pleaseInputUser(); inline void pleaseInputPasswd(); inline void printShellPrefix(); - function m_requestCB; + function m_loginInterceptor; string m_strRecvBuf; Ticker m_beatTicker; string m_strUserName; - - static unordered_map g_mapUser; }; } /* namespace Shell */ diff --git a/tests/test_server.cpp b/tests/test_server.cpp index fb7aea50..2805e555 100644 --- a/tests/test_server.cpp +++ b/tests/test_server.cpp @@ -112,16 +112,24 @@ static onceToken s_token([](){ NoticeCenter::Instance().addListener(nullptr,Config::Broadcast::kBroadcastRtmpPublish,[](BroadcastRtmpPublishArgs){ InfoL << args.m_vhost << " " << args.m_app << " " << args.m_streamid << " " << args.m_param_strs ; EventPoller::Instance().async([invoker](){ - //invoker("");//鉴权成功 - invoker("this is auth failed message");//鉴权失败 + invoker("");//鉴权成功 + //invoker("this is auth failed message");//鉴权失败 }); }); NoticeCenter::Instance().addListener(nullptr,Config::Broadcast::kBroadcastMediaPlayed,[](BroadcastMediaPlayedArgs){ InfoL << args.m_schema << " " << args.m_vhost << " " << args.m_app << " " << args.m_streamid << " " << args.m_param_strs ; EventPoller::Instance().async([invoker](){ - //invoker("");//鉴权成功 - invoker("this is auth failed message");//鉴权失败 + invoker("");//鉴权成功 + //invoker("this is auth failed message");//鉴权失败 + }); + }); + + NoticeCenter::Instance().addListener(nullptr,Config::Broadcast::kBroadcastShellLogin,[](BroadcastShellLoginArgs){ + InfoL << "shell login:" << user_name << " " << passwd; + EventPoller::Instance().async([invoker](){ + invoker("");//鉴权成功 + //invoker("this is auth failed message");//鉴权失败 }); }); @@ -130,7 +138,9 @@ static onceToken s_token([](){ int main(int argc,char *argv[]){ //设置退出信号处理函数 signal(SIGINT, [](int){EventPoller::Instance().shutdown();}); - //设置日志 + signal(SIGHUP, [](int){Config::loadIniConfig();}); + + //设置日志 Logger::Instance().add(std::make_shared("stdout", LTrace)); Logger::Instance().setWriter(std::make_shared()); //加载配置文件,如果配置文件不存在就创建一个 @@ -176,10 +186,8 @@ int main(int argc,char *argv[]){ #endif //ENABLE_OPENSSL //简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象 - //测试方法:telnet 127.0.0.1 8023 - //输入用户名和密码登录(user:test,pwd:123456),输入help命令查看帮助 + //测试方法:telnet 127.0.0.1 9000 TcpServer::Ptr shellSrv(new TcpServer()); - ShellSession::addUser("test", "123456"); shellSrv->start(mINI::Instance()[Config::Shell::kPort]); //开启rtsp/rtmp/http服务器 TcpServer::Ptr rtspSrv(new TcpServer());