diff --git a/apps/sbc/Makefile b/apps/sbc/Makefile index 90f33a52..09611c7d 100644 --- a/apps/sbc/Makefile +++ b/apps/sbc/Makefile @@ -2,6 +2,10 @@ plug_in_name = sbc module_ldflags = module_cflags = -DMOD_NAME=\"$(plug_in_name)\" +extra_install = install_tools COREPATH ?= ../../core include $(COREPATH)/plug-in/Makefile.app_module + +install_tools: + -@$(MAKE) -C tools/ install \ No newline at end of file diff --git a/apps/sbc/SBC.cpp b/apps/sbc/SBC.cpp index 7450d98b..38b65551 100644 --- a/apps/sbc/SBC.cpp +++ b/apps/sbc/SBC.cpp @@ -58,19 +58,42 @@ string SBCFactory::pwd; AmConfigReader SBCFactory::cfg; AmSessionEventHandlerFactory* SBCFactory::session_timer_fact = NULL; -EXPORT_SESSION_FACTORY(SBCFactory,MOD_NAME); +extern "C" void* plugin_class_create() +{ + return SBCFactory::instance(); +} + +extern "C" void* session_factory_create() +{ + return plugin_class_create(); +} + +SBCFactory* SBCFactory::_instance=0; +bool SBCFactory::loaded=false; +SBCFactory* SBCFactory::instance() +{ + if(_instance == NULL) + _instance = new SBCFactory(MOD_NAME); + return _instance; +} SBCFactory::SBCFactory(const string& _app_name) -: AmSessionFactory(_app_name) + : AmSessionFactory(_app_name), AmDynInvokeFactory(_app_name) { } +SBCFactory::~SBCFactory() { +} int SBCFactory::onLoad() { + if (loaded) + return 0; + loaded = true; + if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf"))) { ERROR("No configuration for sbc present (%s)\n", (AmConfig::ModConfigPath + string(MOD_NAME ".conf")).c_str() @@ -109,6 +132,8 @@ int SBCFactory::onLoad() AmSession* SBCFactory::onInvite(const AmSipRequest& req) { + profiles_mut.lock(); + string profile = active_profile; if (profile == "$(paramhdr)") { string app_param = getHeader(req.hdrs, PARAM_HDR, true); @@ -120,6 +145,7 @@ AmSession* SBCFactory::onInvite(const AmSipRequest& req) map::iterator it= call_profiles.find(profile); if (it==call_profiles.end()) { + profiles_mut.unlock(); ERROR("could not find call profile '%s' (active_profile = %s)\n", profile.c_str(), active_profile.c_str()); throw AmSession::Exception(500,"Server Internal Error"); @@ -132,8 +158,10 @@ AmSession* SBCFactory::onInvite(const AmSipRequest& req) if (call_profile.sst_enabled) { DBG("Enabling SIP Session Timers\n"); - if (!session_timer_fact->onInvite(req, sst_cfg)) + if (!session_timer_fact->onInvite(req, sst_cfg)) { + profiles_mut.unlock(); return NULL; + } } SBCDialog* b2b_dlg = new SBCDialog(call_profile); @@ -141,6 +169,7 @@ AmSession* SBCFactory::onInvite(const AmSipRequest& req) if (call_profile.sst_enabled) { AmSessionEventHandler* h = session_timer_fact->getHandler(b2b_dlg); if(!h) { + profiles_mut.unlock(); delete b2b_dlg; ERROR("could not get a session timer event handler\n"); throw AmSession::Exception(500,"Server internal error"); @@ -153,10 +182,182 @@ AmSession* SBCFactory::onInvite(const AmSipRequest& req) b2b_dlg->addHandler(h); } } + profiles_mut.unlock(); return b2b_dlg; } +void SBCFactory::invoke(const string& method, const AmArg& args, + AmArg& ret) +{ + if (method == "listProfiles"){ + listProfiles(args, ret); + } else if (method == "reloadProfiles"){ + reloadProfiles(args,ret); + } else if (method == "loadProfile"){ + args.assertArrayFmt("u"); + loadProfile(args,ret); + } else if (method == "reloadProfile"){ + args.assertArrayFmt("u"); + reloadProfile(args,ret); + } else if (method == "getActiveProfile"){ + getActiveProfile(args,ret); + } else if (method == "setActiveProfile"){ + args.assertArrayFmt("u"); + setActiveProfile(args,ret); + } else if(method == "_list"){ + ret.push(AmArg("listProfiles")); + ret.push(AmArg("reloadProfiles")); + ret.push(AmArg("reloadProfile")); + ret.push(AmArg("loadProfile")); + ret.push(AmArg("getActiveProfile")); + ret.push(AmArg("setActiveProfile")); + } else + throw AmDynInvoke::NotImplemented(method); +} + +void SBCFactory::listProfiles(const AmArg& args, AmArg& ret) { + profiles_mut.lock(); + for (std::map::iterator it= + call_profiles.begin(); it != call_profiles.end(); it++) { + AmArg p; + p["name"] = it->first; + p["md5"] = it->second.md5hash; + p["path"] = it->second.profile_file; + ret.push((p)); + } + profiles_mut.unlock(); +} + +void SBCFactory::reloadProfiles(const AmArg& args, AmArg& ret) { + std::map new_call_profiles; + + bool failed = false; + string res = "OK"; + AmArg profile_list; + profiles_mut.lock(); + for (std::map::iterator it= + call_profiles.begin(); it != call_profiles.end(); it++) { + new_call_profiles[it->first] = SBCCallProfile(); + if (!new_call_profiles[it->first].readFromConfiguration(it->first, + it->second.profile_file)) { + ERROR("reading call profile file '%s'\n", it->second.profile_file.c_str()); + res = "Error reading call profile for "+it->first+" from "+it->second.profile_file+ + +"; no profiles reloaded"; + failed = true; + break; + } + AmArg p; + p["name"] = it->first; + p["md5"] = it->second.md5hash; + p["path"] = it->second.profile_file; + profile_list.push(p); + } + if (!failed) { + call_profiles = new_call_profiles; + ret.push(200); + } else { + ret.push(500); + } + ret.push(res); + ret.push(profile_list); + profiles_mut.unlock(); +} + +void SBCFactory::reloadProfile(const AmArg& args, AmArg& ret) { + bool failed = false; + string res = "OK"; + AmArg p; + if (!args[0].hasMember("name")) { + ret.push(400); + ret.push("Parameters error: expected ['name': profile_name] "); + return; + } + + profiles_mut.lock(); + std::map::iterator it= + call_profiles.find(args[0]["name"].asCStr()); + if (it == call_profiles.end()) { + res = "profile '"+string(args[0]["name"].asCStr())+"' not found"; + failed = true; + } else { + SBCCallProfile new_cp; + if (!new_cp.readFromConfiguration(it->first, it->second.profile_file)) { + ERROR("reading call profile file '%s'\n", it->second.profile_file.c_str()); + res = "Error reading call profile for "+it->first+" from "+it->second.profile_file; + failed = true; + } else { + it->second = new_cp; + p["name"] = it->first; + p["md5"] = it->second.md5hash; + p["path"] = it->second.profile_file; + } + } + profiles_mut.unlock(); + + if (!failed) { + ret.push(200); + ret.push(res); + ret.push(p); + } else { + ret.push(500); + ret.push(res); + } +} + +void SBCFactory::loadProfile(const AmArg& args, AmArg& ret) { + if (!args[0].hasMember("name") || !args[0].hasMember("path")) { + ret.push(400); + ret.push("Parameters error: expected ['name': profile_name] " + "and ['path': profile_path]"); + return; + } + SBCCallProfile cp; + if (!cp.readFromConfiguration(args[0]["name"].asCStr(), args[0]["path"].asCStr())) { + ret.push(500); + ret.push("Error reading sbc call profile for "+string(args[0]["name"].asCStr())+ + " from file "+string(args[0]["path"].asCStr())); + return; + } + + profiles_mut.lock(); + call_profiles[args[0]["name"].asCStr()] = cp; + profiles_mut.unlock(); + ret.push(200); + ret.push("OK"); + AmArg p; + p["name"] = args[0]["name"]; + p["md5"] = cp.md5hash; + p["path"] = args[0]["path"]; + ret.push(p); +} + +void SBCFactory::getActiveProfile(const AmArg& args, AmArg& ret) { + profiles_mut.lock(); + AmArg p; + p["active_profile"] = active_profile; + profiles_mut.unlock(); + ret.push(200); + ret.push("OK"); + ret.push(p); +} + +void SBCFactory::setActiveProfile(const AmArg& args, AmArg& ret) { + if (!args[0].hasMember("active_profile")) { + ret.push(400); + ret.push("Parameters error: expected ['active_profile': ] "); + return; + } + profiles_mut.lock(); + active_profile = args[0]["active_profile"].asCStr(); + profiles_mut.unlock(); + ret.push(200); + ret.push("OK"); + AmArg p; + p["active_profile"] = args[0]["active_profile"]; + ret.push(p); +} + SBCDialog::SBCDialog(const SBCCallProfile& call_profile) : m_state(BB_Init), diff --git a/apps/sbc/SBC.h b/apps/sbc/SBC.h index ad4ba6b5..93ef6851 100644 --- a/apps/sbc/SBC.h +++ b/apps/sbc/SBC.h @@ -41,16 +41,31 @@ using std::string; #define SBC_TIMER_ID_PREPAID_TIMEOUT 2 -class SBCFactory: public AmSessionFactory +class SBCFactory: public AmSessionFactory, + public AmDynInvoke, + public AmDynInvokeFactory { - std::map call_profiles; - std::map call_profiles_configs; + std::map call_profiles; + string active_profile; + AmMutex profiles_mut; + + static SBCFactory* _instance; + static bool loaded; + + void listProfiles(const AmArg& args, AmArg& ret); + void reloadProfiles(const AmArg& args, AmArg& ret); + void reloadProfile(const AmArg& args, AmArg& ret); + void loadProfile(const AmArg& args, AmArg& ret); + void getActiveProfile(const AmArg& args, AmArg& ret); + void setActiveProfile(const AmArg& args, AmArg& ret); public: + static SBCFactory* instance(); SBCFactory(const string& _app_name); - + ~SBCFactory(); + int onLoad(); AmSession* onInvite(const AmSipRequest& req); static string user; @@ -59,6 +74,14 @@ class SBCFactory: public AmSessionFactory static AmConfigReader cfg; static AmSessionEventHandlerFactory* session_timer_fact; + + // DI + // DI factory + AmDynInvoke* getInstance() { return instance(); } + // DI API + void invoke(const string& method, + const AmArg& args, AmArg& ret); + }; class SBCDialog : public AmB2BCallerSession diff --git a/apps/sbc/SBCCallProfile.cpp b/apps/sbc/SBCCallProfile.cpp index 205284ea..54a7c64b 100644 --- a/apps/sbc/SBCCallProfile.cpp +++ b/apps/sbc/SBCCallProfile.cpp @@ -14,6 +14,8 @@ bool SBCCallProfile::readFromConfiguration(const string& name, return false; } + profile_file = profile_file_name; + ruri = cfg.getParameter("RURI"); from = cfg.getParameter("From"); to = cfg.getParameter("To"); @@ -140,7 +142,12 @@ bool SBCCallProfile::readFromConfiguration(const string& name, reply_translations[from_code] = make_pair(to_code, to_reply.substr(s_pos)); } - INFO("SBC: loaded SBC profile '%s':\n", name.c_str()); + md5hash = ""; + if (!cfg.getMD5(profile_file_name, md5hash)){ + ERROR("calculating MD5 of file %s\n", profile_file_name.c_str()); + } + + INFO("SBC: loaded SBC profile '%s' - MD5: %s\n", name.c_str(), md5hash.c_str()); INFO("SBC: RURI = '%s'\n", ruri.c_str()); INFO("SBC: From = '%s'\n", from.c_str()); diff --git a/apps/sbc/SBCCallProfile.h b/apps/sbc/SBCCallProfile.h index 66e5a889..7c581695 100644 --- a/apps/sbc/SBCCallProfile.h +++ b/apps/sbc/SBCCallProfile.h @@ -17,6 +17,8 @@ using std::set; struct SBCCallProfile { AmConfigReader cfg; + string md5hash; + string profile_file; string ruri; /* updated if set */ string from; /* updated if set */ diff --git a/apps/sbc/tools/Makefile b/apps/sbc/tools/Makefile new file mode 100644 index 00000000..3bca8548 --- /dev/null +++ b/apps/sbc/tools/Makefile @@ -0,0 +1,15 @@ +COREPATH ?= ../../../core +include $(COREPATH)/../Makefile.defs + +sbc_scripts = $(wildcard sems-sbc-*) + +all: install_tools +install: install_tools + +install_tools: $(DESTDIR)$(bin-prefix)/$(bin-dir) + -@for r in $(sbc_scripts) ; do \ + $(INSTALL-TOUCH) $(DESTDIR)$(bin-prefix)/$(bin-dir)/$$r ; \ + $(INSTALL-BIN) $$r $(DESTDIR)$(bin-prefix)/$(bin-dir) ; \ + done + + diff --git a/apps/sbc/tools/sems-sbc-get-activeprofile b/apps/sbc/tools/sems-sbc-get-activeprofile new file mode 100755 index 00000000..eaf93c7b --- /dev/null +++ b/apps/sbc/tools/sems-sbc-get-activeprofile @@ -0,0 +1,7 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from xmlrpclib import * +s = ServerProxy('http://localhost:8090') +print "Active calls: %d" % s.calls() +print s.getActiveProfile() diff --git a/apps/sbc/tools/sems-sbc-list-profiles b/apps/sbc/tools/sems-sbc-list-profiles new file mode 100755 index 00000000..5ebacc0e --- /dev/null +++ b/apps/sbc/tools/sems-sbc-list-profiles @@ -0,0 +1,7 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from xmlrpclib import * +s = ServerProxy('http://localhost:8090') +print "Active calls: %d" % s.calls() +print s.listProfiles() diff --git a/apps/sbc/tools/sems-sbc-load-profile b/apps/sbc/tools/sems-sbc-load-profile new file mode 100755 index 00000000..cdecba47 --- /dev/null +++ b/apps/sbc/tools/sems-sbc-load-profile @@ -0,0 +1,13 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import sys +from xmlrpclib import * + +if len(sys.argv) != 3: + print "usage: %s " % sys.argv[0] + sys.exit(1) + +s = ServerProxy('http://localhost:8090') +print "Active calls: %d" % s.calls() +p ={ 'name' : sys.argv[1], 'path' : sys.argv[2] } +print s.loadProfile(p) diff --git a/apps/sbc/tools/sems-sbc-reload-profile b/apps/sbc/tools/sems-sbc-reload-profile new file mode 100755 index 00000000..826bc37d --- /dev/null +++ b/apps/sbc/tools/sems-sbc-reload-profile @@ -0,0 +1,13 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import sys +from xmlrpclib import * + +if len(sys.argv) != 2: + print "usage: %s " % sys.argv[0] + sys.exit(1) + +s = ServerProxy('http://localhost:8090') +print "Active calls: %d" % s.calls() +p ={ 'name' : sys.argv[1] } +print s.reloadProfile(p) diff --git a/apps/sbc/tools/sems-sbc-reload-profiles b/apps/sbc/tools/sems-sbc-reload-profiles new file mode 100755 index 00000000..b113a9a4 --- /dev/null +++ b/apps/sbc/tools/sems-sbc-reload-profiles @@ -0,0 +1,7 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from xmlrpclib import * +s = ServerProxy('http://localhost:8090') +print s.calls() +print s.reloadProfiles() diff --git a/apps/sbc/tools/sems-sbc-set-activeprofile b/apps/sbc/tools/sems-sbc-set-activeprofile new file mode 100755 index 00000000..bf76ee8c --- /dev/null +++ b/apps/sbc/tools/sems-sbc-set-activeprofile @@ -0,0 +1,12 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import sys +from xmlrpclib import * + +if len(sys.argv) != 2: + print "usage: %s " % sys.argv[0] + sys.exit(1) + +s = ServerProxy('http://localhost:8090') +print "Active calls: %d" % s.calls() +print s.setActiveProfile(sys.argv[1])