]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #495 in SNORT/snort3 from ha-sc to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Tue, 7 Jun 2016 10:44:57 +0000 (06:44 -0400)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Tue, 7 Jun 2016 10:44:57 +0000 (06:44 -0400)
Squashed commit of the following:

commit 430c1bd63459e8d2815c0d532af12278d865a07a
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Mon Jun 6 11:34:27 2016 -0400

    Added stub for snort_strdup()

commit b0d605d273a4444c22a681aa675a31ef39bc09c4
Merge: 43a60e0 6641e05
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Mon Jun 6 11:16:13 2016 -0400

    Merge branch 'ha-sc' of https://bitbucket-eng-rtp1.cisco.com/bitbucket/scm/snort/snort3 into ha-sc

commit 6641e058727b4dad60b7e7fb476868df3dfb4f3a
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Tue May 31 15:12:25 2016 -0400

    Fix problem with udp_ha.

commit d58771e037cc54905f5244534d3c0f0d1c3fddb9
Merge: 518749e dc34515
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Thu May 26 07:47:39 2016 -0400

    Merge branch 'ha-sc' of https://bitbucket-eng-rtp1.cisco.com/bitbucket/scm/snort/snort3 into ha-sc

commit 518749e07afe7a3532c223c70faa5001f024cc24
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Wed May 25 16:21:55 2016 -0400

    Additional HA UT's and additional stream HA capabiity.

commit dc3451510b5d261c1188a7d57f98b42c18ddd20b
Merge: 022b844 5e0a5bb
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Wed May 25 16:23:59 2016 -0400

    Merge branch 'ha-sc' of https://bitbucket-eng-rtp1.cisco.com/bitbucket/scm/snort/snort3 into ha-sc

    Conflicts:
     src/flow/ha.cc

commit 022b8440807ae03c857307e1ce252253a7e4d45b
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Wed May 25 16:21:55 2016 -0400

    Additional HA UT's and additional stream HA capabiity.

commit 5e0a5bb14097eb2a3d1ab4e53c7335585afb1699
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Thu May 19 10:36:05 2016 -0400

    Fix a memory leak in the Flow object regarding the ha_state.

commit 02bc6738393e253473f57c6b1367e0fd982ac033
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Wed May 18 09:15:29 2016 -0400

    Fix mem leak issue in UT.

commit d44d4c3631b90a7a136810ac137033d8fe72115e
Merge: 9a643a8 b2f8cf7
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Wed May 18 07:57:29 2016 -0400

    Merge branch 'ha-sc' of https://bitbucket-eng-rtp1.cisco.com/bitbucket/scm/snort/snort3

commit b2f8cf7996253e13761d0ec773400a41e14c4b47
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Tue May 17 15:02:59 2016 -0400

    A few small code review fixes.

commit b903d32fe80c4a4f19e80145a420696716cdd535
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Fri May 6 10:07:21 2016 -0400

    Fix a compile warning.

commit bfbd5abccc7a79b3283430a3307ae3402517953d
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Fri May 6 09:28:29 2016 -0400

    Forgot to add the file_connector_module_test to cmake

commit a99fb124eeae1e6d52f40a6217cbe61f4ada4a00
Merge: 08612c6 fe16e75
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Thu May 5 14:10:32 2016 -0400

    Merge branch 'ha-sc' of https://bitbucket-eng-rtp1.cisco.com/bitbucket/scm/snort/snort3 into ha-sc

commit 08612c66de9c1750015fcbd1033661931bcda05e
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Thu May 5 14:08:35 2016 -0400

    UT's for file_connector.

commit 2c5d4c13e44a644572e012e593e72ebe3d2b2b59
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Wed May 4 10:07:52 2016 -0400

    Fixed test stubs to eliminate memory leaks.

commit cc50492ed3d0f1ef5ded6ffcf3bedc238f7e9e4b
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Tue May 3 15:06:02 2016 -0400

    Makefile.am cosmetic changes.

commit 03ff7b57fde7dd0ac747ed2f04707aefed0e6da9
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Tue May 3 13:00:14 2016 -0400

    Remove extraneous stuff.

commit 6b73c2c7ec76339f974875a6aa0f41825f70ea5d
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Tue May 3 10:53:29 2016 -0400

    Additional UT's for side_channel.

