]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1572 in SNORT/snort3 from ~DDAHIPHA/snort3:dev_large_fd_segfault...
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Wed, 24 Apr 2019 19:10:45 +0000 (15:10 -0400)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Wed, 24 Apr 2019 19:10:45 +0000 (15:10 -0400)
Squashed commit of the following:

commit bcc34f2893948bf0ed49d563d576e4abf0e45626
Author: Devendra Dahiphale <ddahipha@cisco.com>
Date:   Tue Apr 23 15:00:15 2019 -0400

    main: Use epoll(for linux systems) instead of select to get rid of limit on fd-set-size and for time efficiency

src/main.cc
src/main/CMakeLists.txt
src/main/ac_shell_cmd.cc [new file with mode: 0644]
src/main/ac_shell_cmd.h [new file with mode: 0644]
src/main/control_mgmt.cc
src/main/control_mgmt.h
src/main/snort.cc

index bf232d5e3938f8f740936df8ff59bbaa8a6bb0cd..2b56bdd7386bbdfe90081da6dc657776a4e65e93 100644 (file)
@@ -61,6 +61,7 @@
 
 #ifdef SHELL
 #include "main/control_mgmt.h"
+#include "main/ac_shell_cmd.h"
 #endif
 
 //-------------------------------------------------------------------------
index 9c8d9b185b531c4a3d056d87e5e1f92e847a0ef6..2dbea989157378bba5619d9e3d1025dc666f0440 100644 (file)
@@ -13,7 +13,7 @@ if ( ENABLE_DEBUG_MSGS )
 endif ( ENABLE_DEBUG_MSGS )
 
 if ( ENABLE_SHELL )
