From efbc7762e3071b1d8e3c4def6f331d302b3e1c21 Mon Sep 17 00:00:00 2001 From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org> Date: Mon, 24 Apr 2023 23:00:41 +0200 Subject: [PATCH] box: introduce node_name funcs and constants Node name stores a DNS- and host- friendly string name. It will be used in the next patches for some new global names: cluster, replicaset, and instance. Part of #5029 NO_DOC=internal NO_CHANGELOG=internal --- src/box/CMakeLists.txt | 6 ++- src/box/node_name.c | 24 ++++++++++++ src/box/node_name.h | 55 ++++++++++++++++++++++++++++ test/unit/CMakeLists.txt | 5 +++ test/unit/node_name.c | 79 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 src/box/node_name.c create mode 100644 src/box/node_name.h create mode 100644 test/unit/node_name.c diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index a7661670d7..9d9208eddd 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -95,8 +95,10 @@ include_directories(${EXTRA_BOX_INCLUDE_DIRS}) add_library(box_error STATIC error.cc errcode.c mp_error.cc) target_link_libraries(box_error core stat mpstream vclock) +add_library(node_name STATIC node_name.c) + add_library(xrow STATIC xrow.c iproto_constants.c iproto_features.c) -target_link_libraries(xrow server core small vclock misc box_error +target_link_libraries(xrow server core small vclock misc box_error node_name ${MSGPUCK_LIBRARIES}) set(tuple_sources @@ -324,6 +326,6 @@ add_custom_command(OUTPUT ${SQL_BIN_DIR}/opcodes.c ${SQL_BIN_DIR}/opcodes.h) target_link_libraries(box box_error tuple stat xrow xlog vclock crc32 raft - ${common_libraries}) + node_name ${common_libraries}) add_dependencies(box build_bundled_libs generate_sql_files) diff --git a/src/box/node_name.c b/src/box/node_name.c new file mode 100644 index 0000000000..4443fbd2be --- /dev/null +++ b/src/box/node_name.c @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2010-2023, Tarantool AUTHORS, please see AUTHORS file. + */ +#include "node_name.h" + +#include <ctype.h> + +bool +node_name_is_valid_n(const char *name, size_t len) +{ + if (len == 0 || len > NODE_NAME_LEN_MAX || !isalpha(*name)) + return false; + const char *end = name + len; + while (name < end) { + char c = *(name++); + if (!isalnum(c) && c != '-') + return false; + if (tolower(c) != c) + return false; + } + return true; +} diff --git a/src/box/node_name.h b/src/box/node_name.h new file mode 100644 index 0000000000..c11fdee181 --- /dev/null +++ b/src/box/node_name.h @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2010-2023, Tarantool AUTHORS, please see AUTHORS file. + */ +#pragma once + +#include <assert.h> +#include <stdbool.h> +#include <stddef.h> +#include <string.h> + +/** + * Name suitable for a node visible in the network. Its format matches the + * sub-domain label in RFC 1035, section 2.3.1 + * (https://www.rfc-editor.org/rfc/rfc1035#section-2.3.1). + * + * It allows to use the node name as a sub-domain and a host name. + * + * The limitations are: max 63 symbols (not including term 0); only lowercase + * letters, digits, and hyphen. Can start only with a letter. Note that the + * sub-domain name rules say that uppercase is allowed but the names are + * case-insensitive. In Tarantool the lowercase is enforced. + */ + +enum { + NODE_NAME_LEN_MAX = 63, + NODE_NAME_SIZE_MAX = NODE_NAME_LEN_MAX + 1, +}; + +#if defined(__cplusplus) +extern "C" { +#endif /* defined(__cplusplus) */ + +/** Check if the node name of the given length is valid. */ +bool +node_name_is_valid_n(const char *name, size_t len); + +static inline bool +node_name_is_valid(const char *name) +{ + return node_name_is_valid_n(name, strnlen(name, NODE_NAME_SIZE_MAX)); +} + +static inline const char * +node_name_str(const char *name) +{ + if (name == NULL || *name == 0) + return "<no-name>"; + return name; +} + +#if defined(__cplusplus) +} +#endif /* defined(__cplusplus) */ diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 24f45f201d..4649c6e897 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -600,3 +600,8 @@ create_unit_test(PREFIX lua_tweaks ${LIBYAML_LIBRARIES} ${READLINE_LIBRARIES} ) + +create_unit_test(PREFIX node_name + SOURCES node_name.c core_test_utils.c + LIBRARIES core unit node_name +) diff --git a/test/unit/node_name.c b/test/unit/node_name.c new file mode 100644 index 0000000000..d17d4d3ffe --- /dev/null +++ b/test/unit/node_name.c @@ -0,0 +1,79 @@ +#include "node_name.h" + +#include "trivia/util.h" +#define UNIT_TAP_COMPATIBLE 1 +#include "unit.h" + +static void +test_node_name_is_valid(void) +{ + header(); + plan(27); + + const char *bad_names[] = { + "", + "1", + "1abc", + "*", + "a_b", + "aBcD", + "a~b", + "{ab}", + }; + for (int i = 0; i < (int)lengthof(bad_names); ++i) { + const char *str = bad_names[i]; + ok(!node_name_is_valid(str), "bad name %d", i); + ok(!node_name_is_valid_n(str, strlen(str)), + "bad name n %d", i); + } + const char *good_names[] = { + "a", + "a-b-c", + "abc", + "a1b2c3-d4-e5-", + }; + for (int i = 0; i < (int)lengthof(good_names); ++i) { + const char *str = good_names[i]; + ok(node_name_is_valid(str), "bad name %d", i); + ok(node_name_is_valid_n(str, strlen(str)), + "bad name n %d", i); + } + char name[NODE_NAME_SIZE_MAX + 1]; + memset(name, 'a', sizeof(name)); + ok(!node_name_is_valid_n(name, NODE_NAME_SIZE_MAX), "max + 1"); + ok(node_name_is_valid_n(name, NODE_NAME_LEN_MAX), "max n"); + name[NODE_NAME_SIZE_MAX - 1] = 0; + ok(node_name_is_valid(name), "max"); + + check_plan(); + footer(); +} + +static void +test_node_name_str(void) +{ + header(); + plan(3); + + const char *stub = "<no-name>"; + is(strcmp(node_name_str("abc"), "abc"), 0, "name"); + is(strcmp(node_name_str(""), stub), 0, "empty"); + is(strcmp(node_name_str(NULL), stub), 0, "null"); + + check_plan(); + footer(); +} + +int +main(void) +{ + header(); + plan(2); + + test_node_name_is_valid(); + test_node_name_str(); + + int rc = check_plan(); + footer(); + return rc; +} -- GitLab