commit fe16e7515225e59e75c6a975262d99260a1235b1
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Wed May 4 10:07:52 2016 -0400

    Fixed test stubs to eliminate memory leaks.

commit 67dec135d68701f4e12e4eeb94a6b8d86ac85afb
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Tue May 3 15:06:02 2016 -0400

    Makefile.am cosmetic changes.

commit b83d121adaed4f6118b14319f6ce2d0dfc46d4f6
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Tue May 3 13:00:14 2016 -0400

    Remove extraneous stuff.

commit 0f903af76892e136b3a86ff538f8bbd5858ba0a6
Author: Ed Borgoyn <eborgoyn@cisco.com>
Date:   Tue May 3 10:53:29 2016 -0400

    Additional UT's for side_channel.

src/flow/ha.cc
src/flow/ha.h
src/flow/test/CMakeLists.txt
src/flow/test/Makefile.am
src/flow/test/ha_module_test.cc [new file with mode: 0644]
src/flow/test/ha_test.cc
src/main/snort.cc
src/stream/base/stream_ha.cc
src/stream/base/stream_ha.h
src/stream/udp/udp_ha.cc
src/stream/udp/udp_ha.h

index 63551787037b118d5a9456467fd59ca46349fb9c..da3730d00b45b90f7f919260ac693ed26ca15386 100644 (file)
@@ -26,6 +26,7 @@
 #include "flow.h"
 #include "flow_key.h"
 #include "ha_module.h"
+#include "log/messages.h"
 #include "main/snort_debug.h"
 #include "packet_io/sfdaq.h"
 #include "profiler/profiler.h"
@@ -48,7 +49,7 @@ enum
     KEY_TYPE_IP4 = 2
 };
 
-typedef std::unordered_map<FlowHAClientHandle, FlowHAClient*> ClientMap;
+typedef std::array<FlowHAClient*, MAX_CLIENTS> ClientMap;
 
 THREAD_LOCAL SimpleStats ha_stats;
 THREAD_LOCAL ProfileStats ha_perf_stats;
@@ -57,10 +58,11 @@ static THREAD_LOCAL HighAvailability* ha;
 PortBitSet* HighAvailabilityManager::ports = nullptr;
 bool HighAvailabilityManager::use_daq_channel = false;
 struct timeval FlowHAState::min_session_lifetime;
-uint8_t FlowHAClient::s_handle_counter = 0;
+uint8_t s_handle_counter = 1; // stream client (index == 0) always exists
 
-static THREAD_LOCAL ClientMap* client_map;
-static THREAD_LOCAL FlowHAClient* s_session_client;
+// The [0] entry contains the stream client (always present)
+// Entries [1] to [MAX_CLIENTS-1] contain the optional clients
+static THREAD_LOCAL ClientMap* s_client_map;
 
 static inline bool is_ip6_key(const FlowKey* key)
 {
@@ -164,22 +166,52 @@ void FlowHAState::reset()
     pending = NONE_PENDING;
 }
 
-FlowHAClient::FlowHAClient(bool session_client)
+FlowHAClient::FlowHAClient(uint8_t length, bool session_client)
 {
     DebugMessage(DEBUG_HA,"FlowHAClient::FlowHAClient()\n");
+    if ( !s_client_map )
+        return;
+
+    header.length = length;
+
     if ( session_client )
     {
         handle = SESSION_HA_CLIENT;
-        s_session_client = this;
+        header.client = SESSION_HA_CLIENT_INDEX;
+        (*s_client_map)[0] = this;
     }
     else
     {
-        assert(s_handle_counter != MAX_CLIENTS);
-        handle = (1 << s_handle_counter);
+        if ( s_handle_counter >= MAX_CLIENTS )
+        {
+            ErrorMessage("Attempting to register too many FlowHAClients\n");
+            return;
+        }
+
+        header.client = s_handle_counter;
+        handle = (1 << (s_handle_counter-1));
+        (*s_client_map)[s_handle_counter] = this;
         s_handle_counter += 1;
     }
 }
 
+bool FlowHAClient::fit(HAMessage* msg, uint8_t size)
+{
+    return ( (int)(msg->cursor - msg->content()) < (int)(msg->content_length() - size) );
+}
+
+bool FlowHAClient::place(HAMessage* msg, uint8_t* data, uint8_t length)
+{
+    if ( fit(msg, length) )
+    {
+        memcpy(msg->cursor,data,(size_t)length);
+        msg->cursor += length;
+        return true;
+    }
+    else
+        return false;
+}
+
 // Write the key type, key length, and key into the message.
 // Does not use the message cursor coming in.
 // Leave the message cursor just after the key. Return