-    set ( SHELL_SOURCES control.cc control.h control_mgmt.cc control_mgmt.h )
+    set ( SHELL_SOURCES control.cc control.h control_mgmt.cc control_mgmt.h ac_shell_cmd.h ac_shell_cmd.cc)
 endif ( ENABLE_SHELL )
 
 add_library (main OBJECT
diff --git a/src/main/ac_shell_cmd.cc b/src/main/ac_shell_cmd.cc
new file mode 100644 (file)
index 0000000..9a59bcd
--- /dev/null
@@ -0,0 +1,64 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ac_shell_cmd.cc author Bhagya Tholpady <bbantwal@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ac_shell_cmd.h"
+
+#include <cassert>
+
+#include "control_mgmt.h"
+#include "control.h"
+
+ACShellCmd::ACShellCmd(int fd, AnalyzerCommand *ac) : ac(ac)
+{
+    assert(ac);
+
+    ControlConn* control_conn = ControlMgmt::find_control(fd);
+
+    if( control_conn )
+    {
+        control_conn->block();
+        control_fd = fd;
+    }
+}
+
+void ACShellCmd::execute(Analyzer& analyzer)
+{
+    ControlConn* control_conn = ControlMgmt::find_control(control_fd);
+
+    if( control_conn )
+        control_conn->send_queued_response();
+
+    ac->execute(analyzer);
+}
+
+ACShellCmd::~ACShellCmd()
+{
+    delete ac;
+    ControlConn* control = ControlMgmt::find_control(control_fd);
+
+    if( control )
+    {
+        control->send_queued_response();
+        control->unblock();
+    }
+}
diff --git a/src/main/ac_shell_cmd.h b/src/main/ac_shell_cmd.h
new file mode 100644 (file)
index 0000000..c8e99ea
--- /dev/null
@@ -0,0 +1,43 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// control_mgmt.h author Bhagya Tholpady <bbantwal@cisco.com>
+//
+// This provides functions to create and control remote/local connections,
+// socket creation/deletion/management functions, and shell commands used by the analyzer.
+
+#ifndef AC_SHELL_CMD_H
+#define AC_SHELL_CMD_H
+
+#include "main/analyzer.h"
+#include "main/analyzer_command.h"
+
+class ACShellCmd : public AnalyzerCommand
+{
+public:
+    ACShellCmd() = delete;
+    ACShellCmd(int fd, AnalyzerCommand* ac_cmd);
+    void execute(Analyzer&) override;
+    const char* stringify() override { return ac->stringify(); }
+    ~ACShellCmd() override;
+
+private:
+    int control_fd = -1;
+    AnalyzerCommand* ac;
+};
+
+#endif
index 0386c8a393f6046185e88cbf148831a9491f6798..fd28396aa6a83c6cde86ce1f3fb5aa7d99d1f8cb 100644 (file)
@@ -15,6 +15,8 @@
 // with this program; if not, write to the Free Software Foundation, Inc.,
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
+// control_mgmt.cc author Bhagya Tholpady <bbantwal@cisco.com>
+//                 author Devendra Dahiphale <ddahipha@cisco.com>
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -30,6 +32,7 @@
 
 #include "log/messages.h"
 #include "utils/stats.h"
+#include "utils/util.h"
 #include "control.h"
 #include "request.h"
 #include "snort_config.h"
@@ -42,20 +45,211 @@ static socklen_t sock_addr_size = 0;
 static struct sockaddr* sock_addr = nullptr;
 static struct sockaddr_in in_addr;
 static struct sockaddr_un unix_addr;
+
+//-------------------------------------------------------------------------
+// epoll implementation (supported by only linux systems)
+//-------------------------------------------------------------------------
+// Only linux systems support epoll (event polling) mechanism.
+// It allows a process to monitor multiple file descriptors
+// and get notification (using epoll_wait) when I/O is possible on them.
+#ifdef __linux__
+
+#include <sys/epoll.h>
+#include <unordered_map>
+
+static int epoll_fd = -1;
+static unordered_map<int, ControlConn*> controls;
+
+#define MAX_EPOLL_EVENTS 65535
+
+static void add_to_epoll(const int fd)
+{
+    if (epoll_fd == -1)
+    {
+        epoll_fd = epoll_create1(0);
+        if (epoll_fd == -1)
+            FatalError("Failed to create epoll file descriptor: %s\n", get_error(errno));
+    }
+
+    static struct epoll_event event;
+    event.events = EPOLLIN | EPOLLET;
+    event.data.fd = fd;
+
+    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event))
+        WarningMessage("Failed to add file descriptor to epoll: %s\n", get_error(errno));
+}
+
+static void remove_from_epoll(const int fd)
+{
+    if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr))
+        WarningMessage("Failed to remove file descriptor from epoll\n");
+}
+
+void ControlMgmt::add_control(int fd, bool local)
+{
+    if (controls.find(fd) != controls.end())
+    {
+        assert(0);
+        WarningMessage("Cannot have two active connections with the same fd\n");
+        return;
+    }
+
+    controls[fd] = new ControlConn(fd, local);
+    add_to_epoll(fd);
+}
+
+ControlConn* ControlMgmt::find_control(int fd)
+{
+    auto control_conn = controls.find(fd);
+    if (control_conn == controls.end())
+        return nullptr;
+
+    return control_conn->second;
+}
+
+void ControlMgmt::delete_control(int fd)
+{
+    auto control_conn = find_control(fd);
+    if (control_conn)
+    {
+        remove_from_epoll(fd);
+        delete control_conn;
+        controls.erase(fd);
+    }
+}
+
+void ControlMgmt::reconfigure_controls()
+{
+    for (auto &control : controls)
+        control.second->configure();
+}
+
+void ControlMgmt::delete_controls()
+{
+    for (auto &control : controls)
+    {
+        remove_from_epoll(control.first);
+        delete control.second;
+    }
+    controls.clear();
+}
+
+int ControlMgmt::socket_init()
+{
+    int sock_family = setup_socket_family();
+
+    if (sock_family == AF_UNSPEC)
+        return -1;
+
+    listener = socket(sock_family, SOCK_STREAM, 0);
+
+    if (listener < 0)
+        FatalError("socket failed: %s\n", get_error(errno));
+
+    // FIXIT-M want to disable time wait
+    int on = 1;
+    setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+    if (::bind(listener, sock_addr, sock_addr_size) < 0)
+        FatalError("bind failed: %s\n", get_error(errno));
+
+    // FIXIT-M configure max conns
+    if (listen(listener, 0) < 0)
+        FatalError("listen failed: %s\n", get_error(errno));
+
+    add_to_epoll(listener);
+
+    return 0;
+}
+
+int ControlMgmt::socket_term()
+{
+    delete_controls();
+
+    if (listener >= 0)
+        close(listener);
+
+    listener = -1;
+
+    if (epoll_fd >= 0)
+        close(epoll_fd);
+
+    epoll_fd = -1;
+
+    return 0;
+}
+
+bool ControlMgmt::process_control_commands(int& current_fd, Request*& current_request, int evnt_fd)
+{
+    bool ret = false;
+    auto control_conn = controls.find(evnt_fd);
+
+    if (control_conn == controls.end())
+        return ret;
+
+    Request* old_request = current_request;
+    int fd = control_conn->second->shell_execute(current_fd, current_request);
+    current_fd = -1;
+    current_request = old_request;
+
+    if (fd >= 0)
+    {
+        if (control_conn->second->is_local_control())
+             proc_stats.local_commands++;
+        else
+             proc_stats.remote_commands++;
+        ret = true;
+    }
+    return ret;
+}
+
+bool ControlMgmt::service_users(int& current_fd, Request*& current_request)
+{
+    bool ret = false;
+    vector<epoll_event> events(MAX_EPOLL_EVENTS);
+
+    int event_count = epoll_wait(epoll_fd, events.data(), MAX_EPOLL_EVENTS, 0);
+    for(int i = 0; i < event_count; i++)
+    {
+        ret = process_control_commands(current_fd, current_request, events[i].data.fd);
+
+        if (listener == events[i].data.fd)
+        {
+            // got a new connection request, accept it and store it in controls
+            if( !socket_conn() )
+            {
+                ret = true;
+            }
+        }
+
+        if (!ret && (events[i].events & EPOLLHUP))
+        {
+            delete_control(events[i].data.fd);
+        }
+    }
+    return ret;
+}
+
+#else
+//-------------------------------------------------------------------------
+// select implementation (default)
+//-------------------------------------------------------------------------
+// Default implementation using select() for monitoring multiple fds.
+
 static fd_set inputs;
