diff --git a/Apply-upstream-patches-from-codership-galera-558.patch b/Apply-upstream-patches-from-codership-galera-558.patch deleted file mode 100644 index d9e25223bda87318086efc69cec5cb2669b063ad..0000000000000000000000000000000000000000 --- a/Apply-upstream-patches-from-codership-galera-558.patch +++ /dev/null @@ -1,1965 +0,0 @@ -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 -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 -+# Copyright (C) 2020-2023 Codership Oy - # - - 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 -+ 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 -+# Copyright (C) 2020-2023 Codership Oy - # - # 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 -+/* Copyright (C) 2013-2023 Codership Oy - * - * $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 -+// Copyright (C) 2018-2023 Codership Oy - // - - #include -@@ -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 -+ * Copyright (C) 2020-2023 Codership Oy - */ - - /** -@@ -19,33 +19,77 @@ - #include - #include - -+/* 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 -+// Copyright (C) 2010-2023 Codership Oy - - /** - * @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(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(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 -+ * Copyright (C) 2009-2023 Codership Oy - * - * $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((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 -+ * Copyright (C) 2009-2023 Codership Oy - */ - - #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 -+ * Copyright (C) 2009-2023 Codership Oy - */ - - #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, 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 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(*msg).unserialize( -- begin, available, offset, true)); -+ ret = std::unique_ptr(new UserMessage); -+ gu_trace(offset = ret->unserialize(begin, available, offset)); - break; - case Message::EVS_T_DELEGATE: -- gu_trace(offset = static_cast(*msg).unserialize( -- begin, available, offset, true)); -+ ret = std::unique_ptr(new DelegateMessage); -+ gu_trace(offset = ret->unserialize(begin, available, offset)); - break; - case Message::EVS_T_GAP: -- gu_trace(offset = static_cast(*msg).unserialize( -- begin, available, offset, true)); -+ ret = std::unique_ptr(new GapMessage); -+ gu_trace(offset = ret->unserialize(begin, available, offset)); - break; - case Message::EVS_T_JOIN: -- gu_trace(offset = static_cast(*msg).unserialize( -- begin, available, offset, true)); -+ ret = std::unique_ptr(new JoinMessage); -+ gu_trace(offset = ret->unserialize(begin, available, offset)); - break; - case Message::EVS_T_INSTALL: -- gu_trace(offset = static_cast(*msg).unserialize( -- begin, available, offset, true)); -+ ret = std::unique_ptr(new InstallMessage); -+ gu_trace(offset = ret->unserialize(begin, available, offset)); - break; - case Message::EVS_T_LEAVE: -- gu_trace(offset = static_cast(*msg).unserialize( -- begin, available, offset, true)); -+ ret = std::unique_ptr(new LeaveMessage); -+ gu_trace(offset = ret->unserialize(begin, available, offset)); - break; - case Message::EVS_T_DELAYED_LIST: -- gu_trace(offset = static_cast(*msg).unserialize( -- begin, available, offset, true)); -+ ret = std::unique_ptr(new DelayedListMessage); -+ gu_trace(offset = ret->unserialize(begin, available, offset)); - break; -+ default: -+ return {std::unique_ptr{}, 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, 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, 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 -+ * Copyright (C) 2009-2023 Codership Oy - */ - - /*! -@@ -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, 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 -+ * Copyright (C) 2009-2023 Codership Oy - */ - - /*! -@@ -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& 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 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 jm; -+ std::unique_ptr im; -+ std::unique_ptr gm; -+ std::unique_ptr gm2; -+ std::unique_ptr 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 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 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 jm; -+ std::unique_ptr im; -+ std::unique_ptr im2; -+ std::unique_ptr gm; -+ std::unique_ptr gm2; -+ std::unique_ptr 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 -+ * Copyright (C) 2009-2023 Codership Oy - * - * $Id$ - */ -@@ -173,7 +173,7 @@ namespace gcomm - std::deque out_; - bool queue_; - static std::unique_ptr 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 -+ * Copyright (C) 2019-2023 Codership Oy - */ - - -@@ -920,18 +920,276 @@ END_TEST - - #ifdef GALERA_HAVE_SSL - -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include - #include - --// --// SSL --// -+#include - - 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("FI"), -+ -1, -1, 0); -+ X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC, -+ reinterpret_cast("Uusimaa"), -1, -1, 0); -+ X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC, -+ reinterpret_cast("Helsinki"), -1, -1, 0); -+ X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, -+ reinterpret_cast("Codership"), -1, -1, 0); -+ X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, -+ reinterpret_cast("Galera Devel"), -1, -1, 0); -+ X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, reinterpret_cast(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& 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) diff --git a/cmake_paths.patch b/cmake_paths.patch new file mode 100644 index 0000000000000000000000000000000000000000..ec4f06a80ba512218db0f0cbaf0da36faa46f3f2 --- /dev/null +++ b/cmake_paths.patch @@ -0,0 +1,119 @@ +This patch has been offered upstream with slight typo fixes: + https://github.com/codership/galera/pull/614 +on 21/02/2022 + +#---------------------- + + +1) Documentation files + +--- galera-26.4.11/CMakeLists.txt 2022-02-20 03:35:32.039968825 +0100 ++++ galera-26.4.11/CMakeLists.txt_patched 2022-02-20 03:34:57.710641631 +0100 +@@ -109,14 +109,19 @@ add_subdirectory(galera) + add_subdirectory(scripts/packages) + add_subdirectory(wsrep/tests) + ++# Make the intall destination for documentation files configurable ++if(NOT DEFINED INSTALL_DOCDIR) ++ set(INSTALL_DOCDIR "doc" CACHE STRING "path to install documentaion to") ++endif() ++ + if (NOT ${CMAKE_SYSTEM_NAME} MATCHES ".*BSD") + install(FILES + ${PROJECT_SOURCE_DIR}/AUTHORS + ${PROJECT_SOURCE_DIR}/COPYING + ${PROJECT_SOURCE_DIR}/README +- DESTINATION doc) ++ DESTINATION ${INSTALL_DOCDIR} ) + install(FILES ${PROJECT_SOURCE_DIR}/asio/LICENSE_1_0.txt +- DESTINATION doc ++ DESTINATION ${INSTALL_DOCDIR} + RENAME LICENSE.asio) + endif() + + + +2) Configuration file +3) Executable files +4) Systemd service file + +--- galera-26.4.8/garb/CMakeLists.txt 2021-06-10 03:54:55.482520883 +0200 ++++ galera-26.4.8/garb/CMakeLists.txt_patched 2021-06-10 03:54:41.070274710 +0200 +@@ -31,14 +31,51 @@ target_compile_options(garbd + target_link_libraries(garbd gcs4garb gcomm gcache + ${Boost_PROGRAM_OPTIONS_LIBRARIES}) + +-install(TARGETS garbd DESTINATION bin) ++# Make the install destination for garbd binary configurable ++if(NOT DEFINED INSTALL_GARBD) ++ set(INSTALL_GARBD "bin" CACHE STRING "path to install garbd binary to") ++endif() ++ ++install(TARGETS garbd ++ DESTINATION ${INSTALL_GARBD}) ++ + if (NOT ${CMAKE_SYSTEM_NAME} MATCHES ".*BSD") ++ ++ # Make the install destination for garbd-systemd wrapper script configurable ++ if(NOT DEFINED INSTALL_GARBD-SYSTEMD) ++ set(INSTALL_GARBD-SYSTEMD "share" CACHE STRING "path to install garbd-systemd wrapper script to") ++ endif() ++ ++ install(FILES ++ ${CMAKE_CURRENT_SOURCE_DIR}/files/garb-systemd ++ DESTINATION ${INSTALL_GARBD-SYSTEMD}) ++ ++ # Make the install destination for garbd configuration file configurable ++ if(NOT DEFINED INSTALL_CONFIGURATION) ++ set(INSTALL_CONFIGURATION "share" CACHE STRING "path to install garbd configuration to") ++ endif() ++ + install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/files/garb.cnf ++ DESTINATION ${INSTALL_CONFIGURATION} ++ RENAME garb) ++ ++ # Make the install destination for garbd systemd service file configurable ++ if(NOT DEFINED INSTALL_SYSTEMD_SERVICE) ++ set(INSTALL_SYSTEMD_SERVICE "share" CACHE STRING "path to install garbd Systemd service to") ++ endif() ++ ++ install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/files/garb.service +- ${CMAKE_CURRENT_SOURCE_DIR}/files/garb-systemd +- DESTINATION share) ++ DESTINATION ${INSTALL_SYSTEMD_SERVICE}) ++ ++ # Make the install destination for manpage configurable ++ if(NOT DEFINED INSTALL_MANPAGE) ++ set(INSTALL_MANPAGE "man/man8" CACHE STRING "path to install manpage to") ++ endif() ++ + install(FILES + ${PROJECT_SOURCE_DIR}/man/garbd.8 +- DESTINATION man/man8) ++ DESTINATION ${INSTALL_MANPAGE}) ++ + endif() + + + +5) Shared library path + +--- galera-26.4.8/galera/src/CMakeLists.txt 2021-06-10 03:13:05.465005845 +0200 ++++ galera-26.4.8/galera/src/CMakeLists.txt_patched 2021-06-10 03:16:53.388699046 +0200 +@@ -112,7 +112,12 @@ endif() + + target_link_libraries(galera_smm galera ${GALERA_LINK_OPTIONS}) + +-install(TARGETS galera_smm DESTINATION lib) ++# Make the install destination for garbd binary configurable ++if(NOT DEFINED INSTALL_LIBDIR) ++ set(INSTALL_LIBDIR "lib" CACHE STRING "path to install shared libraries to") ++endif() ++ ++install(TARGETS galera_smm DESTINATION ${INSTALL_LIBDIR}) + + # The following checks are guaranteed to work only + # Linux platform, we skip them on others. + diff --git a/docs.patch b/docs.patch new file mode 100644 index 0000000000000000000000000000000000000000..7a6bec5495c16c6623031016f4639f6843a87ee4 --- /dev/null +++ b/docs.patch @@ -0,0 +1,25 @@ +The CMake prepares file AUTHORS for packing. +It only contains one line, and isn't packed in any upstream-produced packagess. +I don't find it useful and since upstream doesn't pack it either, stop packing it here. + +The README file contains infromation on how to build the project from sources, and thus isn't useful for the end users. + +On the other hand, the README-MySQL isn't prepared for packing by CMake, but contains useful information about the software usage and it is package in upstream-produced packages. + +Offered upstream: +https://github.com/codership/galera/pull/666 +https://groups.google.com/g/codership-team/c/Cn4UO3MkNQs + +--- galera-26.4.18/CMakeLists.txt 2024-06-09 04:54:56.281408893 +0200 ++++ galera-26.4.18/CMakeLists.txt_patched 2024-06-09 06:52:58.093217968 +0200 +@@ -118,9 +118,8 @@ endif() + + if (NOT ${CMAKE_SYSTEM_NAME} MATCHES ".*BSD") + install(FILES +- ${PROJECT_SOURCE_DIR}/AUTHORS + ${PROJECT_SOURCE_DIR}/COPYING +- ${PROJECT_SOURCE_DIR}/README ++ ${PROJECT_SOURCE_DIR}/scripts/packages/README-MySQL + DESTINATION ${INSTALL_DOCDIR} ) + install(FILES ${PROJECT_SOURCE_DIR}/asio/LICENSE_1_0.txt + DESTINATION ${INSTALL_DOCDIR} diff --git a/fix-garb-service.patch b/fix-garb-service.patch new file mode 100644 index 0000000000000000000000000000000000000000..d0435b4042c92830c186e7f4cedd57155bceb3f8 --- /dev/null +++ b/fix-garb-service.patch @@ -0,0 +1,24 @@ +diff -Nur galera-4-26.4.21_bak/garb/files/garb.service galera-4-26.4.21/garb/files/garb.service +--- galera-4-26.4.21_bak/garb/files/garb.service 2025-01-02 15:24:23.861654448 +0800 ++++ galera-4-26.4.21/garb/files/garb.service 2025-01-02 15:25:03.043529992 +0800 +@@ -12,7 +12,7 @@ + + [Service] + User=nobody +-ExecStart=/usr/bin/garb-systemd start ++ExecStart=/usr/sbin/garb-systemd start + + # Use SIGINT because with the default SIGTERM + # garbd fails to reliably transition to 'destroyed' state +diff -Nur galera-4-26.4.21_bak/garb/files/garb-systemd galera-4-26.4.21/garb/files/garb-systemd +--- galera-4-26.4.21_bak/garb/files/garb-systemd 2025-01-02 15:24:23.861654448 +0800 ++++ galera-4-26.4.21/garb/files/garb-systemd 2025-01-02 15:25:33.171434293 +0800 +@@ -13,7 +13,7 @@ + + program_start() { + echo "Starting garbd" +- /usr/bin/garbd "$@" ++ /usr/sbin/garbd "$@" + } + + start() { diff --git a/galera-4-26.4.16.tar.gz b/galera-4-26.4.16.tar.gz deleted file mode 100644 index 52cc33062fd597c5f37d14fc771fc6bd8c15e0c8..0000000000000000000000000000000000000000 Binary files a/galera-4-26.4.16.tar.gz and /dev/null differ diff --git a/galera-4-26.4.21.tar.gz b/galera-4-26.4.21.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..c278e4fb3c954e5fe2acd89dbdfa2c8d712283f3 Binary files /dev/null and b/galera-4-26.4.21.tar.gz differ diff --git a/galera-python3.patch b/galera-python3.patch deleted file mode 100644 index 59bb4f150326f0cd23a43a434025832d4ff28e60..0000000000000000000000000000000000000000 --- a/galera-python3.patch +++ /dev/null @@ -1,17 +0,0 @@ -Upstream PR: -https://github.com/codership/galera/pull/512 - -diff -up galera-25.3.23/SConstruct.bak galera-25.3.23/SConstruct ---- galera-25.3.23/SConstruct.bak 2018-07-13 15:14:49.059835554 +0200 -+++ galera-25.3.23/SConstruct 2018-07-13 15:19:07.717967794 +0200 -@@ -194,8 +194,8 @@ if link != 'default': - env.Replace(LINK = link) - - # Get compiler name/version, CXX may be set to "c++" which may be clang or gcc --cc_version = str(read_first_line(env['CC'].split() + ['--version'])) --cxx_version = str(read_first_line(env['CXX'].split() + ['--version'])) -+cc_version = str(read_first_line(env['CC'].split() + ['--version']).decode()) -+cxx_version = str(read_first_line(env['CXX'].split() + ['--version']).decode()) - - print('Using C compiler executable: ' + env['CC']) - print('C compiler version is: ' + cc_version) diff --git a/galera.spec b/galera.spec index 9591ddb1404939e21839432929e628a16fb9a82d..406bec263c4ae550b5d779b8842c2ee68d650297 100644 --- a/galera.spec +++ b/galera.spec @@ -1,25 +1,22 @@ -%global galeradoc %{buildroot}%{_docdir}/galera Name: galera -Version: 26.4.16 +Version: 26.4.21 Release: 1 Summary: Synchronous multi-master replication library -License: GPLv2 +License: GPL-2.0-only URL: http://galeracluster.com/ -Source0: http://releases.galeracluster.com/%{name}-4.16/source/%{name}-4-%{version}.tar.gz -Source1: garbd.service -#systemd startup script -Source2: garbd-wrapper - -#Use decode to make the SConstruct Python3 compatible -#https://github.com/codership/galera/commit/71685db8da72b81a0950c19269281d10ae179706.patch -Patch0000: galera-python3.patch -# https://salsa.debian.org/mariadb-team/galera-4/-/commit/19f010d78a98d8c481b57de27b0b59cdad8b979d -Patch0001: Apply-upstream-patches-from-codership-galera-558.patch - -BuildRequires: asio-devel boost-devel check-devel gcc-c++ openssl-devel python3-scons systemd +Source0: http://releases.galeracluster.com/%{name}-4.21/source/%{name}-4-%{version}.tar.gz + +Patch0: cmake_paths.patch +Patch1: docs.patch +Patch2: network.patch +Patch3: fix-garb-service.patch + +BuildRequires: asio-devel boost-devel check-devel gcc-c++ openssl-devel cmake systemd +Requires(pre): /usr/sbin/useradd Requires: nmap-ncat +Requires: procps-ng -Requires(post,preun,postun): systemd +%{?systemd_requires} %description This is Galera replication - Codership's implementation of the write set replication (wsrep) interface. @@ -27,28 +24,35 @@ This is Galera replication - Codership's implementation of the write set replica %prep %autosetup -n %{name}-4-%{version} -p1 -sed -i '/^GALERA_VER/s/API + //' wsrep/tests/SConscript - %build %{set_build_flags} -CPPFLAGS=`echo $CPPFLAGS| sed -e "s|-Wp,-D_GLIBCXX_ASSERTIONS||g" ` -CFLAGS=`echo $CFLAGS| sed -e "s|-Wp,-D_GLIBCXX_ASSERTIONS||g" ` -CXXFLAGS=`echo $CXXFLAGS| sed -e "s|-Wp,-D_GLIBCXX_ASSERTIONS||g" ` -export CPPFLAGS CFLAGS CXXFLAGS - -scons-3 %{?_smp_mflags} strict_build_flags=0 +%cmake \ + -DCMAKE_BUILD_TYPE="%{?with_debug:Debug}%{!?with_debug:RelWithDebInfo}" \ + -DINSTALL_LAYOUT=RPM \ + -DCMAKE_RULE_MESSAGES:BOOL=OFF \ + \ + -DBUILD_SHARED_LIBS:BOOL=OFF \ + \ + -DINSTALL_DOCDIR="share/doc/%{name}/" \ + -DINSTALL_GARBD="sbin" \ + -DINSTALL_GARBD-SYSTEMD="sbin" \ + -DINSTALL_CONFIGURATION="/etc/sysconfig/" \ + -DINSTALL_SYSTEMD_SERVICE="lib/systemd/system" \ + -DINSTALL_LIBDIR="%{_lib}/galera" \ + -DINSTALL_MANPAGE="share/man/man8" + +cmake -B %_vpath_builddir -LAH + +%cmake_build %install -install -D -m 644 COPYING %{galeradoc}/COPYING -install -D -m 644 asio/LICENSE_1_0.txt %{galeradoc}/LICENSE.asio -install -D -m 644 scripts/packages/README %{galeradoc}/README -install -D -m 644 scripts/packages/README-MySQL %{galeradoc}/README-MySQL -install -D -m 644 garb/files/garb.cnf %{buildroot}%{_sysconfdir}/sysconfig/garb -install -D -m 644 %{SOURCE1} %{buildroot}%{_unitdir}/garbd.service -install -D -m 755 %{SOURCE2} %{buildroot}%{_sbindir}/garbd-wrapper -install -D -m 755 garb/garbd %{buildroot}%{_sbindir}/garbd -install -D -m 755 libgalera_smm.so %{buildroot}%{_libdir}/galera/libgalera_smm.so +%cmake_install + +mv %{buildroot}%{_unitdir}/garb.service %{buildroot}%{_unitdir}/garbd.service + +%check +%ctest %post /sbin/ldconfig @@ -70,7 +74,14 @@ install -D -m 755 libgalera_smm.so %{buildroot}%{_libdir}/galera/li %{_sbindir}/garbd* %{_unitdir}/garbd.service +%attr(755, -, -) %{_sbindir}/garb-systemd +%{_mandir}/man8/garbd.8* + %changelog +* Thu Jan 02 2025 wangkai <13474090681@163.com> - 26.4.21-1 +- Upgrade to 26.4.21 +- Switch scons build to cmake build + * Wed Dec 06 2023 yaoxin - 26.4.16-1 - Upgrade to 26.4.16 and fix build error diff --git a/garbd-wrapper b/garbd-wrapper deleted file mode 100755 index ede76f7a9a296e0d5f068794750745cea36ba5a2..0000000000000000000000000000000000000000 --- a/garbd-wrapper +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/sh -# This script is simple wrapper around garbd, that parses startup configuration. -# Its main purpose is to bridge the differences between initscript and systemd unit file. - -CONFIG_FILE=/etc/sysconfig/garb - -source $CONFIG_FILE - -# Check that node addresses and group name are configured -if [ -z "$GALERA_NODES" ]; then - echo "List of GALERA_NODES is not configured" >&2 - exit 1 -fi -if [ -z "$GALERA_GROUP" ]; then - echo "GALERA_GROUP name is not configured" >&2 - exit 1 -fi - -GALERA_PORT=${GALERA_PORT:-4567} - -# Find a working node -for ADDRESS in ${GALERA_NODES} 0; do - HOST=$(echo $ADDRESS | cut -d \: -f 1) - PORT=$(echo $ADDRESS | cut -s -d \: -f 2) - PORT=${PORT:-$GALERA_PORT} - ncat --send-only --recv-only $HOST $PORT >/dev/null && break -done -if [ ${ADDRESS} == "0" ]; then - echo "None of the nodes in GALERA_NODES is accessible" >&2 - exit 1 -fi - -OPTIONS="-a gcomm://$ADDRESS" -[ -n "$GALERA_GROUP" ] && OPTIONS="$OPTIONS -g $GALERA_GROUP" -[ -n "$GALERA_OPTIONS" ] && OPTIONS="$OPTIONS -o $GALERA_OPTIONS" -[ -n "$LOG_FILE" ] && OPTIONS="$OPTIONS -l $LOG_FILE" - -exec /usr/sbin/garbd $OPTIONS diff --git a/garbd.service b/garbd.service deleted file mode 100644 index 33a74119094d08c0cfea7e92c0291b20b8048233..0000000000000000000000000000000000000000 --- a/garbd.service +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=Galera Arbitrator(garbd) Daemon -Documentation=https://galeracluster.com/library/documentation/arbitrator.html - -[Service] -ExecStart=/usr/sbin/garbd-wrapper - -[Install] -WantedBy=multi-user.target diff --git a/network.patch b/network.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d9f4835082c872ad53b3071de3da4c2b23c627b --- /dev/null +++ b/network.patch @@ -0,0 +1,19 @@ +Make sure the network is actually up at the moment of the service startup: +https://systemd.io/NETWORK_ONLINE/ + +Offered upstream: +https://github.com/codership/galera/pull/667 +https://groups.google.com/g/codership-team/c/Cn4UO3MkNQs + +--- galera-26.4.18/garb/files/garb.service 2024-04-17 19:39:35.000000000 +0200 ++++ galera-26.4.18/garb/files/garb.service_patched 2024-06-09 07:47:19.245480639 +0200 +@@ -4,7 +4,8 @@ + Description=Galera Arbitrator Daemon + Documentation=man:garbd(8) + Documentation=https://galeracluster.com/library/documentation/arbitrator.html +-After=network.target ++After=network-online.target ++Wants=network-online.target + + [Install] + WantedBy=multi-user.target