@@ -195,7 +227,7 @@ static uint8_t write_flow_key(Flow* flow, HAMessage* msg)
     {
         hdr->key_type = KEY_TYPE_IP6;
         memcpy(msg->cursor, key, KEY_SIZE_IP6);
-        msg->cursor = (uint8_t*)hdr + KEY_SIZE_IP6;
+        msg->cursor += KEY_SIZE_IP6;
         return KEY_SIZE_IP6;
     }
     else
@@ -262,15 +294,17 @@ static uint16_t calculate_msg_header_length(Flow* flow)
 // set of active clients.  The Session client is always present.
 static uint16_t calculate_update_msg_content_length(Flow* flow)
 {
-    uint16_t length = s_session_client->get_message_size();
+    assert(s_client_map);
+    assert((*s_client_map)[0]);
+    uint16_t length = ((*s_client_map)[0]->get_message_size() + sizeof(HAClientHeader));
     DebugFormat(DEBUG_HA,"HighAvailability::calculate_update_msg_content_length(): length: %d\n",
         length);
 
-    // Iterating through the hash map is OK to determine length.
-    for (auto& iter : * client_map )
-        if ( flow->ha_state->check_pending(iter.first) )
+    for (int i=1; i<s_handle_counter; i++)
+        if ( flow->ha_state->check_pending(1<<i) )
         {
-            length += iter.second->get_message_size();
+            assert((*s_client_map)[i]);
+            length += ((*s_client_map)[i]->get_message_size() + sizeof(HAClientHeader));
             DebugFormat(DEBUG_HA,
                 "HighAvailability::calculate_update_msg_content_length(): length: %d\n", length);
         }
@@ -289,19 +323,22 @@ static void write_msg_header(Flow* flow, HAEvent event, uint16_t content_length,
     write_flow_key(flow, msg);  // set cursor to just beyond key
 }
 
-static void write_update_msg_content(Flow* flow, HAMessage* msg)
+static void write_update_msg_client( FlowHAClient* client, Flow* flow, HAMessage* msg)
 {
-    //  Always have the session portion
-    s_session_client->produce(flow,msg);
+    assert(client);
+    assert(msg);
 
-    // Since I'm not sure that the hash map is deterministic, I'll
-    // step through the clients in order
-    for ( int i=0; i<FlowHAClient::s_handle_counter; i++ )
-    {
-        FlowHAClientHandle handle = 1<<i;
-        if ( flow->ha_state->check_pending(handle) )
-            client_map->find(handle)->second->produce(flow,msg);
-    }
+    client->place(msg,(uint8_t*)&(client->header),(uint8_t)sizeof(client->header));
+    client->produce(flow, msg);
+}
+
+static void write_update_msg_content(Flow* flow, HAMessage* msg)
+{
+    assert(s_client_map);
+    
+    for ( int i=0; i<s_handle_counter; i++ )
+        if ( (i==SESSION_HA_CLIENT_INDEX) || flow->ha_state->check_pending(1<<i) )
+            write_update_msg_client((*s_client_map)[i],flow, msg);
 }
 
 static void consume_receive_delete_message(HAMessage* msg)
@@ -318,11 +355,42 @@ static void consume_receive_update_message(HAMessage* msg)
     // flow will be nullptr if/when the session does not exist in the caches
     Flow* flow = stream.get_session(&key);
 
-    assert(s_session_client);
+    assert(s_client_map);
 
-    // Update messages MUST include the session client component
-    if ( !s_session_client->consume(flow,msg) )
-        return;
+    // pointer to the last byte in the message
+    uint8_t* content_end = msg->content() + msg->content_length() - 1;
+
+    while( msg->cursor <= content_end )
+    {
+        // do we have sufficient message left to be able to have an HAClientHeader?
+        if ( (int)(content_end - msg->cursor) < (int)sizeof( HAClientHeader ) )
+        {
+            ErrorMessage("Consuming HA Update message - no HAClientHeader\n");
+            break;
+        }
+
+        HAClientHeader* header = (HAClientHeader*)msg->cursor;
+        msg->cursor += sizeof( HAClientHeader ); // step to the client content
+
+        if ( (header->client >= s_handle_counter) ||
+            ((*s_client_map)[header->client] == nullptr)  )
+        {
+            ErrorMessage("Consuming HA Update message - invalid client index\n");
+            break;
+        }
+
+        if ( (content_end - msg->cursor) < header->length )
+        {
+            ErrorMessage("Consuming HA Update memssage - message too short\n");
+            break;
+        }
+
+        if ( !(*s_client_map)[header->client]->consume(flow,msg) )
+        {
+            ErrorMessage("Consuming HA Update message - error from client consume()\n");
+            break;
+        }
+    }
 }
 
 static void consume_receive_message(HAMessage* msg)
