]> git.stg.codes - stg.git/blobdiff - projects/stargazer/plugins/configuration/sgconfig/configproto.cpp
Add an option to opt-out Firebird store.
[stg.git] / projects / stargazer / plugins / configuration / sgconfig / configproto.cpp
index 17a226bea6e7309b8257dd9eefc04193e61c8cf4..5c176f4568fd6fc5cb76f04dd2518b43d598390f 100644 (file)
 
 #include "conn.h"
 
+#include "parser_server_info.h"
+#include "parser_admins.h"
+#include "parser_tariffs.h"
+#include "parser_users.h"
+#include "parser_services.h"
+#include "parser_message.h"
+#include "parser_user_info.h"
+#include "parser_auth_by.h"
+
 #include "stg/common.h"
 #include "stg/logger.h"
 
 #include <algorithm>
 #include <functional>
+#include <vector>
 #include <csignal>
 #include <cstring>
 #include <cerrno>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
-#include <arpa/inet.h>
-
-namespace
-{
-
-struct IsFinished : public std::unary_function<STG::Conn *, bool>
-{
-    result_type operator()(const argument_type & arg)
-    {
-        return (arg->IsDone() && !arg->IsKeepAlive()) || !arg->IsOk();
-    }
-};
-
-struct RemoveConn : public std::unary_function<STG::Conn *, void>
-{
-    result_type operator()(const argument_type & arg)
-    {
-        delete arg;
-    }
-};
+#include <netdb.h>
 
-}
+namespace SP = STG::PARSER;
 
-CONFIGPROTO::CONFIGPROTO(PLUGIN_LOGGER & l)
+CONFIGPROTO::CONFIGPROTO(STG::PluginLogger & l)
     : m_settings(NULL),
       m_admins(NULL),
       m_tariffs(NULL),
       m_users(NULL),
+      m_services(NULL),
+      m_corporations(NULL),
+      m_store(NULL),
       m_port(0),
-      m_running(false),
+      m_bindAddress("0.0.0.0"),
       m_stopped(true),
       m_logger(l),
       m_listenSocket(-1)
 {
-    std::for_each(m_conns.begin(), m_conns.end(), RemoveConn());
+}
+
+CONFIGPROTO::~CONFIGPROTO()
+{
+    {
+    std::deque<STG::Conn *>::iterator it;
+    for (it = m_conns.begin(); it != m_conns.end(); ++it)
+        delete *it;
+    }
+    {
+    BASE_PARSER::REGISTRY::iterator it;
+    for (it = m_registry.begin(); it != m_registry.end(); ++it)
+        delete it->second;
+    }
 }
 
 int CONFIGPROTO::Prepare()
@@ -82,7 +89,6 @@ int CONFIGPROTO::Prepare()
     sigaddset(&sigmask, SIGUSR1);
     sigaddset(&sigmask, SIGHUP);
     pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
-
     m_listenSocket = socket(PF_INET, SOCK_STREAM, 0);
 
     if (m_listenSocket < 0)
@@ -92,11 +98,6 @@ int CONFIGPROTO::Prepare()
         return -1;
     }
 
-    struct sockaddr_in listenAddr;
-    listenAddr.sin_family = PF_INET;
-    listenAddr.sin_port = htons(m_port);
-    listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0"); // TODO: arbitrary address
-
     int dummy = 1;
 
     if (setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, &dummy, 4) != 0)
@@ -106,12 +107,8 @@ int CONFIGPROTO::Prepare()
         return -1;
     }
 
-    if (bind(m_listenSocket, reinterpret_cast<sockaddr *>(&listenAddr), sizeof(listenAddr)) == -1)
-    {
-        m_errorStr = std::string("Cannot bind listen socket: '") + strerror(errno) + "'.";
-        m_logger(m_errorStr);
+    if (!Bind())
         return -1;
-    }
 
     if (listen(m_listenSocket, 64) == -1) // TODO: backlog length
     {
@@ -120,14 +117,14 @@ int CONFIGPROTO::Prepare()
         return -1;
     }
 
