From 4a757eb34173a14bf07cd49362a4f7d78bb04eba Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 18 Jul 2018 18:42:10 +1000 Subject: [PATCH 1/5] ctdb-common: Add line based I/O BUG: https://bugzilla.samba.org/show_bug.cgi?id=13520 Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke (cherry picked from commit c7041b0faf490661818244dd032ad413ce906e5c) --- ctdb/common/line.c | 145 ++++++++++++++++++++++++++++++ ctdb/common/line.h | 62 +++++++++++++ ctdb/tests/cunit/line_test_001.sh | 90 +++++++++++++++++++ ctdb/tests/src/line_test.c | 102 +++++++++++++++++++++ ctdb/wscript | 5 +- 5 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 ctdb/common/line.c create mode 100644 ctdb/common/line.h create mode 100755 ctdb/tests/cunit/line_test_001.sh create mode 100644 ctdb/tests/src/line_test.c diff --git a/ctdb/common/line.c b/ctdb/common/line.c new file mode 100644 index 00000000000..c4c6726875b --- /dev/null +++ b/ctdb/common/line.c @@ -0,0 +1,145 @@ +/* + Line based I/O over fds + + Copyright (C) Amitay Isaacs 2018 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" + +#include + +#include "lib/util/sys_rw.h" + +#include "common/line.h" + +struct line_read_state { + line_process_fn_t callback; + void *private_data; + char *buf; + size_t hint, len, offset; + int num_lines; +}; + +static bool line_read_one(char *buf, size_t start, size_t len, size_t *pos) +{ + size_t i; + + for (i=start; ibuf, start, state->offset, &pos); + if (! ok) { + break; + } + + state->buf[pos] = '\0'; + state->num_lines += 1; + + ret = state->callback(state->buf + start, state->private_data); + if (ret != 0) { + return ret; + } + + start = pos+1; + } + + if (pos > 0) { + if (pos+1 < state->offset) { + memmove(state->buf, + state->buf + pos+1, + state->offset - (pos+1)); + } + state->offset -= (pos+1); + } + + return 0; +} + +int line_read(int fd, + size_t length, + TALLOC_CTX *mem_ctx, + line_process_fn_t callback, + void *private_data, + int *num_lines) +{ + struct line_read_state state; + + if (length < 32) { + length = 32; + } + + state = (struct line_read_state) { + .callback = callback, + .private_data = private_data, + .hint = length, + }; + + while (1) { + ssize_t n; + int ret; + + if (state.offset == state.len) { + state.len += state.hint; + state.buf = talloc_realloc_size(mem_ctx, + state.buf, + state.len); + if (state.buf == NULL) { + return ENOMEM; + } + } + + n = sys_read(fd, + state.buf + state.offset, + state.len - state.offset); + if (n < 0) { + return errno; + } + if (n == 0) { + break; + } + + state.offset += n; + + ret = line_read_process(&state); + if (ret != 0) { + if (num_lines != NULL) { + *num_lines = state.num_lines; + } + return ret; + } + } + + if (num_lines != NULL) { + *num_lines = state.num_lines; + } + return 0; +} diff --git a/ctdb/common/line.h b/ctdb/common/line.h new file mode 100644 index 00000000000..6b67f1e92e1 --- /dev/null +++ b/ctdb/common/line.h @@ -0,0 +1,62 @@ +/* + Line based I/O over fds + + Copyright (C) Amitay Isaacs 2018 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_LINE_H__ +#define __CTDB_LINE_H__ + +#include + +/** + * @file line.h + * + * @brief Line based I/O over pipes and sockets + */ + +/** + * @brief The callback routine called to process a line + * + * @param[in] line The line read + * @param[in] private_data Private data for callback + * @return 0 to continue processing lines, non-zero to stop reading + */ +typedef int (*line_process_fn_t)(char *line, void *private_data); + +/** + * @brief Read a line (terminated by \n or \0) + * + * If there is any read error on fd, then errno will be returned. + * If callback function returns a non-zero value, then that value will be + * returned. + * + * @param[in] fd The file descriptor + * @param[in] length The expected length of a line (this is only a hint) + * @param[in] mem_ctx Talloc memory context + * @param[in] callback Callback function called when a line is read + * @param[in] private_data Private data for callback + * @param[out] num_lines Number of lines read so far + * @return 0 on on success, errno on failure + */ +int line_read(int fd, + size_t length, + TALLOC_CTX *mem_ctx, + line_process_fn_t callback, + void *private_data, + int *num_lines); + +#endif /* __CTDB_LINE_H__ */ diff --git a/ctdb/tests/cunit/line_test_001.sh b/ctdb/tests/cunit/line_test_001.sh new file mode 100755 index 00000000000..991d01a24e7 --- /dev/null +++ b/ctdb/tests/cunit/line_test_001.sh @@ -0,0 +1,90 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +tfile="${TEST_VAR_DIR}/line.$$" + +remove_files () +{ + rm -f "$tfile" +} + +test_cleanup remove_files + +> "$tfile" + +ok_null +unit_test line_test "$tfile" + +printf "\0" > "$tfile" + +required_result 1 < "$tfile" + +ok_null +unit_test line_test "$tfile" + +cat < "$tfile" +hello +world +EOF + +required_result 2 << EOF +hello +world +EOF +unit_test line_test "$tfile" + +required_result 2 << EOF +hello +world +EOF +unit_test line_test "$tfile" + +cat < "$tfile" +This is a really long long line full of random words and hopefully it will be read properly by the line test program and identified as a single line +EOF + +required_result 1 < "$tfile" +line number one +line number two +line number one +line number two +line number one +EOF + +required_result 5 < "$tfile" +this is line number one +this is line number two +this is line number three +this is line number four +this is line number five +EOF + +required_result 5 <. +*/ + +#include "replace.h" +#include "system/filesys.h" + +#include +#include + +#include "common/line.c" + +static int line_print(char *line, void *private_data) +{ + printf("%s\n", line); + fflush(stdout); + + return 0; +} + +int main(int argc, const char **argv) +{ + TALLOC_CTX *mem_ctx; + size_t hint = 32; + pid_t pid; + int ret, lines = 0; + int pipefd[2]; + + if (argc < 2 || argc > 3) { + fprintf(stderr, "Usage: %s []\n", argv[0]); + exit(1); + } + + if (argc == 3) { + long value; + + value = atol(argv[2]); + assert(value > 0); + hint = value; + } + + ret = pipe(pipefd); + assert(ret == 0); + + pid = fork(); + assert(pid != -1); + + if (pid == 0) { + char buffer[16]; + ssize_t n, n2; + int fd; + + close(pipefd[0]); + + fd = open(argv[1], O_RDONLY); + assert(fd != -1); + + while (1) { + n = read(fd, buffer, sizeof(buffer)); + assert(n >= 0 && n <= sizeof(buffer)); + + if (n == 0) { + break; + } + + n2 = write(pipefd[1], buffer, n); + assert(n2 == n); + } + + close(pipefd[1]); + close(fd); + + exit(0); + } + + close(pipefd[1]); + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ret = line_read(pipefd[0], hint, NULL, line_print, NULL, &lines); + assert(ret == 0); + + talloc_free(mem_ctx); + + return lines; +} diff --git a/ctdb/wscript b/ctdb/wscript index f8259c7c1d6..e3bcdf7e962 100644 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -409,7 +409,9 @@ def build(bld): logging.c rb_tree.c tunable.c pidfile.c run_proc.c hash_count.c run_event.c - sock_client.c version.c'''), + sock_client.c version.c + line.c + '''), deps='''samba-util sys_rw tevent-util replace talloc tevent tdb''') @@ -765,6 +767,7 @@ def build(bld): 'sock_io_test', 'hash_count_test', 'run_event_test', + 'line_test', ] for target in ctdb_unit_tests: -- 2.20.1 From f05d1defcdaee7820c33d7db30fcd96ff9ca693b Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 11 Jul 2018 18:35:46 +1000 Subject: [PATCH 2/5] ctdb-protocol: Avoid fgets in ctdb_connection_list_read C library buffering API can behave in unexpected fashion if underlying fd for stdin, stdout or stderr is closed and re-opened. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13520 Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke (cherry picked from commit c9b42d27e6cf9e6ae36f44970f0a388edc737a7a) --- ctdb/protocol/protocol_util.c | 86 ++++++++++++++++++++--------------- ctdb/wscript | 4 +- 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/ctdb/protocol/protocol_util.c b/ctdb/protocol/protocol_util.c index c75555fa734..45c639d747f 100644 --- a/ctdb/protocol/protocol_util.c +++ b/ctdb/protocol/protocol_util.c @@ -22,6 +22,8 @@ #include +#include "common/line.h" + #include "protocol.h" #include "protocol_util.h" @@ -603,56 +605,66 @@ const char *ctdb_connection_list_to_string( return out; } -int ctdb_connection_list_read(TALLOC_CTX *mem_ctx, bool client_first, - struct ctdb_connection_list **conn_list) -{ +struct ctdb_connection_list_read_state { struct ctdb_connection_list *list; - char line[128]; /* long enough for IPv6 */ + bool client_first; +}; + +static int ctdb_connection_list_read_line(char *line, void *private_data) +{ + struct ctdb_connection_list_read_state *state = + (struct ctdb_connection_list_read_state *)private_data; + struct ctdb_connection conn; int ret; - if (conn_list == NULL) { - return EINVAL; + /* Skip empty lines */ + if (line[0] == '\0') { + return 0; } - list = talloc_zero(mem_ctx, struct ctdb_connection_list); - if (list == NULL) { - return ENOMEM; + /* Comment */ + if (line[0] == '#') { + return 0; } - while (fgets(line, sizeof(line), stdin) != NULL) { - char *t; - struct ctdb_connection conn; + ret = ctdb_connection_from_string(line, state->client_first, &conn); + if (ret != 0) { + return ret; + } - /* Skip empty lines */ - if (line[0] == '\n') { - continue; - } + ret = ctdb_connection_list_add(state->list, &conn); + if (ret != 0) { + return ret; + } - /* Comment */ - if (line[0] == '#') { - continue; - } + return 0; +} - t = strtok(line, "\n"); - if (t == NULL) { - goto fail; - } +int ctdb_connection_list_read(TALLOC_CTX *mem_ctx, bool client_first, + struct ctdb_connection_list **conn_list) +{ + struct ctdb_connection_list_read_state state; + int ret; - ret = ctdb_connection_from_string(t, client_first, &conn); - if (ret != 0) { - goto fail; - } + if (conn_list == NULL) { + return EINVAL; + } - ret = ctdb_connection_list_add(list, &conn); - if (ret != 0) { - goto fail; - } + state.list = talloc_zero(mem_ctx, struct ctdb_connection_list); + if (state.list == NULL) { + return ENOMEM; } - *conn_list = list; - return 0; + state.client_first = client_first; + + ret = line_read(0, + 128, + mem_ctx, + ctdb_connection_list_read_line, + &state, + NULL); -fail: - talloc_free(list); - return EINVAL; + *conn_list = state.list; + + return ret; } diff --git a/ctdb/wscript b/ctdb/wscript index e3bcdf7e962..8727fd8aefa 100644 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -433,7 +433,7 @@ def build(bld): bld.SAMBA_SUBSYSTEM('ctdb-protocol-util', source='protocol/protocol_util.c', - deps='replace talloc tdb') + deps='ctdb-util replace talloc tdb') bld.SAMBA_SUBSYSTEM('ctdb-client', source=bld.SUBDIR('client', 'ctdb_client.c'), @@ -824,7 +824,7 @@ def build(bld): bld.SAMBA_BINARY(target, source=src, deps='''protocol-tests-common - samba-util talloc tdb''', + samba-util ctdb-util talloc tdb''', install_path='${CTDB_TEST_LIBEXECDIR}') bld.SAMBA_SUBSYSTEM('ctdb-tests-common', -- 2.20.1 From cc42044a131b7919e7f781ff5203788687c58d2f Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Wed, 18 Jul 2018 19:00:42 +1000 Subject: [PATCH 3/5] ctdb-common: Add fd argument to ctdb_connection_list_read() This makes testing easier. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13520 Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke (cherry picked from commit 3bf753e830c20183ef4f3278880d3be362e53bef) --- ctdb/protocol/protocol_util.c | 6 ++++-- ctdb/protocol/protocol_util.h | 4 +++- ctdb/tests/src/protocol_util_test.c | 18 ++++++------------ ctdb/tools/ctdb.c | 6 +++--- ctdb/tools/ctdb_killtcp.c | 2 +- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/ctdb/protocol/protocol_util.c b/ctdb/protocol/protocol_util.c index 45c639d747f..77e79867443 100644 --- a/ctdb/protocol/protocol_util.c +++ b/ctdb/protocol/protocol_util.c @@ -640,7 +640,9 @@ static int ctdb_connection_list_read_line(char *line, void *private_data) return 0; } -int ctdb_connection_list_read(TALLOC_CTX *mem_ctx, bool client_first, +int ctdb_connection_list_read(TALLOC_CTX *mem_ctx, + int fd, + bool client_first, struct ctdb_connection_list **conn_list) { struct ctdb_connection_list_read_state state; @@ -657,7 +659,7 @@ int ctdb_connection_list_read(TALLOC_CTX *mem_ctx, bool client_first, state.client_first = client_first; - ret = line_read(0, + ret = line_read(fd, 128, mem_ctx, ctdb_connection_list_read_line, diff --git a/ctdb/protocol/protocol_util.h b/ctdb/protocol/protocol_util.h index 66a49136576..347fe8a275a 100644 --- a/ctdb/protocol/protocol_util.h +++ b/ctdb/protocol/protocol_util.h @@ -66,7 +66,9 @@ int ctdb_connection_list_sort(struct ctdb_connection_list *conn_list); const char *ctdb_connection_list_to_string( TALLOC_CTX *mem_ctx, struct ctdb_connection_list *conn_list, bool client_first); -int ctdb_connection_list_read(TALLOC_CTX *mem_ctx, bool client_first, +int ctdb_connection_list_read(TALLOC_CTX *mem_ctx, + int fd, + bool client_first, struct ctdb_connection_list **conn_list); #endif /* __CTDB_PROTOCOL_UTIL_H__ */ diff --git a/ctdb/tests/src/protocol_util_test.c b/ctdb/tests/src/protocol_util_test.c index eb7eb0ff88f..5608b13920c 100644 --- a/ctdb/tests/src/protocol_util_test.c +++ b/ctdb/tests/src/protocol_util_test.c @@ -153,7 +153,7 @@ static void test_connection_list_read(const char *s1, const char *s2) TALLOC_CTX *tmp_ctx; int pipefd[2]; pid_t pid; - struct ctdb_connection_list *conn_list; + struct ctdb_connection_list *conn_list = NULL; const char *t; int ret; @@ -182,14 +182,11 @@ static void test_connection_list_read(const char *s1, const char *s2) close(pipefd[1]); - ret = dup2(pipefd[0], STDIN_FILENO); - assert(ret != -1); + ret = ctdb_connection_list_read(tmp_ctx, pipefd[0], false, &conn_list); + assert(ret == 0); close(pipefd[0]); - ret = ctdb_connection_list_read(tmp_ctx, false, &conn_list); - assert(ret == 0); - ret = ctdb_connection_list_sort(conn_list); assert(ret == 0); @@ -206,7 +203,7 @@ static void test_connection_list_read_bad(const char *s1) TALLOC_CTX *tmp_ctx; int pipefd[2]; pid_t pid; - struct ctdb_connection_list *conn_list; + struct ctdb_connection_list *conn_list = NULL; int ret; tmp_ctx = talloc_new(NULL); @@ -234,14 +231,11 @@ static void test_connection_list_read_bad(const char *s1) close(pipefd[1]); - ret = dup2(pipefd[0], STDIN_FILENO); - assert(ret != -1); + ret = ctdb_connection_list_read(tmp_ctx, pipefd[0], false, &conn_list); + assert(ret == EINVAL); close(pipefd[0]); - ret = ctdb_connection_list_read(tmp_ctx, false, &conn_list); - assert(ret == EINVAL); - talloc_free(tmp_ctx); } diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c index 2cb46b057f0..a6f8f2904dd 100644 --- a/ctdb/tools/ctdb.c +++ b/ctdb/tools/ctdb.c @@ -3023,7 +3023,7 @@ static int control_tickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb, int i, num_failed; /* Client first but the src/dst logic is confused */ - ret = ctdb_connection_list_read(mem_ctx, false, &clist); + ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist); if (ret != 0) { return ret; } @@ -3241,7 +3241,7 @@ static int control_addtickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb, struct tevent_req *req; /* Client first but the src/dst logic is confused */ - ret = ctdb_connection_list_read(mem_ctx, false, &clist); + ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist); if (ret != 0) { return ret; } @@ -3306,7 +3306,7 @@ static int control_deltickle(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb, struct tevent_req *req; /* Client first but the src/dst logic is confused */ - ret = ctdb_connection_list_read(mem_ctx, false, &clist); + ret = ctdb_connection_list_read(mem_ctx, 0, false, &clist); if (ret != 0) { return ret; } diff --git a/ctdb/tools/ctdb_killtcp.c b/ctdb/tools/ctdb_killtcp.c index da497d21d57..b35331d02ed 100644 --- a/ctdb/tools/ctdb_killtcp.c +++ b/ctdb/tools/ctdb_killtcp.c @@ -372,7 +372,7 @@ int main(int argc, char **argv) goto fail; } } else { - ret = ctdb_connection_list_read(mem_ctx, true, &conn_list); + ret = ctdb_connection_list_read(mem_ctx, 0, true, &conn_list); if (ret != 0) { D_ERR("Unable to parse connections (%s)\n", strerror(ret)); -- 2.20.1 From edbad0618993012106747efb5829ead8bf6c48a9 Mon Sep 17 00:00:00 2001 From: Zhu Shangzhong Date: Tue, 12 Mar 2019 20:49:48 +0800 Subject: [PATCH 4/5] ctdb: Initialize addr struct to zero before reparsing as IPV4 Failed to kill the tcp connection that using IPv4-mapped IPv6 address (e.g. ctdb_killtcp eth0 ::ffff:192.168.200.44:2049 ::ffff:192.168.200.45:863). When the ctdb_killtcp is used to kill the tcp connection, the IPs and ports in the connection will be parsed to conn.client and conn.server (call stack: main->ctdb_sock_addr_from_string->ip_from_string). In the ip_from_string, as we are using IPv4-mapped IPv6 addresses, the ipv6_from_string will be used to parse ip to addr.ip6 first. The next step the ipv4_from_string will be used to reparse ip to addr.ip. As a result, the data that dump from conn.server is "2 0 8 1 192 168 200 44 0 0 0 0 0 0 0 0 0 0 255 255 192 168 200 44 0 0 0 0", the data from conn.client is "2 0 3 95 192 168 200 45 0 0 0 0 0 0 0 0 0 0 255 255 192 168 200 45 0 0 0 0". The connection will be add to conn_list by ctdb_connection_list_add. Then the reset_connections_send uses conn_list as parameter to start to reset connections in the conn_list. In the reset_connections_send, the database "connections" will be created. The connections from conn_list will be written to the database(call db_hash_add), and use the data that dump from conn_client and conn_server as key. In the reset_connections_capture_tcp_handler, the ctdb_sys_read_tcp_packet will receive data on the raw socket. And extract the IPs and ports from the tcp packet. when extracting IP and port, the tcp4_extract OR tcp6_extract will be used. Then we got the new conn.client and conn.server. the data that dump from the conn.server is "2 0 8 1 192 168 200 44 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", the data from conn.client is "2 0 3 95 192 168 200 45 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0". Finally, we use the data as key to check if this connection is one being reset(call db_hash_delete). The db_hash_delete will return ENOENT. Because the two key that being used by db_hash_delete and db_hash_add are different. So, the TCP RST will be NOT sent for the connection forever. We should initialize addr struct to zero before reparsing as IPV4 in the ip_from_string. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13839 Signed-off-by: Zhu Shangzhong Reviewed-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 539b5ff32b32b7c75dfaaa119e41f5af6ff1e6fc) --- ctdb/protocol/protocol_util.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ctdb/protocol/protocol_util.c b/ctdb/protocol/protocol_util.c index 77e79867443..a46cde9f46f 100644 --- a/ctdb/protocol/protocol_util.c +++ b/ctdb/protocol/protocol_util.c @@ -251,6 +251,9 @@ static int ip_from_string(const char *str, ctdb_sock_addr *addr) if (memcmp(&addr->ip6.sin6_addr.s6_addr[0], ipv4_mapped_prefix, sizeof(ipv4_mapped_prefix)) == 0) { + /* Initialize addr struct to zero before reparsing as IPV4 */ + ZERO_STRUCTP(addr); + /* Reparse as IPv4 */ ret = ipv4_from_string(p+1, &addr->ip); } -- 2.20.1 From 03e9900c7233d6e2d802a178c76e6720e72715bc Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Thu, 14 Mar 2019 16:32:02 +1100 Subject: [PATCH 5/5] ctdb-tests: Add some testing for IPv4-mapped IPv6 address parsing ctdb_sock_addr values are hashed in some contexts. This means that all of the memory used for the ctdb_sock_addr should be consistent regardless of how parsing is done. The first 2 cases are just sanity checks but the 3rd case involving an IPv4-mapped IPv6 address is the real target of this test addition. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13839 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit d9286701cd9253bf3b42cac3d850ae8c23743e6d) --- ctdb/tests/src/protocol_util_test.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ctdb/tests/src/protocol_util_test.c b/ctdb/tests/src/protocol_util_test.c index 5608b13920c..9be95eca2ef 100644 --- a/ctdb/tests/src/protocol_util_test.c +++ b/ctdb/tests/src/protocol_util_test.c @@ -52,6 +52,20 @@ static void test_sock_addr_from_string_bad(const char *ip, bool with_port) assert(ret == EINVAL); } +static void test_sock_addr_from_string_memcmp(const char *ip1, + const char* ip2) +{ + ctdb_sock_addr sa1, sa2; + int ret; + + ret = ctdb_sock_addr_from_string(ip1, &sa1, false); + assert(ret == 0); + ret = ctdb_sock_addr_from_string(ip2, &sa2, false); + assert(ret == 0); + ret = memcmp(&sa1, &sa2, sizeof(ctdb_sock_addr)); + assert(ret == 0); +} + static void test_sock_addr_cmp(const char *ip1, const char *ip2, bool with_port, int res) { @@ -299,6 +313,11 @@ int main(int argc, char *argv[]) test_sock_addr_from_string_bad("junk", false); test_sock_addr_from_string_bad("0.0.0.0:0 trailing junk", true); + test_sock_addr_from_string_memcmp("127.0.0.1", "127.0.0.1"); + test_sock_addr_from_string_memcmp("fe80::6af7:28ff:fefa:d136", + "fe80::6af7:28ff:fefa:d136"); + test_sock_addr_from_string_memcmp("::ffff:192.0.2.128", "192.0.2.128"); + test_sock_addr_cmp("127.0.0.1", "127.0.0.1" , false, 0); test_sock_addr_cmp("127.0.0.1", "127.0.0.2" , false, -1); test_sock_addr_cmp("127.0.0.2", "127.0.0.1" , false, 1); -- 2.20.1