@@ -377,7 +445,9 @@ HighAvailability::HighAvailability(PortBitSet* ports, bool)
                 break;
             }
 
-    client_map = new ClientMap;
+    s_client_map = new ClientMap;
+    for ( int i=0; i<MAX_CLIENTS; i++ )
+        (*s_client_map)[i] = nullptr;
 
     // Only looking for side channel processing - FIXIT-H
 }
@@ -391,7 +461,7 @@ HighAvailability::~HighAvailability()
         sc->unregister_receive_handler();
     }
 
-    delete client_map;
+    delete s_client_map;
 }
 
 void HighAvailability::receive_handler(SCMessage* sc_msg)
index 1eba398833d900c07f5b691cc8cb9b005e3e6ec2..d99a8c905f7ada5f11b622a6e2b34804caf42f90 100644 (file)
@@ -34,8 +34,12 @@ class Flow;
 // NOTE: The type, masks, and count values must be in sync,
 typedef uint16_t FlowHAClientHandle;
 const FlowHAClientHandle SESSION_HA_CLIENT = 0x0000;
+const uint8_t SESSION_HA_CLIENT_INDEX = 0;
 const FlowHAClientHandle ALL_CLIENTS = 0xffff;
-const uint8_t MAX_CLIENTS = 16;
+// One client for each mask bit plus one 'automatic' session client
+//   client handle = (1<<(client_index-1)
+//   session client has handle of 0 and index of 0
+const uint8_t MAX_CLIENTS = 17;
 
 enum HAEvent
 {
@@ -125,12 +129,15 @@ public:
     virtual ~FlowHAClient() { }
     virtual bool consume(Flow*, HAMessage*) { return false; }
     virtual bool produce(Flow*, HAMessage*) { return false; }
-    virtual size_t get_message_size() { return 0; }
+    uint8_t get_message_size() { return header.length; }
+    bool fit(HAMessage*, uint8_t);
+    bool place(HAMessage*, uint8_t*, uint8_t);
     FlowHAClientHandle handle;  // Actual handle for the instance
-    static uint8_t s_handle_counter; // next handle to be assigned
+    HAClientHeader header;
 
 protected:
-    FlowHAClient(bool); // Arg == true for session client
+    FlowHAClient(uint8_t, bool);
+
 };
 
 // HighAvailability is instantiated for each packet-thread.
index f0765dba2b8eac186155d2b2cdc7a7563876c13e..1e23da9a7de6d8b2ef0bc09d370b7f8bd59cd9d6 100644 (file)
@@ -1,2 +1,3 @@
-add_cpputest(ha_test flow)
+add_cpputest(ha_test ha)
+add_cpputest(ha_module_ha ha_module)
 
index 251347a5a7037eec7b9c2143c5be883a60678be4..3a529e2763dbf74d4d7f62886803cbac687bbd0b 100644 (file)
@@ -2,11 +2,22 @@
 AM_DEFAULT_SOURCE_EXT = .cc
 
 check_PROGRAMS = \
-ha_test
+ha_test \
+ha_module_test
 
 TESTS = $(check_PROGRAMS)
 
 ha_test_CPPFLAGS = @AM_CPPFLAGS@ @CPPUTEST_CPPFLAGS@
+ha_module_test_CPPFLAGS = @AM_CPPFLAGS@ @CPPUTEST_CPPFLAGS@
 
