1966 lines
68 KiB
Diff
1966 lines
68 KiB
Diff
From: https://github.com/codership/galera/commits/4.x-26.4.16-gh-558
|
|
Forwarded: https://github.com/codership/galera/pull/588
|
|
From cb4437f7f4b30ff1d3394fa10fa1e4168b47b61c Mon Sep 17 00:00:00 2001
|
|
Author: Teemu Ollakka <teemu.ollakka@galeracluster.com>
|
|
Date: Mon, 2 Oct 2023 14:48:06 +0300
|
|
Subject: [PATCH 1/8] Add CMake option to compile with UBSAN instrumentation
|
|
|
|
CMake option -DGALERA_WITH_UBSAN:BOOL=ON enables UBSAN
|
|
instrumentation for the build.
|
|
---
|
|
cmake/asan.cmake | 6 ++++++
|
|
1 file changed, 6 insertions(+)
|
|
|
|
--- a/cmake/asan.cmake
|
|
+++ b/cmake/asan.cmake
|
|
@@ -1,5 +1,5 @@
|
|
#
|
|
-# Copyright (C) 2020 Codership Oy <info@codership.com>
|
|
+# Copyright (C) 2020-2023 Codership Oy <info@codership.com>
|
|
#
|
|
|
|
if (GALERA_WITH_ASAN)
|
|
@@ -7,3 +7,21 @@ if (GALERA_WITH_ASAN)
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
|
add_definitions(-DGALERA_WITH_ASAN)
|
|
endif()
|
|
+
|
|
+if (GALERA_WITH_UBSAN)
|
|
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined")
|
|
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
|
|
+ add_definitions(-DGALERA_WITH_UBSAN)
|
|
+ # don't run unit tests that use outdaed unaligned record set format
|
|
+ add_definitions(-DGALERA_ONLY_ALIGNED)
|
|
+
|
|
+ find_library(UBSAN_LIB NAMES ubsan libubsan.so.1)
|
|
+ message(STATUS ${UBSAN_LIB})
|
|
+ set(CMAKE_REQUIRED_LIBRARIES ${UBSAN_LIB})
|
|
+ check_c_source_compiles("int main() { return 0; }" GALERA_HAVE_UBSAN_LIB)
|
|
+ if (NOT GALERA_HAVE_UBSAN_LIB)
|
|
+ message(FATAL_ERROR "Could not find UBSAN support library")
|
|
+ endif()
|
|
+ unset(CMAKE_REQUIRED_LIBRARIES)
|
|
+ list(APPEND GALERA_SYSTEM_LIBS ${UBSAN_LIB})
|
|
+endif()
|
|
--- a/cmake/os.cmake
|
|
+++ b/cmake/os.cmake
|
|
@@ -11,7 +11,8 @@ set(GALERA_SYSTEM_LIBS ${PTHREAD_LIB} ${
|
|
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
|
# Check if linkage with atomic library is needed for 8 byte atomics
|
|
set(ATOMIC_8_TEST_C_SOURCE
|
|
- "int main() { long long val; __atomic_fetch_add_8(&val, 1, __ATOMIC_SEQ_CST); return 0;}")
|
|
+ "#include <stdatomic.h>
|
|
+ int main() { atomic_llong val; atomic_fetch_add(&val, 1); return 0; }")
|
|
check_c_source_compiles("${ATOMIC_8_TEST_C_SOURCE}" GALERA_HAVE_ATOMIC)
|
|
if (NOT GALERA_HAVE_ATOMIC)
|
|
find_library(ATOMIC_LIB NAMES atomic libatomic.so.1)
|
|
--- a/cmake/compiler.cmake
|
|
+++ b/cmake/compiler.cmake
|
|
@@ -1,5 +1,5 @@
|
|
#
|
|
-# Copyright (C) 2020 Codership Oy <info@codership.com>
|
|
+# Copyright (C) 2020-2023 Codership Oy <info@codership.com>
|
|
#
|
|
# Common compiler and preprocessor options.
|
|
#
|
|
@@ -46,7 +46,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}
|
|
|
|
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
# To detect STD library misuse with Debug builds.
|
|
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_ASSERTIONS")
|
|
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_ASSERTIONS -O0")
|
|
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
|
|
# Enable debug sync points
|
|
add_definitions(-DGU_DBUG_ON)
|
|
else()
|
|
--- a/galera/tests/data_set_check.cpp
|
|
+++ b/galera/tests/data_set_check.cpp
|
|
@@ -1,10 +1,14 @@
|
|
-/* Copyright (C) 2013-2020 Codership Oy <info@codership.com>
|
|
+/* Copyright (C) 2013-2023 Codership Oy <info@codership.com>
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#undef NDEBUG
|
|
|
|
+#if defined(__sun)
|
|
+#define GALERA_ONLY_ALIGNED
|
|
+#endif
|
|
+
|
|
#include "../src/data_set.hpp"
|
|
|
|
#include "gu_logger.hpp"
|
|
--- a/galera/tests/defaults_check.cpp
|
|
+++ b/galera/tests/defaults_check.cpp
|
|
@@ -1,5 +1,5 @@
|
|
//
|
|
-// Copyright (C) 2018-2020 Codership Oy <info@codership.com>
|
|
+// Copyright (C) 2018-2023 Codership Oy <info@codership.com>
|
|
//
|
|
|
|
#include <wsrep_api.h>
|
|
@@ -307,7 +307,6 @@ START_TEST(defaults)
|
|
ret, strerror(ret));
|
|
}
|
|
|
|
- provider.free(&provider);
|
|
mark_point();
|
|
|
|
/* cleanup files */
|
|
--- a/galerautils/src/gu_crc32c_x86.c
|
|
+++ b/galerautils/src/gu_crc32c_x86.c
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (C) 2020 Codership Oy <info@codership.com>
|
|
+ * Copyright (C) 2020-2023 Codership Oy <info@codership.com>
|
|
*/
|
|
|
|
/**
|
|
@@ -19,33 +19,77 @@
|
|
#include <assert.h>
|
|
#include <stdbool.h>
|
|
|
|
+/* process data preceding the first 4-aligned byte */
|
|
static inline gu_crc32c_t
|
|
-crc32c_x86_tail3(gu_crc32c_t state, const uint8_t* ptr, size_t len)
|
|
+crc32c_x86_head3(gu_crc32c_t state, const uint8_t* ptr, size_t len)
|
|
{
|
|
+ assert(len > 0);
|
|
assert(len < 4);
|
|
|
|
- switch (len)
|
|
+ if (((uintptr_t)ptr) & 1)
|
|
{
|
|
- case 3:
|
|
+ /* odd address */
|
|
state = __builtin_ia32_crc32qi(state, *ptr);
|
|
ptr++;
|
|
- /* fall through */
|
|
+ len--;
|
|
+ }
|
|
+
|
|
+ /* here ptr is at least 2-aligned */
|
|
+ if (len >= 2)
|
|
+ {
|
|
+ assert(0 == ((uintptr_t)ptr)%2);
|
|
+ state = __builtin_ia32_crc32hi(state, *(uint16_t*)ptr);
|
|
+ ptr += 2;
|
|
+ len -= 2;
|
|
+ }
|
|
+
|
|
+ if (len)
|
|
+ {
|
|
+ assert(1 == len);
|
|
+ state = __builtin_ia32_crc32qi(state, *ptr);
|
|
+ }
|
|
+
|
|
+ return state;
|
|
+}
|
|
+
|
|
+static inline gu_crc32c_t
|
|
+crc32c_x86_tail3(gu_crc32c_t state, const uint8_t* ptr, size_t len)
|
|
+{
|
|
+ switch (len)
|
|
+ {
|
|
+ case 3:
|
|
case 2:
|
|
+ /* this byte is 4-aligned */
|
|
state = __builtin_ia32_crc32hi(state, *(uint16_t*)ptr);
|
|
- break;
|
|
+ if (len == 2) break;
|
|
+ ptr += 2;
|
|
+ /* fall through */
|
|
case 1:
|
|
state = __builtin_ia32_crc32qi(state, *ptr);
|
|
+ break;
|
|
+ default:
|
|
+ assert(0);
|
|
}
|
|
-
|
|
return state;
|
|
}
|
|
|
|
static inline gu_crc32c_t
|
|
crc32c_x86(gu_crc32c_t state, const uint8_t* ptr, size_t len)
|
|
{
|
|
+ if (0 == len) return state;
|
|
+
|
|
static size_t const arg_size = sizeof(uint32_t);
|
|
|
|
- /* apparently no ptr misalignment protection is needed */
|
|
+ size_t align_offset = ((uintptr_t)ptr) % arg_size;
|
|
+ if (align_offset)
|
|
+ {
|
|
+ align_offset = arg_size - align_offset;
|
|
+ if (align_offset > len) align_offset = len;
|
|
+ state = crc32c_x86_head3(state, ptr, align_offset);
|
|
+ len -= align_offset;
|
|
+ ptr += align_offset;
|
|
+ }
|
|
+
|
|
while (len >= arg_size)
|
|
{
|
|
state = __builtin_ia32_crc32si(state, *(uint32_t*)ptr);
|
|
@@ -55,7 +99,7 @@ crc32c_x86(gu_crc32c_t state, const uint
|
|
|
|
assert(len < 4);
|
|
|
|
- return crc32c_x86_tail3(state, ptr, len);
|
|
+ return (len ? crc32c_x86_tail3(state, ptr, len) : state);
|
|
}
|
|
|
|
gu_crc32c_t
|
|
@@ -71,7 +115,20 @@ gu_crc32c_x86_64(gu_crc32c_t state, cons
|
|
const uint8_t* ptr = (const uint8_t*)data;
|
|
|
|
#ifdef __LP64__
|
|
+ if (0 == len) return state;
|
|
+
|
|
static size_t const arg_size = sizeof(uint64_t);
|
|
+
|
|
+ size_t align_offset = ((uintptr_t)ptr) % arg_size;
|
|
+ if (align_offset)
|
|
+ {
|
|
+ align_offset = arg_size - align_offset;
|
|
+ if (align_offset > len) align_offset = len;
|
|
+ state = crc32c_x86(state, ptr, align_offset);
|
|
+ len -= align_offset;
|
|
+ ptr += align_offset;
|
|
+ }
|
|
+
|
|
uint64_t state64 = state;
|
|
|
|
while (len >= arg_size)
|
|
--- a/galerautils/src/gu_mmh3.c
|
|
+++ b/galerautils/src/gu_mmh3.c
|
|
@@ -257,10 +257,11 @@ static uint64_t const GU_MMH128_SEED2 =
|
|
extern void
|
|
gu_mmh128 (const void* const msg, size_t const len, void* const out)
|
|
{
|
|
- _mmh3_128_seed (msg, len, GU_MMH128_SEED1, GU_MMH128_SEED2, (uint64_t*)out);
|
|
- uint64_t* const res = (uint64_t*)out;
|
|
+ uint64_t res[2];
|
|
+ _mmh3_128_seed (msg, len, GU_MMH128_SEED1, GU_MMH128_SEED2, res);
|
|
res[0] = gu_le64(res[0]);
|
|
res[1] = gu_le64(res[1]);
|
|
+ memcpy(out, res, sizeof(res));
|
|
}
|
|
|
|
/* returns hash as an integer, in host byte-order */
|
|
@@ -378,8 +379,9 @@ gu_mmh128_get32 (const gu_mmh128_ctx_t*
|
|
void
|
|
gu_mmh3_32 (const void* const key, int const len, uint32_t const seed, void* const out)
|
|
{
|
|
- uint32_t const res = _mmh32_seed (key, len, seed);
|
|
- *((uint32_t*)out) = gu_le32(res);
|
|
+ uint32_t res = _mmh32_seed (key, len, seed);
|
|
+ res = gu_le32(res);
|
|
+ memcpy(out, &res, sizeof(res));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
--- a/galerautils/src/gu_utils.c
|
|
+++ b/galerautils/src/gu_utils.c
|
|
@@ -1,4 +1,4 @@
|
|
-// Copyright (C) 2010 Codership Oy <info@codership.com>
|
|
+// Copyright (C) 2010-2023 Codership Oy <info@codership.com>
|
|
|
|
/**
|
|
* @file Miscellaneous utility functions
|
|
@@ -42,13 +42,20 @@ gu_str2ll (const char* str, long long* l
|
|
shift += 10;
|
|
ret++;
|
|
|
|
- if (llret == ((llret << (shift + 1)) >> (shift + 1))) {
|
|
- llret <<= shift;
|
|
- }
|
|
- else { /* ERANGE */
|
|
- if (llret > 0) llret = LLONG_MAX;
|
|
- else llret = LLONG_MIN;
|
|
- errno = ERANGE;
|
|
+ {
|
|
+ long long const sign = (llret < 0 ? -1 : 1);
|
|
+ unsigned long long ullret = sign * llret;
|
|
+
|
|
+ if (ullret == ((ullret << (shift + 1)) >> (shift + 1))) {
|
|
+ ullret <<= shift;
|
|
+ llret = ullret;
|
|
+ llret *= sign;
|
|
+ }
|
|
+ else { /* ERANGE */
|
|
+ if (llret > 0) llret = LLONG_MAX;
|
|
+ else llret = LLONG_MIN;
|
|
+ errno = ERANGE;
|
|
+ }
|
|
}
|
|
/* fall through */
|
|
default:
|
|
--- a/galera/src/certification.cpp
|
|
+++ b/galera/src/certification.cpp
|
|
@@ -98,8 +98,8 @@ check_purge_complete(const galera::Certi
|
|
{
|
|
std::for_each(
|
|
cert_index.begin(), cert_index.end(),
|
|
- [&cert_index, &key_set,
|
|
- ts](const galera::Certification::CertIndexNG::value_type& ke) {
|
|
+ [&key_set, ts]
|
|
+ (const galera::Certification::CertIndexNG::value_type& ke) {
|
|
ke->for_each_ref([&ke, &key_set, ts](const TrxHandleSlave* ref) {
|
|
if (ts == ref)
|
|
{
|
|
--- a/gcache/src/gcache_mem_store.hpp
|
|
+++ b/gcache/src/gcache_mem_store.hpp
|
|
@@ -92,16 +92,19 @@ namespace gcache
|
|
|
|
void* realloc (void* ptr, size_type size)
|
|
{
|
|
- BufferHeader* bh(0);
|
|
- size_type old_size(0);
|
|
+ if (!ptr) return malloc(size);
|
|
|
|
- if (ptr)
|
|
+ BufferHeader* bh(ptr2BH(ptr));
|
|
+ assert (SEQNO_NONE == bh->seqno_g);
|
|
+
|
|
+ if (!size)
|
|
{
|
|
- bh = ptr2BH(ptr);
|
|
- assert (SEQNO_NONE == bh->seqno_g);
|
|
- old_size = bh->size;
|
|
+ free(bh);
|
|
+ return nullptr;
|
|
}
|
|
|
|
+ uintptr_t const orig(reinterpret_cast<uintptr_t>(bh));
|
|
+ size_type const old_size(bh->size);
|
|
diff_type const diff_size(size - old_size);
|
|
|
|
if (size > max_size_ ||
|
|
@@ -109,11 +112,11 @@ namespace gcache
|
|
|
|
assert (size_ + diff_size <= max_size_);
|
|
|
|
+ allocd_.erase(bh);
|
|
void* tmp = ::realloc (bh, size);
|
|
|
|
if (tmp)
|
|
{
|
|
- allocd_.erase(bh);
|
|
allocd_.insert(tmp);
|
|
|
|
bh = BH_cast(tmp);
|
|
@@ -124,6 +127,13 @@ namespace gcache
|
|
|
|
return (bh + 1);
|
|
}
|
|
+ else
|
|
+ {
|
|
+ assert(size > 0);
|
|
+ /* orginal buffer is still allocated so we need to restore it
|
|
+ * but we can't use bh directly due to GCC warnings */
|
|
+ allocd_.insert(reinterpret_cast<BufferHeader*>(orig));
|
|
+ }
|
|
|
|
return 0;
|
|
}
|
|
@@ -133,8 +143,8 @@ namespace gcache
|
|
assert (BH_is_released(bh));
|
|
|
|
size_ -= bh->size;
|
|
- ::free (bh);
|
|
allocd_.erase(bh);
|
|
+ ::free (bh);
|
|
}
|
|
|
|
void set_max_size (size_t size) { max_size_ = size; }
|
|
--- a/gcache/src/gcache_rb_store.cpp
|
|
+++ b/gcache/src/gcache_rb_store.cpp
|
|
@@ -798,7 +798,8 @@ namespace gcache
|
|
sizeof(cs_old)));
|
|
std::ostringstream msg;
|
|
|
|
- msg << "Attempt to reuse the same seqno: " << seqno_g
|
|
+ msg << "Attempt (" << collision_count
|
|
+ << ") to reuse the same seqno: " << seqno_g
|
|
<< ". New ptr = " << new_ptr << ", " << bh
|
|
<< ", cs: " << gu::Hexdump(cs_new, sizeof(cs_new))
|
|
<< ", previous ptr = " << old_ptr;
|
|
@@ -1230,7 +1231,7 @@ namespace gcache
|
|
size_t chain_count[] = { 0, 0, 0, 0 };
|
|
|
|
chain_t chain(NONE);
|
|
- const uint8_t* chain_start;
|
|
+ const uint8_t* chain_start(start_);
|
|
size_t count;
|
|
|
|
bool next(false);
|
|
--- a/gcs/src/gcs_group.cpp
|
|
+++ b/gcs/src/gcs_group.cpp
|
|
@@ -1409,7 +1409,7 @@ group_for_each_donor_in_string (const gc
|
|
* that at least one of the nodes in the list will become available. */
|
|
if (-EAGAIN != err) err = idx;
|
|
|
|
- begin = end + 1; /* skip comma */
|
|
+ if (end) begin = end + 1; /* skip comma */
|
|
|
|
} while (end != NULL);
|
|
|
|
@@ -1498,7 +1498,7 @@ group_find_ist_donor_by_name_in_string (
|
|
ret = idx;
|
|
}
|
|
}
|
|
- begin = end + 1;
|
|
+ if (end) begin = end + 1;
|
|
} while (end != NULL);
|
|
|
|
if (ret == -1) {
|
|
--- a/gcs/src/unit_tests/gcs_core_test.cpp
|
|
+++ b/gcs/src/unit_tests/gcs_core_test.cpp
|
|
@@ -506,7 +506,7 @@ START_TEST (gcs_core_test_api)
|
|
size_t act_size = sizeof(act3_str);
|
|
|
|
action_t act_s(act, NULL, NULL, act_size, GCS_ACT_WRITESET, -1, (gu_thread_t)-1);
|
|
- action_t act_r(act, NULL, NULL, -1, (gcs_act_type_t)-1, -1, (gu_thread_t)-1);
|
|
+ action_t act_r(act, NULL, NULL, -1, (gcs_act_type_t)GCS_ACT_UNKNOWN, -1, (gu_thread_t)-1);
|
|
long i = 5;
|
|
|
|
// test basic fragmentaiton
|
|
@@ -610,7 +610,7 @@ CORE_TEST_OWN (int gcs_proto_ver)
|
|
size_t act_size = sizeof(act2_str);
|
|
|
|
action_t act_s(act, NULL, NULL, act_size, GCS_ACT_WRITESET, -1, (gu_thread_t)-1);
|
|
- action_t act_r(act, NULL, NULL, -1, (gcs_act_type_t)-1, -1, (gu_thread_t)-1);
|
|
+ action_t act_r(act, NULL, NULL, -1, (gcs_act_type_t)GCS_ACT_UNKNOWN, -1, (gu_thread_t)-1);
|
|
|
|
// Create primary and non-primary component messages
|
|
gcs_comp_msg_t* prim = gcs_comp_msg_new (true, false, 0, 1, 0);
|
|
--- a/gcomm/src/evs_message2.cpp
|
|
+++ b/gcomm/src/evs_message2.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (C) 2009-2012 Codership Oy <info@codership.com>
|
|
+ * Copyright (C) 2009-2023 Codership Oy <info@codership.com>
|
|
*
|
|
* $Id$
|
|
*/
|
|
@@ -179,8 +179,16 @@ size_t gcomm::evs::Message::serialize(gu
|
|
return offset;
|
|
}
|
|
|
|
+gcomm::evs::Message::Type gcomm::evs::Message::get_type(const gu::byte_t* buf,
|
|
+ size_t buflen,
|
|
+ size_t offset)
|
|
+{
|
|
+ uint8_t b;
|
|
+ gu_trace(offset = gu::unserialize1(buf, buflen, offset, b));
|
|
+ return static_cast<Type>((b >> 2) & 0x7);
|
|
+}
|
|
|
|
-size_t gcomm::evs::Message::unserialize(const gu::byte_t* const buf,
|
|
+size_t gcomm::evs::Message::unserialize_common(const gu::byte_t* const buf,
|
|
size_t const buflen,
|
|
size_t offset)
|
|
{
|
|
@@ -267,13 +275,9 @@ size_t gcomm::evs::UserMessage::serializ
|
|
|
|
size_t gcomm::evs::UserMessage::unserialize(const gu::byte_t* const buf,
|
|
size_t const buflen,
|
|
- size_t offset,
|
|
- bool skip_header)
|
|
+ size_t offset)
|
|
{
|
|
- if (skip_header == false)
|
|
- {
|
|
- gu_trace(offset = Message::unserialize(buf, buflen, offset));
|
|
- }
|
|
+ gu_trace(offset = Message::unserialize_common(buf, buflen, offset));
|
|
gu_trace(offset = gu::unserialize1(buf, buflen, offset, user_type_));
|
|
uint8_t b;
|
|
gu_trace(offset = gu::unserialize1(buf, buflen, offset, b));
|
|
@@ -340,13 +344,9 @@ size_t gcomm::evs::DelegateMessage::seri
|
|
|
|
size_t gcomm::evs::DelegateMessage::unserialize(const gu::byte_t* const buf,
|
|
size_t const buflen,
|
|
- size_t offset,
|
|
- bool skip_header)
|
|
+ size_t offset)
|
|
{
|
|
- if (skip_header == false)
|
|
- {
|
|
- gu_trace(offset = Message::unserialize(buf, buflen, offset));
|
|
- }
|
|
+ gu_trace(offset = Message::unserialize_common(buf, buflen, offset));
|
|
return offset;
|
|
}
|
|
|
|
@@ -371,13 +371,9 @@ size_t gcomm::evs::GapMessage::serialize
|
|
|
|
size_t gcomm::evs::GapMessage::unserialize(const gu::byte_t* const buf,
|
|
size_t const buflen,
|
|
- size_t offset,
|
|
- bool skip_header)
|
|
+ size_t offset)
|
|
{
|
|
- if (skip_header == false)
|
|
- {
|
|
- gu_trace(offset = Message::unserialize(buf, buflen, offset));
|
|
- }
|
|
+ gu_trace(offset = Message::unserialize_common(buf, buflen, offset));
|
|
gu_trace(offset = gu::unserialize8(buf, buflen, offset, seq_));
|
|
gu_trace(offset = gu::unserialize8(buf, buflen, offset, aru_seq_));
|
|
gu_trace(offset = range_uuid_.unserialize(buf, buflen, offset));
|
|
@@ -406,13 +402,9 @@ size_t gcomm::evs::JoinMessage::serializ
|
|
|
|
size_t gcomm::evs::JoinMessage::unserialize(const gu::byte_t* const buf,
|
|
size_t const buflen,
|
|
- size_t offset,
|
|
- bool skip_header)
|
|
+ size_t offset)
|
|
{
|
|
- if (skip_header == false)
|
|
- {
|
|
- gu_trace(offset = Message::unserialize(buf, buflen, offset));
|
|
- }
|
|
+ gu_trace(offset = Message::unserialize_common(buf, buflen, offset));
|
|
gu_trace(offset = gu::unserialize8(buf, buflen, offset, seq_));
|
|
gu_trace(offset = gu::unserialize8(buf, buflen, offset, aru_seq_));
|
|
node_list_.clear();
|
|
@@ -441,13 +433,9 @@ size_t gcomm::evs::InstallMessage::seria
|
|
|
|
size_t gcomm::evs::InstallMessage::unserialize(const gu::byte_t* const buf,
|
|
size_t const buflen,
|
|
- size_t offset,
|
|
- bool skip_header)
|
|
+ size_t offset)
|
|
{
|
|
- if (skip_header == false)
|
|
- {
|
|
- gu_trace(offset = Message::unserialize(buf, buflen, offset));
|
|
- }
|
|
+ gu_trace(offset = Message::unserialize_common(buf, buflen, offset));
|
|
gu_trace(offset = gu::unserialize8(buf, buflen, offset, seq_));
|
|
gu_trace(offset = gu::unserialize8(buf, buflen, offset, aru_seq_));
|
|
gu_trace(offset = install_view_id_.unserialize(buf, buflen, offset));
|
|
@@ -477,13 +465,9 @@ size_t gcomm::evs::LeaveMessage::seriali
|
|
|
|
size_t gcomm::evs::LeaveMessage::unserialize(const gu::byte_t* const buf,
|
|
size_t const buflen,
|
|
- size_t offset,
|
|
- bool skip_header)
|
|
+ size_t offset)
|
|
{
|
|
- if (skip_header == false)
|
|
- {
|
|
- gu_trace(offset = Message::unserialize(buf, buflen, offset));
|
|
- }
|
|
+ gu_trace(offset = Message::unserialize_common(buf, buflen, offset));
|
|
gu_trace(offset = gu::unserialize8(buf, buflen, offset, seq_));
|
|
gu_trace(offset = gu::unserialize8(buf, buflen, offset, aru_seq_));
|
|
return offset;
|
|
@@ -512,13 +496,9 @@ size_t gcomm::evs::DelayedListMessage::s
|
|
|
|
size_t gcomm::evs::DelayedListMessage::unserialize(const gu::byte_t* const buf,
|
|
size_t const buflen,
|
|
- size_t offset,
|
|
- bool skip_header)
|
|
+ size_t offset)
|
|
{
|
|
- if (skip_header == false)
|
|
- {
|
|
- gu_trace(offset = Message::unserialize(buf, buflen, offset));
|
|
- }
|
|
+ gu_trace(offset = Message::unserialize_common(buf, buflen, offset));
|
|
delayed_list_.clear();
|
|
uint8_t list_sz(0);
|
|
gu_trace(offset = gu::unserialize1(buf, buflen, offset, list_sz));
|
|
--- a/gcomm/src/evs_message2.hpp
|
|
+++ b/gcomm/src/evs_message2.hpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (C) 2009-2019 Codership Oy <info@codership.com>
|
|
+ * Copyright (C) 2009-2023 Codership Oy <info@codership.com>
|
|
*/
|
|
|
|
#ifndef EVS_MESSAGE2_HPP
|
|
@@ -290,7 +290,17 @@ public:
|
|
*/
|
|
gu::datetime::Date tstamp() const { return tstamp_; }
|
|
|
|
- size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset);
|
|
+ /* Read type from message buffer. */
|
|
+ static Type get_type(const gu::byte_t* buf, size_t buflen, size_t offset);
|
|
+
|
|
+ /* Unserialize common header. */
|
|
+ size_t unserialize_common(const gu::byte_t* buf, size_t buflen,
|
|
+ size_t offset);
|
|
+
|
|
+ /* Unserialize message. */
|
|
+ virtual size_t unserialize(const gu::byte_t* buf, size_t buflen,
|
|
+ size_t offset)
|
|
+ = 0;
|
|
|
|
bool operator==(const Message& cmp) const;
|
|
|
|
@@ -444,8 +454,7 @@ public:
|
|
void set_aru_seq(const seqno_t as) { aru_seq_ = as; }
|
|
|
|
size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const;
|
|
- size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset,
|
|
- bool skip_header = false);
|
|
+ size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset) override;
|
|
size_t serial_size() const;
|
|
|
|
};
|
|
@@ -504,8 +513,8 @@ public:
|
|
fifo_seq)
|
|
{ }
|
|
size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const;
|
|
- size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset,
|
|
- bool skip_header = false);
|
|
+ size_t unserialize(const gu::byte_t* buf, size_t buflen,
|
|
+ size_t offset) override;
|
|
size_t serial_size() const;
|
|
};
|
|
|
|
@@ -537,8 +546,8 @@ public:
|
|
range)
|
|
{ }
|
|
size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const;
|
|
- size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset,
|
|
- bool skip_header = false);
|
|
+ size_t unserialize(const gu::byte_t* buf, size_t buflen,
|
|
+ size_t offset) override;
|
|
size_t serial_size() const;
|
|
};
|
|
|
|
@@ -569,8 +578,8 @@ public:
|
|
node_list)
|
|
{ }
|
|
size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const;
|
|
- size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset,
|
|
- bool skip_header = false);
|
|
+ size_t unserialize(const gu::byte_t* buf, size_t buflen,
|
|
+ size_t offset) override;
|
|
size_t serial_size() const;
|
|
};
|
|
|
|
@@ -602,8 +611,8 @@ public:
|
|
node_list)
|
|
{ }
|
|
size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const;
|
|
- size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset,
|
|
- bool skip_header = false);
|
|
+ size_t unserialize(const gu::byte_t* buf, size_t buflen,
|
|
+ size_t offset) override;
|
|
size_t serial_size() const;
|
|
};
|
|
|
|
@@ -631,8 +640,8 @@ public:
|
|
flags)
|
|
{ }
|
|
size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const;
|
|
- size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset,
|
|
- bool skip_header = false);
|
|
+ size_t unserialize(const gu::byte_t* buf, size_t buflen,
|
|
+ size_t offset) override;
|
|
size_t serial_size() const;
|
|
};
|
|
|
|
@@ -662,8 +671,8 @@ public:
|
|
const DelayedList& delayed_list() const { return delayed_list_; }
|
|
|
|
size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const;
|
|
- size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset,
|
|
- bool skip_header = false);
|
|
+ size_t unserialize(const gu::byte_t* buf, size_t buflen,
|
|
+ size_t offset) override;
|
|
size_t serial_size() const;
|
|
bool operator==(const DelayedListMessage& cmp) const
|
|
{
|
|
--- a/gcomm/src/evs_proto.cpp
|
|
+++ b/gcomm/src/evs_proto.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (C) 2009-2019 Codership Oy <info@codership.com>
|
|
+ * Copyright (C) 2009-2023 Codership Oy <info@codership.com>
|
|
*/
|
|
|
|
#include "evs_proto.hpp"
|
|
@@ -2490,67 +2490,63 @@ void gcomm::evs::Proto::handle_msg(const
|
|
// Protolay interface
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
-size_t gcomm::evs::Proto::unserialize_message(const UUID& source,
|
|
- const Datagram& rb,
|
|
- Message* msg)
|
|
+std::pair<std::unique_ptr<gcomm::evs::Message>, size_t>
|
|
+gcomm::evs::Proto::unserialize_message(const UUID& source, const Datagram& rb)
|
|
{
|
|
- size_t offset;
|
|
+ size_t offset = 0;
|
|
const gu::byte_t* begin(gcomm::begin(rb));
|
|
const size_t available(gcomm::available(rb));
|
|
- gu_trace(offset = msg->unserialize(begin,
|
|
- available,
|
|
- 0));
|
|
- if ((msg->flags() & Message::F_SOURCE) == 0)
|
|
+ std::unique_ptr<Message> ret;
|
|
+ switch (Message::get_type(begin, available, offset))
|
|
{
|
|
- assert(source != UUID::nil());
|
|
- gcomm_assert(source != UUID::nil());
|
|
- msg->set_source(source);
|
|
- }
|
|
-
|
|
- switch (msg->type())
|
|
- {
|
|
- case Message::EVS_T_NONE:
|
|
- gu_throw_fatal;
|
|
- break;
|
|
+ case Message::EVS_T_NONE: gu_throw_fatal; break;
|
|
case Message::EVS_T_USER:
|
|
- gu_trace(offset = static_cast<UserMessage&>(*msg).unserialize(
|
|
- begin, available, offset, true));
|
|
+ ret = std::unique_ptr<UserMessage>(new UserMessage);
|
|
+ gu_trace(offset = ret->unserialize(begin, available, offset));
|
|
break;
|
|
case Message::EVS_T_DELEGATE:
|
|
- gu_trace(offset = static_cast<DelegateMessage&>(*msg).unserialize(
|
|
- begin, available, offset, true));
|
|
+ ret = std::unique_ptr<DelegateMessage>(new DelegateMessage);
|
|
+ gu_trace(offset = ret->unserialize(begin, available, offset));
|
|
break;
|
|
case Message::EVS_T_GAP:
|
|
- gu_trace(offset = static_cast<GapMessage&>(*msg).unserialize(
|
|
- begin, available, offset, true));
|
|
+ ret = std::unique_ptr<GapMessage>(new GapMessage);
|
|
+ gu_trace(offset = ret->unserialize(begin, available, offset));
|
|
break;
|
|
case Message::EVS_T_JOIN:
|
|
- gu_trace(offset = static_cast<JoinMessage&>(*msg).unserialize(
|
|
- begin, available, offset, true));
|
|
+ ret = std::unique_ptr<JoinMessage>(new JoinMessage);
|
|
+ gu_trace(offset = ret->unserialize(begin, available, offset));
|
|
break;
|
|
case Message::EVS_T_INSTALL:
|
|
- gu_trace(offset = static_cast<InstallMessage&>(*msg).unserialize(
|
|
- begin, available, offset, true));
|
|
+ ret = std::unique_ptr<InstallMessage>(new InstallMessage);
|
|
+ gu_trace(offset = ret->unserialize(begin, available, offset));
|
|
break;
|
|
case Message::EVS_T_LEAVE:
|
|
- gu_trace(offset = static_cast<LeaveMessage&>(*msg).unserialize(
|
|
- begin, available, offset, true));
|
|
+ ret = std::unique_ptr<LeaveMessage>(new LeaveMessage);
|
|
+ gu_trace(offset = ret->unserialize(begin, available, offset));
|
|
break;
|
|
case Message::EVS_T_DELAYED_LIST:
|
|
- gu_trace(offset = static_cast<DelayedListMessage&>(*msg).unserialize(
|
|
- begin, available, offset, true));
|
|
+ ret = std::unique_ptr<DelayedListMessage>(new DelayedListMessage);
|
|
+ gu_trace(offset = ret->unserialize(begin, available, offset));
|
|
break;
|
|
+ default:
|
|
+ return {std::unique_ptr<Message>{}, 0};
|
|
}
|
|
- return (offset + rb.offset());
|
|
+
|
|
+ /* Message did not have source field, must be set from source reported
|
|
+ by the lower layer. */
|
|
+ if ((ret->flags() & Message::F_SOURCE) == 0)
|
|
+ {
|
|
+ assert(source != UUID::nil());
|
|
+ gcomm_assert(source != UUID::nil());
|
|
+ ret->set_source(source);
|
|
+ }
|
|
+
|
|
+ return {std::move(ret), offset + rb.offset()};
|
|
}
|
|
|
|
-void gcomm::evs::Proto::handle_up(const void* cid,
|
|
- const Datagram& rb,
|
|
+void gcomm::evs::Proto::handle_up(const void* cid, const Datagram& rb,
|
|
const ProtoUpMeta& um)
|
|
{
|
|
-
|
|
- Message msg;
|
|
-
|
|
if (state() == S_CLOSED || um.source() == uuid() || is_evicted(um.source()))
|
|
{
|
|
// Silent drop
|
|
@@ -2559,12 +2555,16 @@ void gcomm::evs::Proto::handle_up(const
|
|
|
|
gcomm_assert(um.source() != UUID::nil());
|
|
|
|
+ std::pair<std::unique_ptr<Message>, size_t> msg;
|
|
try
|
|
{
|
|
- size_t offset;
|
|
- gu_trace(offset = unserialize_message(um.source(), rb, &msg));
|
|
- handle_msg(msg, Datagram(rb, offset),
|
|
- (msg.flags() & Message::F_RETRANS) == 0);
|
|
+ gu_trace(msg = unserialize_message(um.source(), rb));
|
|
+ if (not msg.first) {
|
|
+ /* Message could not be serialized. */
|
|
+ return;
|
|
+ }
|
|
+ handle_msg(*msg.first, Datagram(rb, msg.second),
|
|
+ (msg.first->flags() & Message::F_RETRANS) == 0);
|
|
}
|
|
catch (gu::Exception& e)
|
|
{
|
|
@@ -2575,11 +2575,11 @@ void gcomm::evs::Proto::handle_up(const
|
|
break;
|
|
|
|
case EINVAL:
|
|
- log_warn << "invalid message: " << msg;
|
|
+ log_warn << "invalid message: " << *msg.first;
|
|
break;
|
|
|
|
default:
|
|
- log_fatal << "exception caused by message: " << msg;
|
|
+ log_fatal << "exception caused by message: " << *msg.first;
|
|
std::cerr << " state after handling message: " << *this;
|
|
throw;
|
|
}
|
|
@@ -3791,20 +3791,20 @@ void gcomm::evs::Proto::handle_user(cons
|
|
}
|
|
}
|
|
|
|
-
|
|
void gcomm::evs::Proto::handle_delegate(const DelegateMessage& msg,
|
|
NodeMap::iterator ii,
|
|
const Datagram& rb)
|
|
{
|
|
gcomm_assert(ii != known_.end());
|
|
evs_log_debug(D_DELEGATE_MSGS) << "delegate message " << msg;
|
|
- Message umsg;
|
|
- size_t offset;
|
|
- gu_trace(offset = unserialize_message(UUID::nil(), rb, &umsg));
|
|
- gu_trace(handle_msg(umsg, Datagram(rb, offset), false));
|
|
+ std::pair<std::unique_ptr<Message>, size_t> umsg;
|
|
+ gu_trace(umsg = unserialize_message(UUID::nil(), rb));
|
|
+ if (not umsg.first) {
|
|
+ return;
|
|
+ }
|
|
+ gu_trace(handle_msg(*umsg.first, Datagram(rb, umsg.second), false));
|
|
}
|
|
|
|
-
|
|
void gcomm::evs::Proto::handle_gap(const GapMessage& msg, NodeMap::iterator ii)
|
|
{
|
|
assert(ii != known_.end());
|
|
--- a/gcomm/src/evs_proto.hpp
|
|
+++ b/gcomm/src/evs_proto.hpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (C) 2009-2019 Codership Oy <info@codership.com>
|
|
+ * Copyright (C) 2009-2023 Codership Oy <info@codership.com>
|
|
*/
|
|
|
|
/*!
|
|
@@ -288,11 +288,9 @@ private:
|
|
void populate_node_list(MessageNodeList*) const;
|
|
void isolate(gu::datetime::Period period);
|
|
public:
|
|
- static size_t unserialize_message(const UUID&,
|
|
- const Datagram&,
|
|
- Message*);
|
|
- void handle_msg(const Message& msg,
|
|
- const Datagram& dg = Datagram(),
|
|
+ static std::pair<std::unique_ptr<gcomm::evs::Message>, size_t>
|
|
+ unserialize_message(const UUID&, const Datagram&);
|
|
+ void handle_msg(const Message& msg, const Datagram& dg = Datagram(),
|
|
bool direct = true);
|
|
// Protolay
|
|
void handle_up(const void*, const Datagram&, const ProtoUpMeta&);
|
|
--- a/gcomm/test/check_evs2.cpp
|
|
+++ b/gcomm/test/check_evs2.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (C) 2009-2020 Codership Oy <info@codership.com>
|
|
+ * Copyright (C) 2009-2023 Codership Oy <info@codership.com>
|
|
*/
|
|
|
|
/*!
|
|
@@ -455,12 +455,13 @@ START_TEST(test_input_map_gap_range_list
|
|
}
|
|
END_TEST
|
|
|
|
-static Datagram* get_msg(DummyTransport* tp, Message* msg, bool release = true)
|
|
+static Datagram* get_msg(DummyTransport* tp, std::unique_ptr<Message>& msg,
|
|
+ bool release = true)
|
|
{
|
|
Datagram* rb = tp->out();
|
|
if (rb != 0)
|
|
{
|
|
- gu_trace(Proto::unserialize_message(tp->uuid(), *rb, msg));
|
|
+ msg = Proto::unserialize_message(tp->uuid(), *rb).first;
|
|
if (release == true)
|
|
{
|
|
delete rb;
|
|
@@ -471,7 +472,7 @@ static Datagram* get_msg(DummyTransport*
|
|
|
|
static void single_join(DummyTransport* t, Proto* p)
|
|
{
|
|
- Message jm, im, gm;
|
|
+ std::unique_ptr<Message> jm, im, gm;
|
|
|
|
// Initial state is joining
|
|
p->shift_to(Proto::S_JOINING);
|
|
@@ -479,42 +480,42 @@ static void single_join(DummyTransport*
|
|
// Send join must produce emitted join message
|
|
p->send_join();
|
|
|
|
- Datagram* rb = get_msg(t, &jm);
|
|
+ Datagram* rb = get_msg(t, jm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(jm.type() == Message::EVS_T_JOIN);
|
|
+ ck_assert(jm->type() == Message::EVS_T_JOIN);
|
|
|
|
// Install message is emitted at the end of JOIN handling
|
|
// 'cause this is the only instance and is always consistent
|
|
// with itself
|
|
- rb = get_msg(t, &im);
|
|
+ rb = get_msg(t, im);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(im.type() == Message::EVS_T_INSTALL);
|
|
+ ck_assert(im->type() == Message::EVS_T_INSTALL);
|
|
|
|
// Handling INSTALL message emits three gap messages,
|
|
// one for receiving install message (commit gap), one for
|
|
// shift to install and one for shift to operational
|
|
- rb = get_msg(t, &gm);
|
|
+ rb = get_msg(t, gm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(gm.type() == Message::EVS_T_GAP);
|
|
- ck_assert((gm.flags() & Message::F_COMMIT) != 0);
|
|
+ ck_assert(gm->type() == Message::EVS_T_GAP);
|
|
+ ck_assert((gm->flags() & Message::F_COMMIT) != 0);
|
|
|
|
- rb = get_msg(t, &gm);
|
|
+ rb = get_msg(t, gm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(gm.type() == Message::EVS_T_GAP);
|
|
- ck_assert((gm.flags() & Message::F_COMMIT) == 0);
|
|
+ ck_assert(gm->type() == Message::EVS_T_GAP);
|
|
+ ck_assert((gm->flags() & Message::F_COMMIT) == 0);
|
|
|
|
- rb = get_msg(t, &gm);
|
|
+ rb = get_msg(t, gm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(gm.type() == Message::EVS_T_GAP);
|
|
- ck_assert((gm.flags() & Message::F_COMMIT) == 0);
|
|
+ ck_assert(gm->type() == Message::EVS_T_GAP);
|
|
+ ck_assert((gm->flags() & Message::F_COMMIT) == 0);
|
|
|
|
// State must have evolved JOIN -> S_GATHER -> S_INSTALL -> S_OPERATIONAL
|
|
ck_assert(p->state() == Proto::S_OPERATIONAL);
|
|
|
|
// Handle join message again, must stay in S_OPERATIONAL, must not
|
|
// emit anything
|
|
- p->handle_msg(jm);
|
|
- rb = get_msg(t, &gm);
|
|
+ p->handle_msg(*jm);
|
|
+ rb = get_msg(t, gm);
|
|
ck_assert(rb == 0);
|
|
ck_assert(p->state() == Proto::S_OPERATIONAL);
|
|
|
|
@@ -553,11 +554,11 @@ static void double_join(DummyTransport*
|
|
DummyTransport* t2, Proto* p2)
|
|
{
|
|
|
|
- Message jm;
|
|
- Message im;
|
|
- Message gm;
|
|
- Message gm2;
|
|
- Message msg;
|
|
+ std::unique_ptr<Message> jm;
|
|
+ std::unique_ptr<Message> im;
|
|
+ std::unique_ptr<Message> gm;
|
|
+ std::unique_ptr<Message> gm2;
|
|
+ std::unique_ptr<Message> msg;
|
|
|
|
Datagram* rb;
|
|
|
|
@@ -570,99 +571,99 @@ static void double_join(DummyTransport*
|
|
// Expected output: one join message
|
|
p2->send_join(false);
|
|
ck_assert(p2->state() == Proto::S_JOINING);
|
|
- rb = get_msg(t2, &jm);
|
|
+ rb = get_msg(t2, jm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(jm.type() == Message::EVS_T_JOIN);
|
|
- rb = get_msg(t2, &msg);
|
|
+ ck_assert(jm->type() == Message::EVS_T_JOIN);
|
|
+ rb = get_msg(t2, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
// Handle node 2's join on node 1
|
|
// Expected output: shift to S_GATHER and one join message
|
|
- p1->handle_msg(jm);
|
|
+ p1->handle_msg(*jm);
|
|
ck_assert(p1->state() == Proto::S_GATHER);
|
|
- rb = get_msg(t1, &jm);
|
|
+ rb = get_msg(t1, jm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(jm.type() == Message::EVS_T_JOIN);
|
|
- rb = get_msg(t1, &msg);
|
|
+ ck_assert(jm->type() == Message::EVS_T_JOIN);
|
|
+ rb = get_msg(t1, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
// Handle node 1's join on node 2
|
|
// Expected output: shift to S_GATHER and one join message
|
|
- p2->handle_msg(jm);
|
|
+ p2->handle_msg(*jm);
|
|
ck_assert(p2->state() == Proto::S_GATHER);
|
|
- rb = get_msg(t2, &jm);
|
|
+ rb = get_msg(t2, jm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(jm.type() == Message::EVS_T_JOIN);
|
|
- rb = get_msg(t2, &msg);
|
|
+ ck_assert(jm->type() == Message::EVS_T_JOIN);
|
|
+ rb = get_msg(t2, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
// Handle node 2's join on node 1
|
|
// Expected output: Install and commit gap messages, state stays in S_GATHER
|
|
- p1->handle_msg(jm);
|
|
+ p1->handle_msg(*jm);
|
|
ck_assert(p1->state() == Proto::S_GATHER);
|
|
- rb = get_msg(t1, &im);
|
|
+ rb = get_msg(t1, im);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(im.type() == Message::EVS_T_INSTALL);
|
|
- rb = get_msg(t1, &gm);
|
|
+ ck_assert(im->type() == Message::EVS_T_INSTALL);
|
|
+ rb = get_msg(t1, gm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(gm.type() == Message::EVS_T_GAP);
|
|
- ck_assert((gm.flags() & Message::F_COMMIT) != 0);
|
|
- rb = get_msg(t1, &msg);
|
|
+ ck_assert(gm->type() == Message::EVS_T_GAP);
|
|
+ ck_assert((gm->flags() & Message::F_COMMIT) != 0);
|
|
+ rb = get_msg(t1, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
// Handle install message on node 2
|
|
// Expected output: commit gap message and state stays in S_RECOVERY
|
|
- p2->handle_msg(im);
|
|
+ p2->handle_msg(*im);
|
|
ck_assert(p2->state() == Proto::S_GATHER);
|
|
- rb = get_msg(t2, &gm2);
|
|
+ rb = get_msg(t2, gm2);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(gm2.type() == Message::EVS_T_GAP);
|
|
- ck_assert((gm2.flags() & Message::F_COMMIT) != 0);
|
|
- rb = get_msg(t2, &msg);
|
|
+ ck_assert(gm2->type() == Message::EVS_T_GAP);
|
|
+ ck_assert((gm2->flags() & Message::F_COMMIT) != 0);
|
|
+ rb = get_msg(t2, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
// Handle gap messages
|
|
// Expected output: Both nodes shift to S_INSTALL,
|
|
// both send gap messages
|
|
- p1->handle_msg(gm2);
|
|
+ p1->handle_msg(*gm2);
|
|
ck_assert(p1->state() == Proto::S_INSTALL);
|
|
- Message gm12;
|
|
- rb = get_msg(t1, &gm12);
|
|
+ std::unique_ptr<Message> gm12;
|
|
+ rb = get_msg(t1, gm12);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(gm12.type() == Message::EVS_T_GAP);
|
|
- ck_assert((gm12.flags() & Message::F_COMMIT) == 0);
|
|
- rb = get_msg(t1, &msg);
|
|
+ ck_assert(gm12->type() == Message::EVS_T_GAP);
|
|
+ ck_assert((gm12->flags() & Message::F_COMMIT) == 0);
|
|
+ rb = get_msg(t1, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
- p2->handle_msg(gm);
|
|
+ p2->handle_msg(*gm);
|
|
ck_assert(p2->state() == Proto::S_INSTALL);
|
|
- Message gm22;
|
|
- rb = get_msg(t2, &gm22);
|
|
+ std::unique_ptr<Message> gm22;
|
|
+ rb = get_msg(t2, gm22);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(gm22.type() == Message::EVS_T_GAP);
|
|
- ck_assert((gm22.flags() & Message::F_COMMIT) == 0);
|
|
- rb = get_msg(t2, &msg);
|
|
+ ck_assert(gm22->type() == Message::EVS_T_GAP);
|
|
+ ck_assert((gm22->flags() & Message::F_COMMIT) == 0);
|
|
+ rb = get_msg(t2, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
// Handle final gap messages, expected output shift to operational
|
|
// and gap message
|
|
|
|
- p1->handle_msg(gm22);
|
|
+ p1->handle_msg(*gm22);
|
|
ck_assert(p1->state() == Proto::S_OPERATIONAL);
|
|
- rb = get_msg(t1, &msg);
|
|
+ rb = get_msg(t1, msg);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(msg.type() == Message::EVS_T_GAP);
|
|
- ck_assert((msg.flags() & Message::F_COMMIT) == 0);
|
|
- rb = get_msg(t1, &msg);
|
|
+ ck_assert(msg->type() == Message::EVS_T_GAP);
|
|
+ ck_assert((msg->flags() & Message::F_COMMIT) == 0);
|
|
+ rb = get_msg(t1, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
- p2->handle_msg(gm12);
|
|
+ p2->handle_msg(*gm12);
|
|
ck_assert(p2->state() == Proto::S_OPERATIONAL);
|
|
- rb = get_msg(t2, &msg);
|
|
+ rb = get_msg(t2, msg);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(msg.type() == Message::EVS_T_GAP);
|
|
- ck_assert((msg.flags() & Message::F_COMMIT) == 0);
|
|
- rb = get_msg(t2, &msg);
|
|
+ ck_assert(msg->type() == Message::EVS_T_GAP);
|
|
+ ck_assert((msg->flags() & Message::F_COMMIT) == 0);
|
|
+ rb = get_msg(t2, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
}
|
|
@@ -2031,12 +2032,12 @@ START_TEST(test_gh_100)
|
|
// install message is generated. After that handle install timer
|
|
// on p1 and verify that the newly generated install message has
|
|
// greater install view id seqno than the first one.
|
|
- Message jm;
|
|
- Message im;
|
|
- Message im2;
|
|
- Message gm;
|
|
- Message gm2;
|
|
- Message msg;
|
|
+ std::unique_ptr<Message> jm;
|
|
+ std::unique_ptr<Message> im;
|
|
+ std::unique_ptr<Message> im2;
|
|
+ std::unique_ptr<Message> gm;
|
|
+ std::unique_ptr<Message> gm2;
|
|
+ std::unique_ptr<Message> msg;
|
|
|
|
Datagram* rb;
|
|
|
|
@@ -2049,56 +2050,56 @@ START_TEST(test_gh_100)
|
|
// Expected output: one join message
|
|
p2.send_join(false);
|
|
ck_assert(p2.state() == Proto::S_JOINING);
|
|
- rb = get_msg(&t2, &jm);
|
|
+ rb = get_msg(&t2, jm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(jm.type() == Message::EVS_T_JOIN);
|
|
- rb = get_msg(&t2, &msg);
|
|
+ ck_assert(jm->type() == Message::EVS_T_JOIN);
|
|
+ rb = get_msg(&t2, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
// Handle node 2's join on node 1
|
|
// Expected output: shift to S_GATHER and one join message
|
|
- p1.handle_msg(jm);
|
|
+ p1.handle_msg(*jm);
|
|
ck_assert(p1.state() == Proto::S_GATHER);
|
|
- rb = get_msg(&t1, &jm);
|
|
+ rb = get_msg(&t1, jm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(jm.type() == Message::EVS_T_JOIN);
|
|
- rb = get_msg(&t1, &msg);
|
|
+ ck_assert(jm->type() == Message::EVS_T_JOIN);
|
|
+ rb = get_msg(&t1, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
// Handle node 1's join on node 2
|
|
// Expected output: shift to S_GATHER and one join message
|
|
- p2.handle_msg(jm);
|
|
+ p2.handle_msg(*jm);
|
|
ck_assert(p2.state() == Proto::S_GATHER);
|
|
- rb = get_msg(&t2, &jm);
|
|
+ rb = get_msg(&t2, jm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(jm.type() == Message::EVS_T_JOIN);
|
|
- rb = get_msg(&t2, &msg);
|
|
+ ck_assert(jm->type() == Message::EVS_T_JOIN);
|
|
+ rb = get_msg(&t2, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
// Handle node 2's join on node 1
|
|
// Expected output: Install and commit gap messages, state stays in S_GATHER
|
|
- p1.handle_msg(jm);
|
|
+ p1.handle_msg(*jm);
|
|
ck_assert(p1.state() == Proto::S_GATHER);
|
|
- rb = get_msg(&t1, &im);
|
|
+ rb = get_msg(&t1, im);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(im.type() == Message::EVS_T_INSTALL);
|
|
- rb = get_msg(&t1, &gm);
|
|
+ ck_assert(im->type() == Message::EVS_T_INSTALL);
|
|
+ rb = get_msg(&t1, gm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(gm.type() == Message::EVS_T_GAP);
|
|
- ck_assert((gm.flags() & Message::F_COMMIT) != 0);
|
|
- rb = get_msg(&t1, &msg);
|
|
+ ck_assert(gm->type() == Message::EVS_T_GAP);
|
|
+ ck_assert((gm->flags() & Message::F_COMMIT) != 0);
|
|
+ rb = get_msg(&t1, msg);
|
|
ck_assert(rb == 0);
|
|
|
|
// Handle timers to to generate shift to GATHER
|
|
p1.handle_inactivity_timer();
|
|
p1.handle_install_timer();
|
|
- rb = get_msg(&t1, &jm);
|
|
+ rb = get_msg(&t1, jm);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(jm.type() == Message::EVS_T_JOIN);
|
|
- rb = get_msg(&t1, &im2);
|
|
+ ck_assert(jm->type() == Message::EVS_T_JOIN);
|
|
+ rb = get_msg(&t1, im2);
|
|
ck_assert(rb != 0);
|
|
- ck_assert(im2.type() == Message::EVS_T_INSTALL);
|
|
- ck_assert(im2.install_view_id().seq() > im.install_view_id().seq());
|
|
+ ck_assert(im2->type() == Message::EVS_T_INSTALL);
|
|
+ ck_assert(im2->install_view_id().seq() > im->install_view_id().seq());
|
|
|
|
gcomm::Datagram* tmp;
|
|
while ((tmp = t1.out())) delete tmp;
|
|
@@ -2195,14 +2196,14 @@ START_TEST(test_gal_521)
|
|
ck_assert(t2->empty() == false);
|
|
|
|
Datagram *d1;
|
|
- Message um1;
|
|
- ck_assert((d1 = get_msg(t1, &um1, false)) != 0);
|
|
- ck_assert(um1.type() == Message::EVS_T_USER);
|
|
+ std::unique_ptr<Message> um1;
|
|
+ ck_assert((d1 = get_msg(t1, um1, false)) != 0);
|
|
+ ck_assert(um1->type() == Message::EVS_T_USER);
|
|
ck_assert(t1->empty() == true);
|
|
Datagram *d2;
|
|
- Message um2;
|
|
- ck_assert((d2 = get_msg(t2, &um2, false)) != 0);
|
|
- ck_assert(um2.type() == Message::EVS_T_USER);
|
|
+ std::unique_ptr<Message> um2;
|
|
+ ck_assert((d2 = get_msg(t2, um2, false)) != 0);
|
|
+ ck_assert(um2->type() == Message::EVS_T_USER);
|
|
ck_assert(t2->empty() == true);
|
|
|
|
// Both of the nodes handle each other's messages. Now due to
|
|
@@ -2211,53 +2212,53 @@ START_TEST(test_gal_521)
|
|
// must emit gap messages to make safe_seq to progress.
|
|
evs1->handle_up(0, *d2, ProtoUpMeta(dn[1]->uuid()));
|
|
delete d2;
|
|
- Message gm1;
|
|
- ck_assert(get_msg(t1, &gm1) != 0);
|
|
- ck_assert(gm1.type() == Message::EVS_T_GAP);
|
|
+ std::unique_ptr<Message> gm1;
|
|
+ ck_assert(get_msg(t1, gm1) != 0);
|
|
+ ck_assert(gm1->type() == Message::EVS_T_GAP);
|
|
ck_assert(t1->empty() == true);
|
|
|
|
evs2->handle_up(0, *d1, ProtoUpMeta(dn[0]->uuid()));
|
|
delete d1;
|
|
- Message gm2;
|
|
- ck_assert(get_msg(t2, &gm2) != 0);
|
|
- ck_assert(gm2.type() == Message::EVS_T_GAP);
|
|
+ std::unique_ptr<Message> gm2;
|
|
+ ck_assert(get_msg(t2, gm2) != 0);
|
|
+ ck_assert(gm2->type() == Message::EVS_T_GAP);
|
|
ck_assert(t2->empty() == true);
|
|
|
|
// Handle gap messages. The safe_seq is now incremented so the
|
|
// second user messages are now sent from output queue.
|
|
- evs1->handle_msg(gm2);
|
|
- ck_assert((d1 = get_msg(t1, &um1, false)) != 0);
|
|
- ck_assert(um1.type() == Message::EVS_T_USER);
|
|
+ evs1->handle_msg(*gm2);
|
|
+ ck_assert((d1 = get_msg(t1, um1, false)) != 0);
|
|
+ ck_assert(um1->type() == Message::EVS_T_USER);
|
|
ck_assert(t1->empty() == true);
|
|
|
|
- evs2->handle_msg(gm1);
|
|
- ck_assert((d2 = get_msg(t2, &um2, false)) != 0);
|
|
- ck_assert(um2.type() == Message::EVS_T_USER);
|
|
+ evs2->handle_msg(*gm1);
|
|
+ ck_assert((d2 = get_msg(t2, um2, false)) != 0);
|
|
+ ck_assert(um2->type() == Message::EVS_T_USER);
|
|
ck_assert(t2->empty() == true);
|
|
|
|
// Handle user messages. Each node should now emit gap
|
|
// because the output queue is empty.
|
|
evs1->handle_up(0, *d2, ProtoUpMeta(dn[1]->uuid()));
|
|
delete d2;
|
|
- ck_assert(get_msg(t1, &gm1) != 0);
|
|
- ck_assert(gm1.type() == Message::EVS_T_GAP);
|
|
+ ck_assert(get_msg(t1, gm1) != 0);
|
|
+ ck_assert(gm1->type() == Message::EVS_T_GAP);
|
|
ck_assert(t1->empty() == true);
|
|
|
|
evs2->handle_up(0, *d1, ProtoUpMeta(dn[0]->uuid()));
|
|
delete d1;
|
|
- ck_assert(get_msg(t2, &gm2) != 0);
|
|
- ck_assert(gm2.type() == Message::EVS_T_GAP);
|
|
+ ck_assert(get_msg(t2, gm2) != 0);
|
|
+ ck_assert(gm2->type() == Message::EVS_T_GAP);
|
|
ck_assert(t2->empty() == true);
|
|
|
|
// Handle gap messages. No further messages should be emitted
|
|
// since both user messages have been delivered, there are
|
|
// no pending user messages in the output queue and no timers
|
|
// have been expired.
|
|
- evs1->handle_msg(gm2);
|
|
- ck_assert((d1 = get_msg(t1, &um1, false)) == 0);
|
|
+ evs1->handle_msg(*gm2);
|
|
+ ck_assert((d1 = get_msg(t1, um1, false)) == 0);
|
|
|
|
- evs2->handle_msg(gm1);
|
|
- ck_assert((d2 = get_msg(t2, &um2, false)) == 0);
|
|
+ evs2->handle_msg(*gm1);
|
|
+ ck_assert((d2 = get_msg(t2, um2, false)) == 0);
|
|
|
|
|
|
std::for_each(dn.begin(), dn.end(), DeleteObject());
|
|
@@ -2332,70 +2333,70 @@ START_TEST(test_gap_rate_limit)
|
|
// the rest are handled by node2 for generating gap messages.
|
|
f.evs1.handle_down(dg, ProtoDownMeta(O_SAFE));
|
|
gcomm::Datagram* read_dg;
|
|
- gcomm::evs::Message um1;
|
|
- read_dg = get_msg(&f.tr1, &um1);
|
|
+ std::unique_ptr<gcomm::evs::Message> um1;
|
|
+ read_dg = get_msg(&f.tr1, um1);
|
|
ck_assert(read_dg != 0);
|
|
f.evs1.handle_down(dg, ProtoDownMeta(O_SAFE));
|
|
- gcomm::evs::Message um2;
|
|
- read_dg = get_msg(&f.tr1, &um2);
|
|
+ std::unique_ptr<gcomm::evs::Message> um2;
|
|
+ read_dg = get_msg(&f.tr1, um2);
|
|
ck_assert(read_dg != 0);
|
|
f.evs1.handle_down(dg, ProtoDownMeta(O_SAFE));
|
|
- gcomm::evs::Message um3;
|
|
- read_dg = get_msg(&f.tr1, &um3);
|
|
+ std::unique_ptr<gcomm::evs::Message> um3;
|
|
+ read_dg = get_msg(&f.tr1, um3);
|
|
ck_assert(read_dg != 0);
|
|
f.evs1.handle_down(dg, ProtoDownMeta(O_SAFE));
|
|
- gcomm::evs::Message um4;
|
|
- read_dg = get_msg(&f.tr1, &um4);
|
|
+ std::unique_ptr<gcomm::evs::Message> um4;
|
|
+ read_dg = get_msg(&f.tr1, um4);
|
|
ck_assert(read_dg != 0);
|
|
|
|
// Make node2 handle an out of order message and verify that gap is emitted
|
|
- f.evs2.handle_msg(um2);
|
|
- gcomm::evs::Message gm1;
|
|
- read_dg = get_msg(&f.tr2, &gm1);
|
|
+ f.evs2.handle_msg(*um2);
|
|
+ std::unique_ptr<gcomm::evs::Message> gm1;
|
|
+ read_dg = get_msg(&f.tr2, gm1);
|
|
ck_assert(read_dg != 0);
|
|
- ck_assert(gm1.type() == gcomm::evs::Message::EVS_T_GAP);
|
|
- ck_assert(gm1.range_uuid() == f.uuid1);
|
|
- ck_assert(gm1.range().lu() == 0);
|
|
- ck_assert(gm1.range().hs() == 0);
|
|
+ ck_assert(gm1->type() == gcomm::evs::Message::EVS_T_GAP);
|
|
+ ck_assert(gm1->range_uuid() == f.uuid1);
|
|
+ ck_assert(gm1->range().lu() == 0);
|
|
+ ck_assert(gm1->range().hs() == 0);
|
|
// The node2 will also send an user message to complete the sequence
|
|
// number. Consume it.
|
|
- gcomm::evs::Message comp_um1;
|
|
- read_dg = get_msg(&f.tr2, &comp_um1);
|
|
+ std::unique_ptr<gcomm::evs::Message> comp_um1;
|
|
+ read_dg = get_msg(&f.tr2, comp_um1);
|
|
ck_assert(read_dg != 0);
|
|
- ck_assert(comp_um1.type() == gcomm::evs::Message::EVS_T_USER);
|
|
- ck_assert(comp_um1.seq() + comp_um1.seq_range() == 1);
|
|
+ ck_assert(comp_um1->type() == gcomm::evs::Message::EVS_T_USER);
|
|
+ ck_assert(comp_um1->seq() + comp_um1->seq_range() == 1);
|
|
// No further messages should be emitted
|
|
- read_dg = get_msg(&f.tr2, &comp_um1);
|
|
+ read_dg = get_msg(&f.tr2, comp_um1);
|
|
ck_assert(read_dg == 0);
|
|
|
|
// Handle the second out of order message, gap should not be emitted.
|
|
// There will be a next user message which completes the um3.
|
|
- f.evs2.handle_msg(um3);
|
|
- gcomm::evs::Message comp_um2;
|
|
- read_dg = get_msg(&f.tr2, &comp_um2);
|
|
+ f.evs2.handle_msg(*um3);
|
|
+ std::unique_ptr<gcomm::evs::Message> comp_um2;
|
|
+ read_dg = get_msg(&f.tr2, comp_um2);
|
|
ck_assert(read_dg != 0);
|
|
- ck_assert(comp_um2.type() == gcomm::evs::Message::EVS_T_USER);
|
|
- ck_assert(comp_um2.seq() + comp_um2.seq_range() == 2);
|
|
+ ck_assert(comp_um2->type() == gcomm::evs::Message::EVS_T_USER);
|
|
+ ck_assert(comp_um2->seq() + comp_um2->seq_range() == 2);
|
|
|
|
// There should not be any more gap messages.
|
|
- read_dg = get_msg(&f.tr2, &gm1);
|
|
+ read_dg = get_msg(&f.tr2, gm1);
|
|
ck_assert(read_dg == 0);
|
|
|
|
// Move the clock forwards and handle the fourth message, gap should
|
|
// now emitted.
|
|
gu::datetime::SimClock::inc_time(100*gu::datetime::MSec);
|
|
- gcomm::evs::Message gm2;
|
|
- f.evs2.handle_msg(um4);
|
|
- read_dg = get_msg(&f.tr2, &gm2);
|
|
+ std::unique_ptr<gcomm::evs::Message> gm2;
|
|
+ f.evs2.handle_msg(*um4);
|
|
+ read_dg = get_msg(&f.tr2, gm2);
|
|
ck_assert(read_dg != 0);
|
|
- ck_assert(gm2.type() == gcomm::evs::Message::EVS_T_GAP);
|
|
- ck_assert(gm2.range().lu() == 0);
|
|
- ck_assert(gm2.range().hs() == 0);
|
|
+ ck_assert(gm2->type() == gcomm::evs::Message::EVS_T_GAP);
|
|
+ ck_assert(gm2->range().lu() == 0);
|
|
+ ck_assert(gm2->range().hs() == 0);
|
|
|
|
- gcomm::evs::Message comp_u4;
|
|
- read_dg = get_msg(&f.tr2, &comp_u4);
|
|
+ std::unique_ptr<gcomm::evs::Message> comp_u4;
|
|
+ read_dg = get_msg(&f.tr2, comp_u4);
|
|
ck_assert(read_dg != 0);
|
|
- ck_assert(comp_u4.type() == gcomm::evs::Message::EVS_T_USER);
|
|
+ ck_assert(comp_u4->type() == gcomm::evs::Message::EVS_T_USER);
|
|
log_info << "END test_gap_rate_limit";
|
|
}
|
|
END_TEST
|
|
@@ -2427,75 +2428,75 @@ START_TEST(test_gap_rate_limit_delayed)
|
|
// the rest are handled by node2 for generating gap messages.
|
|
f.evs1.handle_down(dg, ProtoDownMeta(O_SAFE));
|
|
gcomm::Datagram* read_dg;
|
|
- gcomm::evs::Message um1;
|
|
- read_dg = get_msg(&f.tr1, &um1);
|
|
+ std::unique_ptr<gcomm::evs::Message> um1;
|
|
+ read_dg = get_msg(&f.tr1, um1);
|
|
ck_assert(read_dg != 0);
|
|
f.evs1.handle_down(dg, ProtoDownMeta(O_SAFE));
|
|
- gcomm::evs::Message um2;
|
|
- read_dg = get_msg(&f.tr1, &um2);
|
|
+ std::unique_ptr<gcomm::evs::Message> um2;
|
|
+ read_dg = get_msg(&f.tr1, um2);
|
|
ck_assert(read_dg != 0);
|
|
f.evs1.handle_down(dg, ProtoDownMeta(O_SAFE));
|
|
- gcomm::evs::Message um3;
|
|
- read_dg = get_msg(&f.tr1, &um3);
|
|
+ std::unique_ptr<gcomm::evs::Message> um3;
|
|
+ read_dg = get_msg(&f.tr1, um3);
|
|
ck_assert(read_dg != 0);
|
|
f.evs1.handle_down(dg, ProtoDownMeta(O_SAFE));
|
|
- gcomm::evs::Message um4;
|
|
- read_dg = get_msg(&f.tr1, &um4);
|
|
+ std::unique_ptr<gcomm::evs::Message> um4;
|
|
+ read_dg = get_msg(&f.tr1, um4);
|
|
ck_assert(read_dg != 0);
|
|
|
|
// Make node2 handle an out of order message and verify that gap is emitted
|
|
- f.evs2.handle_msg(um2);
|
|
- gcomm::evs::Message gm1;
|
|
- read_dg = get_msg(&f.tr2, &gm1);
|
|
+ f.evs2.handle_msg(*um2);
|
|
+ std::unique_ptr<gcomm::evs::Message> gm1;
|
|
+ read_dg = get_msg(&f.tr2, gm1);
|
|
ck_assert(read_dg != 0);
|
|
- ck_assert(gm1.type() == gcomm::evs::Message::EVS_T_GAP);
|
|
- ck_assert(gm1.range_uuid() == f.uuid1);
|
|
- ck_assert(gm1.range().lu() == 0);
|
|
- ck_assert(gm1.range().hs() == 0);
|
|
+ ck_assert(gm1->type() == gcomm::evs::Message::EVS_T_GAP);
|
|
+ ck_assert(gm1->range_uuid() == f.uuid1);
|
|
+ ck_assert(gm1->range().lu() == 0);
|
|
+ ck_assert(gm1->range().hs() == 0);
|
|
// The node2 will also send an user message to complete the sequence
|
|
// number. Consume it.
|
|
- gcomm::evs::Message comp_um1;
|
|
- read_dg = get_msg(&f.tr2, &comp_um1);
|
|
+ std::unique_ptr<gcomm::evs::Message> comp_um1;
|
|
+ read_dg = get_msg(&f.tr2, comp_um1);
|
|
ck_assert(read_dg != 0);
|
|
- ck_assert(comp_um1.type() == gcomm::evs::Message::EVS_T_USER);
|
|
- ck_assert(comp_um1.seq() + comp_um1.seq_range() == 1);
|
|
+ ck_assert(comp_um1->type() == gcomm::evs::Message::EVS_T_USER);
|
|
+ ck_assert(comp_um1->seq() + comp_um1->seq_range() == 1);
|
|
// No further messages should be emitted
|
|
- read_dg = get_msg(&f.tr2, &comp_um1);
|
|
+ read_dg = get_msg(&f.tr2, comp_um1);
|
|
ck_assert(read_dg == 0);
|
|
|
|
// Move time forwards in 1 sec interval and make inactivity check
|
|
// in between. No gap messages should be emitted.
|
|
gu::datetime::SimClock::inc_time(gu::datetime::Sec);
|
|
f.evs2.handle_inactivity_timer();
|
|
- gcomm::evs::Message gm_discard;
|
|
- read_dg = get_msg(&f.tr2, &gm_discard);
|
|
+ std::unique_ptr<gcomm::evs::Message> gm_discard;
|
|
+ read_dg = get_msg(&f.tr2, gm_discard);
|
|
ck_assert(read_dg == 0);
|
|
// The clock is now advanced over retrans_period + delay margin. Next
|
|
// call to handle_inactivity_timer() should fire the check. Gap message
|
|
// is emitted.
|
|
gu::datetime::SimClock::inc_time(gu::datetime::Sec);
|
|
f.evs2.handle_inactivity_timer();
|
|
- read_dg = get_msg(&f.tr2, &gm1);
|
|
+ read_dg = get_msg(&f.tr2, gm1);
|
|
ck_assert(read_dg != 0);
|
|
- ck_assert(gm1.type() == gcomm::evs::Message::EVS_T_GAP);
|
|
+ ck_assert(gm1->type() == gcomm::evs::Message::EVS_T_GAP);
|
|
// Now call handle_inactivity_timer() again, gap message should not
|
|
// be emitted due to rate limit.
|
|
// Galera 4 will run with evs protocol version 1 and will emit
|
|
// delayed list at this point.
|
|
f.evs2.handle_inactivity_timer();
|
|
- gcomm::evs::Message dm;
|
|
- read_dg = get_msg(&f.tr2, &dm);
|
|
+ std::unique_ptr<gcomm::evs::Message> dm;
|
|
+ read_dg = get_msg(&f.tr2, dm);
|
|
ck_assert(read_dg != 0);
|
|
- ck_assert(dm.type() == gcomm::evs::Message::EVS_T_DELAYED_LIST);
|
|
- read_dg = get_msg(&f.tr2, &gm_discard);
|
|
+ ck_assert(dm->type() == gcomm::evs::Message::EVS_T_DELAYED_LIST);
|
|
+ read_dg = get_msg(&f.tr2, gm_discard);
|
|
ck_assert(read_dg == 0);
|
|
// Move clock forward 100msec, new gap should be now emitted.
|
|
gu::datetime::SimClock::inc_time(100*gu::datetime::MSec);
|
|
f.evs2.handle_inactivity_timer();
|
|
- gcomm::evs::Message gm2;
|
|
- read_dg = get_msg(&f.tr2, &gm2);
|
|
+ std::unique_ptr<gcomm::evs::Message> gm2;
|
|
+ read_dg = get_msg(&f.tr2, gm2);
|
|
ck_assert(read_dg != 0);
|
|
- ck_assert(gm2.type() == gcomm::evs::Message::EVS_T_GAP);
|
|
+ ck_assert(gm2->type() == gcomm::evs::Message::EVS_T_GAP);
|
|
log_info << "END test_gap_rate_limit_delayed";
|
|
|
|
gcomm::Datagram* tmp;
|
|
--- a/gcomm/test/check_trace.hpp
|
|
+++ b/gcomm/test/check_trace.hpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (C) 2009-2014 Codership Oy <info@codership.com>
|
|
+ * Copyright (C) 2009-2023 Codership Oy <info@codership.com>
|
|
*
|
|
* $Id$
|
|
*/
|
|
@@ -173,7 +173,7 @@ namespace gcomm
|
|
std::deque<Datagram*> out_;
|
|
bool queue_;
|
|
static std::unique_ptr<Protonet> net_;
|
|
- Protonet& get_net();
|
|
+ static Protonet& get_net();
|
|
public:
|
|
|
|
DummyTransport(const UUID& uuid = UUID::nil(), bool queue = true,
|
|
--- a/galerautils/tests/CMakeLists.txt
|
|
+++ b/galerautils/tests/CMakeLists.txt
|
|
@@ -47,7 +47,6 @@ add_test(
|
|
#
|
|
# C++ galerautils tests.
|
|
#
|
|
-
|
|
add_executable(gu_tests++
|
|
gu_atomic_test.cpp
|
|
gu_gtid_test.cpp
|
|
@@ -75,7 +74,7 @@ add_executable(gu_tests++
|
|
|
|
target_compile_definitions(gu_tests++
|
|
PRIVATE
|
|
- -DGU_ASIO_TEST_CERT_DIR="${PROJECT_SOURCE_DIR}/tests/conf")
|
|
+ -DGU_ASIO_TEST_CERT_DIR="${CMAKE_CURRENT_BINARY_DIR}/certs")
|
|
|
|
# TODO: These should be eventually fixed.
|
|
target_compile_options(gu_tests++
|
|
@@ -93,7 +92,6 @@ add_test(
|
|
NAME gu_tests++
|
|
COMMAND gu_tests++
|
|
)
|
|
-
|
|
#
|
|
# Deqmap micro benchmark.
|
|
#
|
|
--- a/galerautils/tests/gu_asio_test.cpp
|
|
+++ b/galerautils/tests/gu_asio_test.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (C) 2019-2020 Codership Oy <info@codership.com>
|
|
+ * Copyright (C) 2019-2023 Codership Oy <info@codership.com>
|
|
*/
|
|
|
|
|
|
@@ -920,18 +920,276 @@ END_TEST
|
|
|
|
#ifdef GALERA_HAVE_SSL
|
|
|
|
+#include <openssl/bn.h>
|
|
+#include <openssl/conf.h>
|
|
+#include <openssl/engine.h>
|
|
+#include <openssl/pem.h>
|
|
+#include <openssl/x509v3.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/types.h>
|
|
+#include <dirent.h>
|
|
#include <signal.h>
|
|
|
|
-//
|
|
-// SSL
|
|
-//
|
|
+#include <vector>
|
|
|
|
static std::string get_cert_dir()
|
|
{
|
|
- // This will be set by CMake/preprocessor.
|
|
+ static_assert(::strlen(GU_ASIO_TEST_CERT_DIR) > 0);
|
|
+ const std::string ret{ GU_ASIO_TEST_CERT_DIR };
|
|
+ auto* dir = opendir(ret.c_str());
|
|
+ if (!dir)
|
|
+ {
|
|
+ if (mkdir(ret.c_str(), S_IRWXU))
|
|
+ {
|
|
+ const auto* errstr = ::strerror(errno);
|
|
+ gu_throw_fatal << "Could not create dir " << ret << ": " << errstr;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ closedir(dir);
|
|
+ }
|
|
return GU_ASIO_TEST_CERT_DIR;
|
|
}
|
|
|
|
+static int password_cb(char*, int, int, void*) { return 0; }
|
|
+
|
|
+static void throw_error(const char* msg)
|
|
+{
|
|
+ gu_throw_fatal << msg << ": " << ERR_error_string(ERR_get_error(), nullptr);
|
|
+}
|
|
+
|
|
+static EVP_PKEY* create_key()
|
|
+{
|
|
+#if OPENSSL_VERSION_MAJOR < 3
|
|
+ auto* bn = BN_new();
|
|
+ if (!bn)
|
|
+ {
|
|
+ throw_error("could not create BN");
|
|
+ }
|
|
+ BN_set_word(bn, 0x10001);
|
|
+ auto* rsa = RSA_new();
|
|
+ if (!rsa)
|
|
+ {
|
|
+ BN_free(bn);
|
|
+ throw_error("could not create RSA");
|
|
+ }
|
|
+ RSA_generate_key_ex(rsa, 2048, bn, nullptr);
|
|
+ auto* pkey = EVP_PKEY_new();
|
|
+ if (!pkey)
|
|
+ {
|
|
+ BN_free(bn);
|
|
+ RSA_free(rsa);
|
|
+ throw_error("could not create PKEY");
|
|
+ }
|
|
+ EVP_PKEY_set1_RSA(pkey, rsa);
|
|
+ RSA_free(rsa);
|
|
+ BN_free(bn);
|
|
+ return pkey;
|
|
+#else
|
|
+ auto* ret = EVP_RSA_gen(2048);
|
|
+ if (!ret)
|
|
+ {
|
|
+ throw_error("could not create RSA");
|
|
+ }
|
|
+ return ret;
|
|
+#endif /* OPENSSL_VERSION_MAJOR < 3 */
|
|
+}
|
|
+
|
|
+static FILE* open_file(const std::string& path, const char* mode)
|
|
+{
|
|
+ auto* ret = fopen(path.c_str(), mode);
|
|
+ if (!ret)
|
|
+ {
|
|
+ const auto* errstr = ::strerror(errno);
|
|
+ gu_throw_fatal << "Could not open file " << path << ": "
|
|
+ << errstr;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void write_key(EVP_PKEY* pkey, const std::string& filename)
|
|
+{
|
|
+ const std::string cert_dir = get_cert_dir();
|
|
+ const std::string key_file_path = cert_dir + "/" + filename;
|
|
+ auto* key_file = open_file(key_file_path, "wb");
|
|
+ if (!PEM_write_PrivateKey(key_file, pkey, nullptr, nullptr, 0, password_cb,
|
|
+ nullptr))
|
|
+ {
|
|
+ throw_error("Could not write key");
|
|
+ }
|
|
+ fclose(key_file);
|
|
+}
|
|
+
|
|
+static void set_x509v3_extensions(X509* x509, X509* issuer)
|
|
+{
|
|
+ auto* conf_bio = BIO_new(BIO_s_mem());
|
|
+ std::string ext{ "[extensions]\n"
|
|
+ "authorityKeyIdentifier=keyid,issuer\n"
|
|
+ "subjectKeyIdentifier=hash\n" };
|
|
+ if (!issuer)
|
|
+ {
|
|
+ ext += "basicConstraints=critical,CA:TRUE\n";
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ext += "keyUsage=digitalSignature,keyEncipherment\n";
|
|
+ ext += "basicConstraints=CA:FALSE\n";
|
|
+ }
|
|
+ BIO_printf(conf_bio, "%s", ext.c_str());
|
|
+ auto* conf = NCONF_new(nullptr);
|
|
+ long errorline = -1;
|
|
+ int err;
|
|
+ if ((err = NCONF_load_bio(conf, conf_bio, &errorline)) <= 0)
|
|
+ {
|
|
+ gu_throw_fatal << "Could not load conf: " << err;
|
|
+ }
|
|
+ if (errorline != -1)
|
|
+ {
|
|
+ gu_throw_fatal << "Could not load conf, errorline: " << errorline;
|
|
+ }
|
|
+ // TODO: V3 extensions
|
|
+ X509V3_CTX ctx;
|
|
+ X509V3_set_ctx(&ctx, issuer ? issuer : x509, x509, nullptr, nullptr, 0);
|
|
+ X509V3_set_nconf(&ctx, conf);
|
|
+ if (!X509V3_EXT_add_nconf(conf, &ctx, "extensions", x509))
|
|
+ {
|
|
+ throw_error("Could not add extension");
|
|
+ }
|
|
+ NCONF_free(conf);
|
|
+ BIO_free(conf_bio);
|
|
+}
|
|
+
|
|
+static X509* create_x509(EVP_PKEY* pkey, X509* issuer, const char* cn)
|
|
+{
|
|
+ auto* x509 = X509_new();
|
|
+ /* According to standard, value 2 means version 3. */
|
|
+ X509_set_version(x509, 2);
|
|
+ ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
|
|
+ X509_gmtime_adj(X509_get_notBefore(x509), 0);
|
|
+ X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);
|
|
+ X509_set_pubkey(x509, pkey);
|
|
+
|
|
+ auto* name = X509_get_subject_name(x509);
|
|
+ X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, reinterpret_cast<const unsigned char*>("FI"),
|
|
+ -1, -1, 0);
|
|
+ X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC,
|
|
+ reinterpret_cast<const unsigned char*>("Uusimaa"), -1, -1, 0);
|
|
+ X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC,
|
|
+ reinterpret_cast<const unsigned char*>("Helsinki"), -1, -1, 0);
|
|
+ X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
|
|
+ reinterpret_cast<const unsigned char*>("Codership"), -1, -1, 0);
|
|
+ X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC,
|
|
+ reinterpret_cast<const unsigned char*>("Galera Devel"), -1, -1, 0);
|
|
+ X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, reinterpret_cast<const unsigned char*>(cn), -1,
|
|
+ -1, 0);
|
|
+ if (!issuer)
|
|
+ {
|
|
+ /* Self signed */
|
|
+ X509_set_issuer_name(x509, name);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ X509_set_issuer_name(x509, X509_get_subject_name(issuer));
|
|
+ }
|
|
+
|
|
+ set_x509v3_extensions(x509, issuer);
|
|
+
|
|
+ X509_sign(x509, pkey, EVP_sha256());
|
|
+
|
|
+ return x509;
|
|
+}
|
|
+
|
|
+static void write_x509(X509* x509, const std::string& filename)
|
|
+{
|
|
+ const std::string cert_dir = get_cert_dir();
|
|
+ const std::string file_path = cert_dir + "/" + filename;
|
|
+ auto* file = open_file(file_path, "wb");
|
|
+ if (!PEM_write_X509(file, x509))
|
|
+ {
|
|
+ throw_error("Could not write x509");
|
|
+ }
|
|
+ fclose(file);
|
|
+}
|
|
+
|
|
+static void write_x509_list(const std::vector<X509*>& certs,
|
|
+ const std::string& filename)
|
|
+{
|
|
+ const std::string cert_dir = get_cert_dir();
|
|
+ const std::string file_path = cert_dir + "/" + filename;
|
|
+ auto* file = open_file(file_path, "wb");
|
|
+ for (auto* x509 : certs)
|
|
+ {
|
|
+ if (!PEM_write_X509(file, x509))
|
|
+ {
|
|
+ throw_error("Could not write x509");
|
|
+ }
|
|
+ }
|
|
+ fclose(file);
|
|
+}
|
|
+
|
|
+/* Self signed CA + certificate */
|
|
+static void generate_self_signed()
|
|
+{
|
|
+ auto* pkey = create_key();
|
|
+ write_key(pkey, "galera_key.pem");
|
|
+ auto* ca = create_x509(pkey, nullptr, "Galera Root");
|
|
+ write_x509(ca, "galera_ca.pem");
|
|
+
|
|
+ auto* cert = create_x509(pkey, ca, "Galera Cert");
|
|
+ write_x509(cert, "galera_cert.pem");
|
|
+ X509_free(cert);
|
|
+ X509_free(ca);
|
|
+ EVP_PKEY_free(pkey);
|
|
+}
|
|
+
|
|
+/*
|
|
+ ---- Server cert 1
|
|
+ /
|
|
+ Root CA - Intermediate CA
|
|
+ \---- Server cert 2
|
|
+
|
|
+ Two bundles consisting of intermediate CA and server certificate
|
|
+ are created for servers 1 and 2.
|
|
+ */
|
|
+static void generate_chains()
|
|
+{
|
|
+ auto* root_ca_key = create_key();
|
|
+ auto* root_ca = create_x509(root_ca_key, nullptr, "Galera Root CA");
|
|
+ auto* int_ca_key = create_key();
|
|
+ auto* int_ca = create_x509(int_ca_key, root_ca, "Galera Intermediate CA");
|
|
+
|
|
+ auto* server_1_key = create_key();
|
|
+ auto* server_1_cert = create_x509(server_1_key, int_ca, "Galera Server 1");
|
|
+ auto* server_2_key = create_key();
|
|
+ auto* server_2_cert = create_x509(server_2_key, int_ca, "Galera Server 2");
|
|
+
|
|
+ write_x509(root_ca, "galera-ca.pem");
|
|
+ write_key(server_1_key, "galera-server-1.key");
|
|
+ write_x509_list({ server_1_cert, int_ca }, "bundle-galera-server-1.pem");
|
|
+ write_key(server_2_key, "galera-server-2.key");
|
|
+ write_x509_list({ server_2_cert, int_ca }, "bundle-galera-server-2.pem");
|
|
+
|
|
+ X509_free(server_2_cert);
|
|
+ EVP_PKEY_free(server_2_key);
|
|
+ X509_free(server_1_cert);
|
|
+ EVP_PKEY_free(server_1_key);
|
|
+ X509_free(int_ca);
|
|
+ EVP_PKEY_free(int_ca_key);
|
|
+ X509_free(root_ca);
|
|
+ EVP_PKEY_free(root_ca_key);
|
|
+}
|
|
+
|
|
+static void generate_certificates()
|
|
+{
|
|
+ generate_self_signed();
|
|
+ generate_chains();
|
|
+}
|
|
+
|
|
+//
|
|
+// SSL
|
|
+//
|
|
+
|
|
static gu::Config get_ssl_config()
|
|
{
|
|
gu::Config ret;
|
|
@@ -1834,6 +2092,20 @@ END_TEST
|
|
// Datagram
|
|
//
|
|
|
|
+/* Helper to determine if UDP sockets can be opened. */
|
|
+static bool have_datagram() try
|
|
+{
|
|
+ gu::AsioIoService io_service;
|
|
+ gu::URI uri("udp://127.0.0.1:0");
|
|
+ auto socket(io_service.make_datagram_socket(uri));
|
|
+ socket->open(uri);
|
|
+ return true;
|
|
+}
|
|
+catch (...)
|
|
+{
|
|
+ return false;
|
|
+}
|
|
+
|
|
class MockDatagramSocketHandler : public gu::AsioDatagramSocketHandler
|
|
{
|
|
public:
|
|
@@ -2173,6 +2445,7 @@ Suite* gu_asio_suite()
|
|
//
|
|
// SSL
|
|
//
|
|
+ generate_certificates();
|
|
|
|
tc = tcase_create("test_ssl_io_service");
|
|
tcase_add_test(tc, test_ssl_io_service);
|
|
@@ -2339,6 +2612,7 @@ Suite* gu_asio_suite()
|
|
//
|
|
// Datagram
|
|
//
|
|
+ if (have_datagram()) {
|
|
|
|
tc = tcase_create("test_datagram_socket");
|
|
tcase_add_test(tc, test_datagram_socket);
|
|
@@ -2360,6 +2634,7 @@ Suite* gu_asio_suite()
|
|
tcase_add_test(tc, test_datagram_send_to_and_async_read);
|
|
suite_add_tcase(s, tc);
|
|
|
|
+ }
|
|
#if defined(GALERA_ASIO_TEST_MULTICAST)
|
|
tc = tcase_create("test_datagram_connect_multicast");
|
|
tcase_add_test(tc, test_datagram_connect_multicast);
|
|
--- a/galera/src/CMakeLists.txt
|
|
+++ b/galera/src/CMakeLists.txt
|
|
@@ -127,7 +127,7 @@ endif()
|
|
if (GALERA_VERSION_SCRIPT)
|
|
add_custom_command(TARGET galera_smm POST_BUILD
|
|
COMMAND
|
|
- sh -c "! ${CMAKE_OBJDUMP} -T libgalera_smm.so | grep asio 1> /dev/null"
|
|
+ sh -c "! ${CMAKE_OBJDUMP} -T libgalera_smm.so | grep asio"
|
|
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
|
|
COMMENT "Checking library symbol visibility (hidden)"
|
|
VERBATIM)
|
|
@@ -135,7 +135,7 @@ else()
|
|
set(GALERA_LINK_OPTIONS "")
|
|
add_custom_command(TARGET galera_smm POST_BUILD
|
|
COMMAND
|
|
- sh -c "${CMAKE_OBJDUMP} -T libgalera_smm.so | grep asio 1> /dev/null"
|
|
+ sh -c "${CMAKE_OBJDUMP} -T libgalera_smm.so | grep asio"
|
|
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
|
|
COMMENT "Checking library symbol visibility (not hidden)"
|
|
VERBATIM)
|
|
@@ -145,7 +145,7 @@ if (NOT GALERA_WITH_SSL)
|
|
message(STATUS "Building Galera without SSL")
|
|
add_custom_command(TARGET galera_smm POST_BUILD
|
|
COMMAND
|
|
- sh -c "! (${CMAKE_OBJDUMP} -x libgalera_smm.so | grep NEEDED.*crypto 1> /dev/null) && ! (${CMAKE_OBJDUMP} -x libgalera_smm.so | grep NEEDED.*ssl 1> /dev/null)"
|
|
+ sh -c "! (${CMAKE_OBJDUMP} -x libgalera_smm.so | grep NEEDED.*crypto) && ! (${CMAKE_OBJDUMP} -x libgalera_smm.so | grep NEEDED.*ssl)"
|
|
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
|
|
COMMENT "Verifying that library is not linked with SSL"
|
|
VERBATIM)
|
|
@@ -154,7 +154,7 @@ else()
|
|
message(STATUS "Building Galera with static SSL")
|
|
add_custom_command(TARGET galera_smm POST_BUILD
|
|
COMMAND
|
|
- sh -c "(${CMAKE_OBJDUMP} -t libgalera_smm.so | grep OPENSSL 1> /dev/null) && (${CMAKE_OBJDUMP} -t libgalera_smm.so | grep CRYPTO 1> /dev/null)"
|
|
+ sh -c "(${CMAKE_OBJDUMP} -t libgalera_smm.so | grep OPENSSL) && (${CMAKE_OBJDUMP} -t libgalera_smm.so | grep CRYPTO)"
|
|
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
|
|
COMMENT "Verifying that library has OpenSSL linked statically"
|
|
VERBATIM)
|
|
@@ -162,7 +162,7 @@ else()
|
|
message(STATUS "Building Galera with SSL")
|
|
add_custom_command(TARGET galera_smm POST_BUILD
|
|
COMMAND
|
|
- sh -c "(${CMAKE_OBJDUMP} -x libgalera_smm.so | grep NEEDED.*crypto 1> /dev/null) && (${CMAKE_OBJDUMP} -x libgalera_smm.so | grep NEEDED.*ssl 1> /dev/null)"
|
|
+ sh -c "(${CMAKE_OBJDUMP} -x libgalera_smm.so | grep NEEDED.*crypto) && (${CMAKE_OBJDUMP} -x libgalera_smm.so | grep NEEDED.*ssl)"
|
|
COMMENT "Verifying that library is linked with SSL"
|
|
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
|
|
VERBATIM)
|