-static std::vector<ControlConn*> controls;
+static vector<ControlConn*> controls;
 
 void ControlMgmt::add_control(int fd, bool local)
 {
     controls.emplace_back(new ControlConn(fd, local));
 }
 
-bool ControlMgmt::find_control(int fd, std::vector<ControlConn*>::iterator& control)
+bool ControlMgmt::find_control(int fd, vector<ControlConn*>::iterator& control)
 {
-    control = std::find_if(controls.begin(), controls.end(),
+    control = find_if(controls.begin(), controls.end(),
                 [=](const ControlConn* c) { return c->get_fd() == fd; });
 
-    if(control != controls.end())
+    if (control != controls.end())
         return true;
     else
         return false;
@@ -63,13 +257,13 @@ bool ControlMgmt::find_control(int fd, std::vector<ControlConn*>::iterator& cont
 
 ControlConn* ControlMgmt::find_control(int fd)
 {
-    std::vector<ControlConn*>::iterator it;
+    vector<ControlConn*>::iterator it;
 
     ControlConn* control = find_control(fd, it) ? (*it) : nullptr;
     return control;
 }
 
-void ControlMgmt::delete_control(std::vector<ControlConn*>::iterator& control)
+void ControlMgmt::delete_control(vector<ControlConn*>::iterator& control)
 {
     delete *control;
     control = controls.erase(control);
@@ -77,14 +271,14 @@ void ControlMgmt::delete_control(std::vector<ControlConn*>::iterator& control)
 
 void ControlMgmt::delete_control(int fd)
 {
-    std::vector<ControlConn*>::iterator control;
-    if ( find_control(fd, control) )
+    vector<ControlConn*>::iterator control;
+    if (find_control(fd, control))
         delete_control(control);
 }
 
 void ControlMgmt::reconfigure_controls()
 {
-    for ( auto control : controls )
+    for (auto control : controls)
     {
         control->configure();
     }
@@ -92,60 +286,18 @@ void ControlMgmt::reconfigure_controls()
 
 void ControlMgmt::delete_controls()
 {
-    for ( auto control : controls )
+    for (auto control : controls)
     {
         delete control;
     }
     controls.clear();
 }
 
-//-------------------------------------------------------------------------
-// socket foo
-//-------------------------------------------------------------------------
-// FIXIT-M make these non-blocking
-// FIXIT-M bind to configured ip including INADDR_ANY
-// (default is loopback if enabled)
-
-int ControlMgmt::setup_socket_family()
-{
-    int family = AF_UNSPEC;
-    if ( SnortConfig::get_conf()->remote_control_port )
-    {
-        memset(&in_addr, 0, sizeof(in_addr));
-
-        in_addr.sin_family = AF_INET;
-        in_addr.sin_addr.s_addr = htonl(0x7F000001);
-        in_addr.sin_port = htons(SnortConfig::get_conf()->remote_control_port);
-        sock_addr = (struct sockaddr*)&in_addr;
-        sock_addr_size = sizeof(in_addr);
-        family = AF_INET;
-    }
-    else if ( !SnortConfig::get_conf()->remote_control_socket.empty() )
-    {
-        std::string fullpath;
-        const char* path_sep = strrchr(SnortConfig::get_conf()->remote_control_socket.c_str(), '/');
-        if (path_sep != nullptr)
-            fullpath = SnortConfig::get_conf()->remote_control_socket;
-        else
-            get_instance_file(fullpath, SnortConfig::get_conf()->remote_control_socket.c_str());
-
-        memset(&unix_addr, 0, sizeof(unix_addr));
-        unix_addr.sun_family = AF_UNIX;
-        strncpy(unix_addr.sun_path, fullpath.c_str(), sizeof(unix_addr.sun_path)-1);
-        sock_addr = (struct sockaddr*)&unix_addr;
-        sock_addr_size = sizeof(unix_addr);
-        unlink(fullpath.c_str());
-        family = AF_UNIX;
-    }
-
-    return family;
-}
-
 int ControlMgmt::socket_init()
 {
     int sock_family = setup_socket_family();
 
-    if ( sock_family == AF_UNSPEC )
+    if (sock_family == AF_UNSPEC)
         return -1;
 
     listener = socket(sock_family, SOCK_STREAM, 0);
@@ -157,11 +309,11 @@ int ControlMgmt::socket_init()
     int on = 1;
     setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
 
-    if ( ::bind(listener, sock_addr, sock_addr_size) < 0 )
+    if (::bind(listener, sock_addr, sock_addr_size) < 0)
         FatalError("bind failed: %s\n", get_error(errno));
 
     // FIXIT-M configure max conns
-    if ( listen(listener, 0) < 0 )
+    if (listen(listener, 0) < 0)
         FatalError("listen failed: %s\n", get_error(errno));
 
     return 0;
@@ -171,7 +323,7 @@ int ControlMgmt::socket_term()
 {
     delete_controls();
 
-    if ( listener >= 0 )
+    if (listener >= 0)
         close(listener);
 
     listener = -1;
@@ -179,34 +331,21 @@ int ControlMgmt::socket_term()
     return 0;
 }
 
-int ControlMgmt::socket_conn()
-{
-    int remote_control = accept(listener, sock_addr, &sock_addr_size);
-
-    if ( remote_control < 0 )
-        return -1;
-
-    add_control(remote_control, false);
-
-    // FIXIT-L authenticate, use ssl ?
-    return 0;
-}
-
 bool ControlMgmt::process_control_commands(int& current_fd, Request*& current_request)
 {
     bool ret = false;
 
-    for(std::vector<ControlConn*>::iterator control =
+    for (vector<ControlConn*>::iterator control =
             controls.begin(); control != controls.end();)
     {
         int fd = (*control)->get_fd();
-        if ( FD_ISSET(fd, &inputs) )
+        if (FD_ISSET(fd, &inputs))
         {
             Request* old_request = current_request;
             fd = (*control)->shell_execute(current_fd, current_request);
             current_fd = -1;
             current_request = old_request;
-            if( fd < 0 )
+            if (fd < 0)
             {
                 delete_control(control);
                 ret = false;
@@ -214,7 +353,7 @@ bool ControlMgmt::process_control_commands(int& current_fd, Request*& current_re
             }
             else
             {
-                if ( (*control)->is_local_control() )
+                if ((*control)->is_local_control())
                     proc_stats.local_commands++;
                 else
                     proc_stats.remote_commands++;
@@ -232,20 +371,20 @@ bool ControlMgmt::service_users(int& current_fd, Request*& current_request)
     int max_fd = -1;
     bool ret = false;
 
-    for ( auto control : controls )
+    for (auto control : controls)
     {
         int fd = control->get_fd();
-        if ( fd >= 0 and !control->is_blocked() )
+        if (fd >= 0 and !control->is_blocked())
         {
             FD_SET(fd, &inputs);
-            if ( fd > max_fd )
+            if (fd > max_fd)
                 max_fd = fd;
         }
     }
-    if ( listener >= 0 )
+    if (listener >= 0)
     {
         FD_SET(listener, &inputs);
-        if ( listener > max_fd )
+        if (listener > max_fd)
             max_fd = listener;
     }
 
@@ -253,15 +392,15 @@ bool ControlMgmt::service_users(int& current_fd, Request*& current_request)
     timeout.tv_sec = 0;
     timeout.tv_usec = 0;
 
-    if ( select(max_fd+1, &inputs, nullptr, nullptr, &timeout) > 0 )
+    if (select(max_fd+1, &inputs, nullptr, nullptr, &timeout) > 0)
     {
         ret = process_control_commands(current_fd, current_request);
 
-        if ( listener >= 0 )
+        if (listener >= 0)
         {
-            if ( FD_ISSET(listener, &inputs) )
+            if (FD_ISSET(listener, &inputs))
             {
-                if ( !socket_conn() )
+                if (!socket_conn())
                 {
                     ret = true;
                 }
@@ -271,36 +410,59 @@ bool ControlMgmt::service_users(int& current_fd, Request*& current_request)
     return ret;
 }
 
-ACShellCmd::ACShellCmd(int fd, AnalyzerCommand *ac) : ac(ac)
-{
-    assert(ac);
-    ControlConn* control = (fd >= 0)? (ControlMgmt::find_control(fd) ) : nullptr;
-
-    if( control )
-    {
-        control->block();
-        control_fd = fd;
-    }
-}
+#endif
 
-void ACShellCmd::execute(Analyzer& analyzer)
+int ControlMgmt::socket_conn()
 {
-    ControlConn* control = (control_fd >= 0)? (ControlMgmt::find_control(control_fd) ) : nullptr;
+    int remote_control = accept(listener, sock_addr, &sock_addr_size);
+
+    if (remote_control < 0)
+        return -1;
 
-    if( control )
-        control->send_queued_response();
+    add_control(remote_control, false);
 
-    ac->execute(analyzer);
+    // FIXIT-L authenticate, use ssl ?
+    return 0;
 }
 
-ACShellCmd::~ACShellCmd()
+//-------------------------------------------------------------------------
+// socket foo
+//-------------------------------------------------------------------------
+// FIXIT-M make these non-blocking
+// FIXIT-M bind to configured ip including INADDR_ANY
+// (default is loopback if enabled)
+int ControlMgmt::setup_socket_family()
 {
-    delete ac;
-    ControlConn* control = (control_fd >= 0)? (ControlMgmt::find_control(control_fd) ) : nullptr;
+    int family = AF_UNSPEC;
+    if (SnortConfig::get_conf()->remote_control_port)
+    {
+        memset(&in_addr, 0, sizeof(in_addr));
 
-    if( control )
+        in_addr.sin_family = AF_INET;
+        in_addr.sin_addr.s_addr = htonl(0x7F000001);
+        in_addr.sin_port = htons(SnortConfig::get_conf()->remote_control_port);
+        sock_addr = (struct sockaddr*)&in_addr;
+        sock_addr_size = sizeof(in_addr);
+        family = AF_INET;
+    }
+    else if (!SnortConfig::get_conf()->remote_control_socket.empty())
     {
-        control->send_queued_response();
-        control->unblock();
+        string fullpath;
+        const char* path_sep = strrchr(SnortConfig::get_conf()->remote_control_socket.c_str(), '/');
+        if (path_sep != nullptr)
+            fullpath = SnortConfig::get_conf()->remote_control_socket;
+        else
+            get_instance_file(fullpath, SnortConfig::get_conf()->remote_control_socket.c_str());
+
+        memset(&unix_addr, 0, sizeof(unix_addr));
+        unix_addr.sun_family = AF_UNIX;
+        strncpy(unix_addr.sun_path, fullpath.c_str(), sizeof(unix_addr.sun_path)-1);
+        sock_addr = (struct sockaddr*)&unix_addr;
+        sock_addr_size = sizeof(unix_addr);
+        unlink(fullpath.c_str());
+        family = AF_UNIX;
     }
+    return family;
 }
+
+
index c8aa18113f0e2f87af8bccf94495991a1e25860f..08f754cccfbe82c1ea88af3473b0f5ae35b8b7c7 100644 (file)
@@ -16,7 +16,7 @@
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
 // control_mgmt.h author Bhagya Tholpady <bbantwal@cisco.com>
-//
+//                author Devendra Dahiphale <ddahipha@cisco.com>
 // This provides functions to create and control remote/local connections,
 // socket creation/deletion/management functions, and shell commands used by the analyzer.
 
 
 #include <vector>
 
-#include "main/analyzer.h"
-#include "main/analyzer_command.h"
-#include "main/snort_types.h"
-#include "utils/util.h"
-
 class ControlConn;
 
 class ControlMgmt
 {
 public:
     static void add_control(int fd, bool local_control);
-    static void delete_control(int fd);
-    static void delete_controls();
-    static ControlConn* find_control(int fd);
     static void reconfigure_controls();
 
-    static bool find_control(int fd, std::vector<ControlConn*>::iterator& control);
-    static void delete_control(std::vector<ControlConn*>::iterator& control);
-
     static int socket_init();
     static int socket_term();
     static int socket_conn();
 
+    static bool process_control_commands(int& current_fd, class Request*& current_request, int);
     static bool process_control_commands(int& current_fd, class Request*& current_request);
+
+    static ControlConn* find_control(int fd);
+    static bool find_control(int fd, std::vector<ControlConn*>::iterator& control);
+
+    static void delete_controls();
+    static void delete_control(int fd);
+    static void delete_control(std::vector<ControlConn*>::iterator& control);
+
     static bool service_users(int& current_fd, class Request*& current_request);
-private:
-    static int setup_socket_family();
-};
 
-class ACShellCmd : public AnalyzerCommand
-{
-public:
-    ACShellCmd() = delete;
-    ACShellCmd(int fd, AnalyzerCommand* ac_cmd);
-    void execute(Analyzer&) override;
-    const char* stringify() override { return ac->stringify(); }
-    ~ACShellCmd() override;
 private:
-    int control_fd = -1;
-    AnalyzerCommand* ac;
+    static int setup_socket_family();
 };
-
 #endif
index c07e01a620cf80df7eda13eb83cd4444ea387960..3e43d7707bd2bd4a6ea2cac79538e554858e4c9b 100644 (file)
@@ -96,6 +96,7 @@
 #endif
 
 #ifdef SHELL
+#include "ac_shell_cmd.h"
 #include "control_mgmt.h"
 #endif