-ha_test_LDADD = ../libflow.a @CPPUTEST_LDFLAGS@
+ha_test_LDADD = \
+../ha.o \
+@CPPUTEST_LDFLAGS@
+
+ha_module_test_LDADD = \
+../ha_module.o \
+../../framework/libframework.a \
+../../sfip/libsfip.a \
+../../catch/libcatch_tests.a \
+@CPPUTEST_LDFLAGS@
 
diff --git a/src/flow/test/ha_module_test.cc b/src/flow/test/ha_module_test.cc
new file mode 100644 (file)
index 0000000..3e01caf
--- /dev/null
@@ -0,0 +1,164 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2016 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.
+//--------------------------------------------------------------------------
+
+// ha_module_test.cc author Ed Borgoyn <eborgoyn@cisco.com>
+// unit test main
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+
+#include "flow/ha.h"
+#include "flow/ha_module.h"
+
+#include "log/messages.h"
+#include "main/snort_debug.h"
+#include "profiler/profiler.h"
+
+void LogMessage(const char*,...) { }
+
+THREAD_LOCAL SimpleStats ha_stats;
+THREAD_LOCAL ProfileStats ha_perf_stats;
+
+void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { }
+void show_stats(PegCount*, const PegInfo*, IndexVec&, const char*) { }
+void show_stats(PegCount*, const PegInfo*, IndexVec&, const char*, FILE*) { }
+
+void ParseWarning(WarningGroup, const char*, ...) { }
+
+char* snort_strdup(const char* str) { return strdup(str); }
+
+void Debug::print(const char*, int, uint64_t, const char*, ...) { }
+
+static bool s_port_1_set = false;
+static bool s_use_daq = false;
+static bool s_instantiate_called = false;
+
+static char* make_bit_string(int bit)
+{
+    static char bit_string[65537];
+    for ( int i=0; i<65536; i++)
+        bit_string[i] = (bit == i) ? '1' : '0';
+
+    bit_string[65536] = '\0';
+
+    return bit_string;
+}
+
+bool HighAvailabilityManager::instantiate(PortBitSet* mod_ports, bool mod_use_daq_channel)
+{
+    s_instantiate_called = true;
+    s_port_1_set = mod_ports->test(1);
+    s_use_daq = mod_use_daq_channel;
+
+    return true;
+}
+
+TEST_GROUP(high_availability_module_test)
+{
+    void setup()
+    {
+    }
+
+    void teardown()
+    {
+    }
+};
+
+TEST(high_availability_module_test, test_ha_valid)
+{
+    Value ports_val(make_bit_string(1));
+    Value enable_val(true);
+    Parameter ports_param = {"ports", Parameter::PT_BIT_LIST, "65535", nullptr, "ports"};
+    Parameter enable_param = {"enable", Parameter::PT_BOOL, nullptr, "false", nullptr };
+
+    HighAvailabilityModule module;
+
+    ports_val.set(&ports_param);
+    enable_val.set(&enable_param);
+
+    s_instantiate_called = false;
+    s_port_1_set = false;
+    s_use_daq = false;
+
+    module.begin("high_availability", 0, nullptr);
+    module.set("high_availability.ports", ports_val, nullptr);
+    module.set("high_availability.enable", enable_val, nullptr);
+    module.end("high_availability", 0, nullptr);
+
+    CHECK(s_instantiate_called == true);
+    CHECK(s_port_1_set == true);
+    CHECK(s_use_daq == false);
+}
+
+TEST(high_availability_module_test, test_ha_disabled)
+{
+    Value enable_val(false);
+    Parameter enable_param = {"enable", Parameter::PT_BOOL, nullptr, "false", nullptr };
+
+    HighAvailabilityModule module;
+
+    enable_val.set(&enable_param);
+
+    s_instantiate_called = false;
+    s_port_1_set = false;
+    s_use_daq = false;
+
+    module.begin("high_availability", 0, nullptr);
+    module.set("high_availability.enable", enable_val, nullptr);
+    module.end("high_availability", 0, nullptr);
+
+    CHECK(s_instantiate_called == false);
+    CHECK(s_port_1_set == false);
+    CHECK(s_use_daq == false);
+}
+
+TEST(high_availability_module_test, test_ha_valid_daq)
+{
+    Value ports_val(make_bit_string(1));
+    Value enable_val(true);
+    Value daq_val(true);
+    Parameter ports_param = {"ports", Parameter::PT_BIT_LIST, "65535", nullptr, "ports"};
+    Parameter enable_param = {"enable", Parameter::PT_BOOL, nullptr, "false", nullptr };
+    Parameter daq_param = {"daq_channel", Parameter::PT_BOOL, nullptr, "false", nullptr };
+
+    HighAvailabilityModule module;
+
+    ports_val.set(&ports_param);
+    enable_val.set(&enable_param);
+    daq_val.set(&daq_param);
+
+    s_instantiate_called = false;
+    s_port_1_set = false;
+    s_use_daq = false;
+
+    module.begin("high_availability", 0, nullptr);
+    module.set("high_availability.ports", ports_val, nullptr);
+    module.set("high_availability.enable", enable_val, nullptr);
+    module.set("high_availability.daq_channel", daq_val, nullptr);
+    module.end("high_availability", 0, nullptr);
+
+    CHECK(s_instantiate_called == true);
+    CHECK(s_port_1_set == true);
+    CHECK(s_use_daq == true);
+}
+
+int main(int argc, char** argv)
+{
+    return CommandLineTestRunner::RunAllTests(argc, argv);
+}
+
index 8fe22bd97f2ba9351a9752024f85a2c8a00a0811..7112c611d0df58ff2c319fee6927c5f32620fd20 100644 (file)
 #include "stream/stream_api.h"
 
 #define MSG_SIZE 100
