Browse Source

Add SIP URI validator.

Michał Słomkowski 8 years ago
parent
commit
9d4da88e9f
7 changed files with 129 additions and 58 deletions
  1. 3 1
      CMakeLists.txt
  2. 11 0
      IncomingConnectionValidator.cpp
  3. 19 0
      IncomingConnectionValidator.hpp
  4. 83 54
      PjsuaCommunicator.cpp
  5. 4 1
      PjsuaCommunicator.hpp
  6. 1 0
      config.ini.example
  7. 8 2
      main.cpp

+ 3 - 1
CMakeLists.txt

@@ -26,7 +26,9 @@ set(SOURCE_FILES
         MumbleCommunicator.hpp
         ICommunicator.hpp
         Configuration.cpp
-        Configuration.hpp)
+        Configuration.hpp
+        IncomingConnectionValidator.cpp
+        IncomingConnectionValidator.hpp)
 
 add_executable(mumsi ${SOURCE_FILES} main.cpp)
 target_link_libraries(mumsi ${PJSIP_LIBRARIES})

+ 11 - 0
IncomingConnectionValidator.cpp

@@ -0,0 +1,11 @@
+#include "IncomingConnectionValidator.hpp"
+
+sip::IncomingConnectionValidator::IncomingConnectionValidator(std::string validUriExpression)
+        : validUriExpression(validUriExpression),
+          logger(log4cpp::Category::getInstance("IncomingConnectionValidator")) {
+
+}
+
+bool sip::IncomingConnectionValidator::validateUri(std::string uri) {
+    return true;
+}

+ 19 - 0
IncomingConnectionValidator.hpp

@@ -0,0 +1,19 @@
+#pragma once
+
+#include <boost/noncopyable.hpp>
+#include <log4cpp/Category.hh>
+
+#include <string>
+
+namespace sip {
+    class IncomingConnectionValidator : boost::noncopyable {
+    public:
+        IncomingConnectionValidator(std::string validUriExpression);
+
+        bool validateUri(std::string uri);
+
+    private:
+        log4cpp::Category &logger;
+        std::string validUriExpression;
+    };
+}

+ 83 - 54
PjsuaCommunicator.cpp

@@ -93,87 +93,116 @@ namespace sip {
                   communicator(comm),
                   account(acc) { }
 
-        virtual void onCallState(pj::OnCallStateParam &prm) {
-            auto ci = getInfo();
+        virtual void onCallState(pj::OnCallStateParam &prm);
 
-            communicator.logger.info("Call %d state=%s.", ci.id, ci.stateText.c_str());
+        virtual void onCallMediaState(pj::OnCallMediaStateParam &prm);
 
-            string address = ci.remoteUri;
+        virtual void onDtmfDigit(pj::OnDtmfDigitParam &prm);
 
-            boost::replace_all(address, "<", "");
-            boost::replace_all(address, ">", "");
+    private:
+        sip::PjsuaCommunicator &communicator;
+        pj::Account &account;
+    };
 
-            if (ci.state == PJSIP_INV_STATE_CONFIRMED) {
-                auto msgText = "Incoming call from " + address + ".";
+    class _Account : public pj::Account {
+    public:
+        _Account(sip::PjsuaCommunicator &comm)
+                : communicator(comm) { }
 
-                communicator.logger.notice(msgText);
-                communicator.onStateChange(msgText);
-            } else if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
-                auto msgText = "Call from " + address + " finished.";
+        virtual void onRegState(pj::OnRegStateParam &prm);
 
-                communicator.logger.notice(msgText);
-                communicator.onStateChange(msgText);
+        virtual void onIncomingCall(pj::OnIncomingCallParam &iprm);
 
-                delete this;
-            }
-        }
+    private:
+        sip::PjsuaCommunicator &communicator;
 
-        virtual void onCallMediaState(pj::OnCallMediaStateParam &prm) {
-            auto ci = getInfo();
+        bool available = true;
 
-            if (ci.media.size() != 1) {
-                throw sip::Exception("ci.media.size is not 1");
-            }
+        friend class _Call;
+    };
 
-            if (ci.media[0].status == PJSUA_CALL_MEDIA_ACTIVE) {
-                auto *aud_med = static_cast<pj::AudioMedia *>(getMedia(0));
+    void _Call::onCallState(pj::OnCallStateParam &prm) {
+        auto ci = getInfo();
 
-                communicator.media->startTransmit(*aud_med);
-                aud_med->startTransmit(*communicator.media);
-            }
-        }
+        communicator.logger.info("Call %d state=%s.", ci.id, ci.stateText.c_str());
+
+        string address = ci.remoteUri;
+
+        boost::replace_all(address, "<", "");
+        boost::replace_all(address, ">", "");
 
-        virtual void onDtmfDigit(pj::OnDtmfDigitParam &prm) {
-            communicator.logger.notice("DTMF digit '%s' (call %d).", prm.digit.c_str(), getId());
+        if (ci.state == PJSIP_INV_STATE_CONFIRMED) {
+            auto msgText = "Incoming call from " + address + ".";
+
+            communicator.logger.notice(msgText);
+            communicator.onStateChange(msgText);
+        } else if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
+            auto msgText = "Call from " + address + " finished.";
+
+            communicator.logger.notice(msgText);
+            communicator.onStateChange(msgText);
+
+            dynamic_cast<_Account &>(account).available = true;
+
+            delete this;
         }
+    }
 