-    m_running = true;
+    RegisterParsers();
+
     m_stopped = false;
     return 0;
 }
 
 int CONFIGPROTO::Stop()
 {
-    m_running = false;
     for (int i = 0; i < 5 && !m_stopped; ++i)
     {
         struct timespec ts = {0, 200000000};
@@ -146,9 +143,9 @@ int CONFIGPROTO::Stop()
     return 0;
 }
 
-void CONFIGPROTO::Run()
+void CONFIGPROTO::Run(std::stop_token token)
 {
-    while (m_running)
+    while (!token.stop_requested())
     {
         fd_set fds;
 
@@ -162,10 +159,11 @@ void CONFIGPROTO::Run()
         if (res < 0)
         {
             m_errorStr = std::string("'select' is failed: '") + strerror(errno) + "'.";
+            printfd(__FILE__, "%s\n", m_errorStr.c_str());
             m_logger(m_errorStr);
             break;
         }
-        if (!m_running)
+        if (token.stop_requested())
             break;
         if (res > 0)
             HandleEvents(fds);
@@ -175,28 +173,112 @@ void CONFIGPROTO::Run()
     m_stopped = true;
 }
 
+bool CONFIGPROTO::Bind()
+{
+    const hostent * he = gethostbyname(m_bindAddress.c_str());
+    if (he == NULL)
+    {
+        m_errorStr = "Failed to resolve name '" + m_bindAddress + "': '" + hstrerror(h_errno) + "'.";
+        printfd(__FILE__, "%s\n", m_errorStr.c_str());
+        m_logger(m_errorStr);
+        return false;
+    }
+
+    char ** ptr = he->h_addr_list;
+    while (*ptr != NULL)
+    {
+        struct sockaddr_in listenAddr;
+        listenAddr.sin_family = PF_INET;
+        listenAddr.sin_port = htons(m_port);
+        listenAddr.sin_addr.s_addr = *reinterpret_cast<in_addr_t *>(*ptr);
+
+        printfd(__FILE__, "Trying to bind to %s:%d\n", inet_ntostring(listenAddr.sin_addr.s_addr).c_str(), m_port);
+
+        if (bind(m_listenSocket, reinterpret_cast<sockaddr *>(&listenAddr), sizeof(listenAddr)) == 0)
+            return true;
+
+        m_errorStr = std::string("Cannot bind listen socket: '") + strerror(errno) + "'.";
+        printfd(__FILE__, "%s\n", m_errorStr.c_str());
+        m_logger(m_errorStr);
+
+        ++ptr;
+    }
+
+    return false;
+}
+
+void CONFIGPROTO::RegisterParsers()
+{
+    assert(m_settings != NULL);
+    assert(m_store != NULL);
+    assert(m_admins != NULL);
+    assert(m_users != NULL);
+    assert(m_tariffs != NULL);
+    assert(m_services != NULL);
+    assert(m_corporations != NULL);
+
+    SP::GET_SERVER_INFO::FACTORY::Register(m_registry, *m_settings, *m_users, *m_tariffs);
+
+    SP::GET_ADMINS::FACTORY::Register(m_registry, *m_admins);
+    SP::ADD_ADMIN::FACTORY::Register(m_registry, *m_admins);
+    SP::DEL_ADMIN::FACTORY::Register(m_registry, *m_admins);
+    SP::CHG_ADMIN::FACTORY::Register(m_registry, *m_admins);
+
+    SP::GET_TARIFFS::FACTORY::Register(m_registry, *m_tariffs);
+    SP::ADD_TARIFF::FACTORY::Register(m_registry, *m_tariffs);
+    SP::DEL_TARIFF::FACTORY::Register(m_registry, *m_tariffs, *m_users);
+    SP::CHG_TARIFF::FACTORY::Register(m_registry, *m_tariffs);
+
+    SP::GET_USERS::FACTORY::Register(m_registry, *m_users);
+    SP::GET_USER::FACTORY::Register(m_registry, *m_users);
+    SP::ADD_USER::FACTORY::Register(m_registry, *m_users);
+    SP::DEL_USER::FACTORY::Register(m_registry, *m_users);
+    SP::CHG_USER::FACTORY::Register(m_registry, *m_users, *m_store, *m_tariffs);
+    SP::CHECK_USER::FACTORY::Register(m_registry, *m_users);
+
+    SP::GET_SERVICES::FACTORY::Register(m_registry, *m_services);
+    SP::GET_SERVICE::FACTORY::Register(m_registry, *m_services);
+    SP::ADD_SERVICE::FACTORY::Register(m_registry, *m_services);
+    SP::DEL_SERVICE::FACTORY::Register(m_registry, *m_services);
+    SP::CHG_SERVICE::FACTORY::Register(m_registry, *m_services);
+
+    SP::SEND_MESSAGE::FACTORY::Register(m_registry, *m_users);
+
+    SP::AUTH_BY::FACTORY::Register(m_registry, *m_users);
+
+    SP::USER_INFO::FACTORY::Register(m_registry, *m_users);
+}
+
 int CONFIGPROTO::MaxFD() const
 {
     int maxFD = m_listenSocket;
-    for (size_t i = 0; i < m_conns.size(); ++i)
-        if (maxFD < m_conns[i]->Sock())
-            maxFD = m_conns[i]->Sock();
+    std::deque<STG::Conn *>::const_iterator it;
+    for (it = m_conns.begin(); it != m_conns.end(); ++it)
+        if (maxFD < (*it)->Sock())
+            maxFD = (*it)->Sock();
     return maxFD;
 }
 
 void CONFIGPROTO::BuildFDSet(fd_set & fds) const
 {
-    for (size_t i = 0; i < m_conns.size(); ++i)
-        FD_SET(m_conns[i]->Sock(), &fds);
+    FD_ZERO(&fds);
+    FD_SET(m_listenSocket, &fds);
+    std::deque<STG::Conn *>::const_iterator it;
+    for (it = m_conns.begin(); it != m_conns.end(); ++it)
+        FD_SET((*it)->Sock(), &fds);
 }
 
 void CONFIGPROTO::CleanupConns()
 {
-    std::vector<STG::Conn *>::iterator pos;
-    pos = std::remove_if(m_conns.begin(), m_conns.end(), IsFinished());
-    if (pos == m_conns.end())
-        return;
-    std::for_each(pos, m_conns.end(), RemoveConn());
+    std::deque<STG::Conn *>::iterator pos;
+    for (pos = m_conns.begin(); pos != m_conns.end(); ++pos)
+        if (((*pos)->IsDone() && !(*pos)->IsKeepAlive()) || !(*pos)->IsOk())
+        {
+            delete *pos;
+            *pos = NULL;
+        }
+
+    pos = std::remove(m_conns.begin(), m_conns.end(), static_cast<STG::Conn *>(NULL));
     m_conns.erase(pos, m_conns.end());
 }
 
@@ -206,9 +288,10 @@ void CONFIGPROTO::HandleEvents(const fd_set & fds)
         AcceptConnection();
     else
     {
-        for (size_t i = 0; i < m_conns.size(); ++i)
-            if (FD_ISSET(m_conns[i]->Sock(), &fds))
-                m_conns[i]->Read();
+        std::deque<STG::Conn *>::iterator it;
+        for (it = m_conns.begin(); it != m_conns.end(); ++it)
+            if (FD_ISSET((*it)->Sock(), &fds))
+                (*it)->Read();
     }
 }
 
@@ -221,23 +304,21 @@ void CONFIGPROTO::AcceptConnection()
     if (sock < 0)
     {
         m_errorStr = std::string("Failed to accept connection: '") + strerror(errno) + "'.";
-        printfd(__FILE__, "%s", m_errorStr.c_str());
+        printfd(__FILE__, "%s\n", m_errorStr.c_str());
         m_logger(m_errorStr);
         return;
     }
 
-    assert(m_settings != NULL);
     assert(m_admins != NULL);
-    assert(m_users != NULL);
-    assert(m_tariffs != NULL);
-
-    m_conns.push_back(new STG::Conn(*m_settings, *m_admins, *m_users, *m_tariffs, sock, outerAddr));
 
-    printfd(__FILE__, "New connection from %s:%d\n", inet_ntostring(m_conns.back()->IP()).c_str(), m_conns.back()->Port());
-}
-/*
-void CONFIGPROTO::WriteLogAccessFailed(uint32_t ip)
-{
-    m_logger("Admin's connection failed. IP %s", inet_ntostring(ip).c_str());
+    try
+    {
+        m_conns.push_back(new STG::Conn(m_registry, *m_admins, sock, outerAddr, m_logger));
+        printfd(__FILE__, "New connection from %s:%d. Total connections: %d\n", inet_ntostring(m_conns.back()->IP()).c_str(), m_conns.back()->Port(), m_conns.size());
+    }
+    catch (const STG::Conn::Error & error)
+    {
+        // Unlikely.
+        m_logger(std::string("Failed to create new client connection: '") + error.what() + "'.");
+    }
 }
-*/