+#define TEST_KEY 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47
+
+class StreamHAClient;
+
+static const uint8_t s_test_key[] =
+{
+TEST_KEY
+};
+
+static const uint8_t s_delete_message[] =
+{
+    0x01,
+    0x03,
+    0x00,
+    0x00,
+    0x01,
+TEST_KEY
+};
+
+
+static struct timeval s_time = { 0, 0 };
+static uint8_t s_message[MSG_SIZE];
+static SideChannel s_side_channel;
+static SCMessage s_sc_message;
+static SCMessage s_rec_sc_message;
+static bool s_get_session_called = false;
+static bool s_delete_session_called = false;
+static bool s_transmit_message_called = false;
+static uint8_t* s_message_content = nullptr;
+static uint8_t s_message_length = 0;
+static Flow s_flow;
+static FlowKey s_flowkey;
+static DAQ_PktHdr_t s_pkthdr;
+static StreamHAClient* ha_client;
+static std::function<void (SCMessage*)> s_handler = nullptr;
+static SCMsgHdr s_sc_header = { 0, 1, 0, 0, };
 
 class StreamHAClient : public FlowHAClient
 {
 public:
-    StreamHAClient() : FlowHAClient(true) { }
+    StreamHAClient() : FlowHAClient(10, true) { }
     ~StreamHAClient() { }
     bool consume(Flow*, HAMessage*) { return true; }
     bool produce(Flow*, HAMessage* msg)
@@ -42,22 +78,25 @@ public:
             *(msg->cursor)++ = i;
         return true;
     }
-    size_t get_message_size() { return 10; }
+    uint8_t get_message_size() { return 10; }
 
 private:
 };
 
-static struct timeval s_time = { 0, 0 };
-static uint8_t message[MSG_SIZE];
-static SideChannel s_side_channel;
-static SCMessage s_sc_message;
-static Flow s_flow;
-static DAQ_PktHdr_t s_pkthdr;
-
-Flow*  Stream::get_session(const FlowKey*) { return &s_flow; }
+Flow*  Stream::get_session(const FlowKey* flowkey)
+{
+    s_flowkey = *flowkey;
+    s_get_session_called = true;
+    return &s_flow;
+}
 
-void Stream::delete_session(const FlowKey*) { }
+void Stream::delete_session(const FlowKey* flowkey)
+{
+    s_flowkey = *flowkey;
+    s_delete_session_called = true;
+}
 
+void ErrorMessage(const char*,...) { }
 void LogMessage(const char*,...) { }
 
 void Debug::print(const char*, int, uint64_t, const char*, ...) { }
@@ -80,7 +119,10 @@ Connector::Direction SideChannel::get_direction()
 
 void SideChannel::set_default_port(SCPort) { }
 
-void SideChannel::register_receive_handler(std::function<void (SCMessage*)>) { }
+void SideChannel::register_receive_handler(std::function<void (SCMessage*)> handler)
+{
+    s_handler = handler;
+}
 
 void SideChannel::unregister_receive_handler() { }
 