-    private:
-        sip::PjsuaCommunicator &communicator;
-        pj::Account &account;
-    };
+    void _Call::onCallMediaState(pj::OnCallMediaStateParam &prm) {
+        auto ci = getInfo();
 
-    class _Account : public pj::Account {
-    public:
-        _Account(sip::PjsuaCommunicator &comm)
-                : communicator(comm) { }
+        if (ci.media.size() != 1) {
+            throw sip::Exception("ci.media.size is not 1");
+        }
+
+        if (ci.media[0].status == PJSUA_CALL_MEDIA_ACTIVE) {
+            auto *aud_med = static_cast<pj::AudioMedia *>(getMedia(0));
 
-        virtual void onRegState(pj::OnRegStateParam &prm) {
-            pj::AccountInfo ai = getInfo();
-            communicator.logger << log4cpp::Priority::INFO
-            << (ai.regIsActive ? "Register:" : "Unregister:") << " code=" << prm.code;
+            communicator.media->startTransmit(*aud_med);
+            aud_med->startTransmit(*communicator.media);
+        } else if (ci.media[0].status == PJSUA_CALL_MEDIA_NONE) {
+            dynamic_cast<_Account &>(account).available = true;
         }
+    }
+
+    void _Call::onDtmfDigit(pj::OnDtmfDigitParam &prm) {
+        communicator.logger.notice("DTMF digit '%s' (call %d).", prm.digit.c_str(), getId());
+    }
 
-        virtual void onIncomingCall(pj::OnIncomingCallParam &iprm) {
-            auto *call = new _Call(communicator, *this, iprm.callId);
+    void _Account::onRegState(pj::OnRegStateParam &prm) {
+        pj::AccountInfo ai = getInfo();
+        communicator.logger << log4cpp::Priority::INFO
+        << (ai.regIsActive ? "Register:" : "Unregister:") << " code=" << prm.code;
+    }
+
+    void _Account::onIncomingCall(pj::OnIncomingCallParam &iprm) {
+        auto *call = new _Call(communicator, *this, iprm.callId);
+
+        string uri = call->getInfo().remoteUri;
 
-            communicator.logger.info("Incoming call from %s.", call->getInfo().remoteUri.c_str());
+        communicator.logger.info("Incoming call from %s.", uri.c_str());
 
+        if (communicator.uriValidator.validateUri(uri)) {
             pj::CallOpParam param;
-            param.statusCode = PJSIP_SC_OK;
+
+            if (available) {
+                param.statusCode = PJSIP_SC_OK;
+                available = false;
+            } else {
+                param.statusCode = PJSIP_SC_BUSY_EVERYWHERE;
+            }
 
             call->answer(param);
+        } else {
+            communicator.logger.warn("Refusing call from %s.", uri.c_str());
         }
-
-    private:
-        sip::PjsuaCommunicator &communicator;
-
-        friend class _Call;
-    };
+    }
 }
 
-sip::PjsuaCommunicator::PjsuaCommunicator()
+sip::PjsuaCommunicator::PjsuaCommunicator(IncomingConnectionValidator &validator)
         : logger(log4cpp::Category::getInstance("SipCommunicator")),
-          pjsuaLogger(log4cpp::Category::getInstance("Pjsua")) {
+          pjsuaLogger(log4cpp::Category::getInstance("Pjsua")),
+          uriValidator(validator) {
 
     logWriter.reset(new sip::_LogWriter(pjsuaLogger));
 

+ 4 - 1
PjsuaCommunicator.hpp

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "ICommunicator.hpp"
+#include "IncomingConnectionValidator.hpp"
 
 #include <pjmedia.h>
 #include <pjsua-lib/pjsua.h>
@@ -56,7 +57,7 @@ namespace sip {
 
     class PjsuaCommunicator : public ICommunicator, boost::noncopyable {
     public:
-        PjsuaCommunicator();
+        PjsuaCommunicator(IncomingConnectionValidator &validator);
 
         void connect(
                 std::string host,
@@ -90,6 +91,8 @@ namespace sip {
 
         std::mutex inBuffAccessMutex;
 
+        IncomingConnectionValidator &uriValidator;
+
         void registerAccount(std::string host,
                              std::string user,
                              std::string password);

+ 1 - 0
config.ini.example

@@ -1,4 +1,5 @@
 [sip]
+validUriExpression = *@sip.example.com *@127.0.0.1
 host = sip.example.org
 port = 5060
 user = mumsi

+ 8 - 2
main.cpp

@@ -1,14 +1,18 @@
 #include "PjsuaCommunicator.hpp"
 #include "MumbleCommunicator.hpp"
+#include "IncomingConnectionValidator.hpp"
 #include "Configuration.hpp"
 
 #include <log4cpp/FileAppender.hh>
 #include <log4cpp/OstreamAppender.hh>
+#include <log4cpp/PatternLayout.hh>
 
 int main(int argc, char *argv[]) {
 
     log4cpp::Appender *appender1 = new log4cpp::OstreamAppender("console", &std::cout);
-    appender1->setLayout(new log4cpp::BasicLayout());
+    log4cpp::PatternLayout layout;
+    layout.setConversionPattern("%d [%p] %c: %m%n");
+    appender1->setLayout(&layout);
     log4cpp::Category &logger = log4cpp::Category::getRoot();
     logger.setPriority(log4cpp::Priority::NOTICE);
     logger.addAppender(appender1);
@@ -20,9 +24,11 @@ int main(int argc, char *argv[]) {
 
     config::Configuration conf(argv[1]);
 
+    sip::IncomingConnectionValidator connectionValidator(conf.getString("sip.validUriExpression"));
+
     boost::asio::io_service ioService;
 
-    sip::PjsuaCommunicator pjsuaCommunicator;
+    sip::PjsuaCommunicator pjsuaCommunicator(connectionValidator);
 
     mumble::MumbleCommunicator mumbleCommunicator(ioService);