@@ -88,40 +130,50 @@ bool SideChannel::discard_message(SCMessage*)
 { return true; }
 
 bool SideChannel::process(int)
-{ return false; }
+{
+    if ( s_handler && s_message_content && (s_message_length != 0))
+    {
+        s_rec_sc_message.content = s_message_content;
+        s_rec_sc_message.content_length = s_message_length;
+        s_rec_sc_message.hdr = &s_sc_header;
+        s_rec_sc_message.sc = &s_side_channel;
+        s_handler(&s_rec_sc_message);
+        return true;
+    }
+    else
+        return false;
+}
 
-bool SideChannel::transmit_message(SCMessage*)
-{ return true; }
+bool SideChannel::transmit_message(SCMessage* msg)
+{
+    s_transmit_message_called = true;
+    s_message_content = msg->content;
+    s_message_length = msg->content_length;
+    return true; }
 
 SCMessage* SideChannel::alloc_transmit_message(uint32_t len)
 {
     if ( len > MSG_SIZE )
         return nullptr;
 
-    s_sc_message.content = message;
+    s_sc_message.content = s_message;
     s_sc_message.content_length = len;
     return &s_sc_message;
 }
 
 TEST_GROUP(high_availability_manager_test)
 {
-    StreamHAClient* ha_client;
     void setup()
     {
-        ha_client = new StreamHAClient;
+        MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
     }
 
     void teardown()
     {
-        delete ha_client;
+        MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();
     }
 };
 
-TEST(high_availability_manager_test, pre_config_init)
-{
-    HighAvailabilityManager::pre_config_init();
-}
-
 TEST(high_availability_manager_test, init_term)
 {
     HighAvailabilityManager::pre_config_init();
@@ -138,35 +190,9 @@ TEST(high_availability_manager_test, inst_init_term)
     port_set.set(1);
     HighAvailabilityManager::instantiate(&port_set, false);
     HighAvailabilityManager::thread_init();
+    ha_client = new StreamHAClient;
     CHECK(HighAvailabilityManager::active()==true);
-    HighAvailabilityManager::thread_term();
-    CHECK(HighAvailabilityManager::active()==false);
-}
-
-TEST(high_availability_manager_test, inst_init_deletion_term)
-{
-    HighAvailabilityManager::pre_config_init();
-    PortBitSet port_set;
-    port_set.set(1);
-    HighAvailabilityManager::instantiate(&port_set, false);
-    HighAvailabilityManager::thread_init();
-    CHECK(HighAvailabilityManager::active()==true);
-    HighAvailabilityManager::process_receive();
-    HighAvailabilityManager::process_deletion(&s_flow);
-    HighAvailabilityManager::thread_term();
-    CHECK(HighAvailabilityManager::active()==false);
-}
-
-TEST(high_availability_manager_test, inst_init_update_term)
-{
-    HighAvailabilityManager::pre_config_init();
-    PortBitSet port_set;
-    port_set.set(1);
-    HighAvailabilityManager::instantiate(&port_set, false);
-    HighAvailabilityManager::thread_init();
-    CHECK(HighAvailabilityManager::active()==true);
-    HighAvailabilityManager::process_update(&s_flow, &s_pkthdr);
-    HighAvailabilityManager::process_receive();
+    delete ha_client;
     HighAvailabilityManager::thread_term();
     CHECK(HighAvailabilityManager::active()==false);
 }
@@ -175,19 +201,47 @@ TEST_GROUP(high_availability_test)
 {
     void setup()
     {
+        MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
         HighAvailabilityManager::pre_config_init();
         PortBitSet port_set;
         port_set.set(1);
         HighAvailabilityManager::instantiate(&port_set, false);
         HighAvailabilityManager::thread_init();
+        ha_client = new StreamHAClient;
     }
 
     void teardown()
     {
+        delete ha_client;
         HighAvailabilityManager::thread_term();
+        MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();
     }
 };
 
+TEST(high_availability_test, receive_deletion)
+{
+    s_delete_session_called = false;
+    s_message_content = (uint8_t*)s_delete_message;
+    s_message_length = sizeof(s_delete_message);
+    HighAvailabilityManager::process_receive();
+    CHECK(s_delete_session_called == true);
+    CHECK(memcmp((const void*)&s_flowkey, (const void*)&s_test_key, sizeof(s_test_key)) == 0);
+}
+
+TEST(high_availability_test, transmit_deletion)
+{
+    s_transmit_message_called = false;
+    HighAvailabilityManager::process_deletion(&s_flow);
+    CHECK(s_transmit_message_called == true);
+}
+
+TEST(high_availability_test, transmit_update_stream_only)
+{
+    s_transmit_message_called = false;
+    HighAvailabilityManager::process_update(&s_flow, &s_pkthdr);
+    CHECK(s_transmit_message_called == true);
+}
+
 int main(int argc, char** argv)
 {
     return CommandLineTestRunner::RunAllTests(argc, argv);
index 03ad8806e7ffa51536afa46e2ed135429ce1bc0e..030e013d0e144d885ae7b02d748347f33d6ed023 100644 (file)
@@ -646,9 +646,9 @@ void Snort::thread_init_unprivileged()
     EventManager::open_outputs();
     IpsManager::setup_options();
     ActionManager::thread_init(snort_conf);
-    InspectorManager::thread_init(snort_conf);
     SideChannelManager::thread_init();
-    HighAvailabilityManager::thread_init();
+    HighAvailabilityManager::thread_init(); // must be before InspectorManager::thread_init();
+    InspectorManager::thread_init(snort_conf);
 }
 
 void Snort::thread_term()
index b43cf1b569118783edfc9bd6efc3ebc066dc190f..f0ef7562617f74ac3d911fc48326124b6a1f4b16 100644 (file)
@@ -56,16 +56,18 @@ void ProtocolHA::process_deletion(Flow* flow)
     HighAvailabilityManager::process_deletion(flow);
 }
 
-THREAD_LOCAL StreamHAClient* StreamHAManager::ha_client;
+THREAD_LOCAL StreamHAClient* StreamHAManager::ha_client = nullptr;
 
 void StreamHAManager::tinit()
 {
-    ha_client = new StreamHAClient();
+    if ( HighAvailabilityManager::active() )
+        ha_client = new StreamHAClient();
 }
 
 void StreamHAManager::tterm()
 {
-    delete ha_client;
+    if ( ha_client )
+        delete ha_client;
 }
 
 void StreamHAManager::process_deletion(Flow*)
index 6bc7ae35fb994bd141b56de6e662ff274a143770..7b1f78b96f778f69cdb34efcf65083d36c575202 100644 (file)
 class StreamHAClient : public FlowHAClient
 {
 public:
-    StreamHAClient() : FlowHAClient(true) { }
+    StreamHAClient() : FlowHAClient(sizeof(LwState), true) { }
     bool consume(Flow*, HAMessage*);
     bool produce(Flow*, HAMessage*);
-    size_t get_message_size()
-    { return sizeof(LwState); }
 
 private:
 };
index 66227886e12bfc8e90c4a38e88e07504b6b2451a..91966f12f8c668bbcc93bca7ce2d20cae632e769 100644 (file)
@@ -31,15 +31,25 @@ void UdpHA::create_session(Flow*)
     DebugMessage(DEBUG_HA,"UdpHA::create_session)\n");
 }
 
-THREAD_LOCAL UdpHA* UdpHAManager::udp_ha;
+THREAD_LOCAL UdpHA* UdpHAManager::udp_ha = nullptr;
+
+void UdpHAManager::process_deletion(Flow* flow)
+{
+    if( udp_ha != nullptr )
+        udp_ha->process_deletion(flow);
+}
 
 void UdpHAManager::tinit()
 {
-    udp_ha = new UdpHA();
+    if ( HighAvailabilityManager::active() )
+        udp_ha = new UdpHA();
+    else
+        udp_ha = nullptr;
 }
 
 void UdpHAManager::tterm()
 {
-    delete udp_ha;
+    if ( udp_ha )
+        delete udp_ha;
 }
 
index 4f69d29c8783a4a7abdad36d01222ef5d2fbd693..bcfdfb9c091c9ff770dca3730d520fe778934d15 100644 (file)
@@ -40,8 +40,7 @@ private:
 class UdpHAManager
 {
 public:
-    static void process_deletion(Flow* flow)
-    { udp_ha->process_deletion(flow); }
+    static void process_deletion(Flow* flow);
     static void tinit();
     static void tterm();
     static THREAD_LOCAL UdpHA* udp_ha;