ctdb-protocol: Add ctdb_connection_list utilities
authorMartin Schwenke <martin@meltin.net>
Mon, 4 Sep 2017 07:01:05 +0000 (17:01 +1000)
committerMartin Schwenke <martins@samba.org>
Tue, 19 Sep 2017 11:30:27 +0000 (13:30 +0200)
Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
ctdb/protocol/protocol_util.c
ctdb/protocol/protocol_util.h
ctdb/tests/src/protocol_util_test.c

index 2b6585b1958b6ef0d166588a8cafee78386e3531..68a470fc31679b07cb5fca2c0ca8fbe4f46d4e38 100644 (file)
@@ -512,3 +512,147 @@ int ctdb_connection_from_string(const char *str, bool client_first,
 
        return 0;
 }
+
+int ctdb_connection_list_add(struct ctdb_connection_list *conn_list,
+                            struct ctdb_connection *conn)
+{
+       uint32_t len;
+
+       if (conn_list == NULL) {
+               return EINVAL;
+       }
+
+       /* Ensure array is big enough */
+       len = talloc_array_length(conn_list->conn);
+       if (conn_list->num == len) {
+               conn_list->conn = talloc_realloc(conn_list, conn_list->conn,
+                                                struct ctdb_connection,
+                                                len+128);
+               if (conn_list->conn == NULL) {
+                       return ENOMEM;
+               }
+       }
+
+       conn_list->conn[conn_list->num] = *conn;
+       conn_list->num++;
+
+       return 0;
+}
+
+static int connection_cmp(const void *a, const void *b)
+{
+       const struct ctdb_connection *conn_a = a;
+       const struct ctdb_connection *conn_b = b;
+       int ret;
+
+       ret = ctdb_sock_addr_cmp(&conn_a->server, &conn_b->server);
+       if (ret == 0) {
+               ret = ctdb_sock_addr_cmp(&conn_a->client, &conn_b->client);
+       }
+
+       return ret;
+}
+
+int ctdb_connection_list_sort(struct ctdb_connection_list *conn_list)
+{
+       if (conn_list == NULL) {
+               return EINVAL;
+       }
+
+       if (conn_list->num > 0) {
+               qsort(conn_list->conn, conn_list->num,
+                     sizeof(struct ctdb_connection), connection_cmp);
+       }
+
+       return 0;
+}
+
+const char *ctdb_connection_list_to_string(
+       TALLOC_CTX *mem_ctx,
+       struct ctdb_connection_list *conn_list, bool client_first)
+{
+       uint32_t i;
+       char *out;
+
+       out = talloc_strdup(mem_ctx, "");
+       if (out == NULL) {
+               return NULL;
+       }
+
+       if (conn_list == NULL || conn_list->num == 0) {
+               return out;
+       }
+
+       for (i = 0; i < conn_list->num; i++) {
+               char buf[128];
+               int ret;
+
+               ret = ctdb_connection_to_buf(buf, sizeof(buf),
+                                            &conn_list->conn[i], client_first);
+               if (ret != 0) {
+                       talloc_free(out);
+                       return NULL;
+               }
+
+               out = talloc_asprintf_append(out, "%s\n", buf);
+               if (out == NULL) {
+                       return NULL;
+               }
+       }
+
+       return out;
+}
+
+int ctdb_connection_list_read(TALLOC_CTX *mem_ctx, bool client_first,
+                             struct ctdb_connection_list **conn_list)
+{
+       struct ctdb_connection_list *list;
+       char line[128]; /* long enough for IPv6 */
+       int ret;
+
+       if (conn_list == NULL) {
+               return EINVAL;
+       }
+
+       list = talloc_zero(mem_ctx, struct ctdb_connection_list);
+       if (list == NULL) {
+               return ENOMEM;
+       }
+
+       while (fgets(line, sizeof(line), stdin) != NULL) {
+               char *t;
+               struct ctdb_connection conn;
+
+               /* Skip empty lines */
+               if (line[0] == '\n') {
+                       continue;
+               }
+
+               /* Comment */
+               if (line[0] == '#') {
+                       continue;
+               }
+
+               t = strtok(line, "\n");
+               if (t == NULL) {
+                       goto fail;
+               }
+
+               ret = ctdb_connection_from_string(t, client_first, &conn);
+               if (ret != 0) {
+                       goto fail;
+               }
+
+               ret = ctdb_connection_list_add(list, &conn);
+               if (ret != 0) {
+                       goto fail;
+               }
+       }
+
+       *conn_list = list;
+       return 0;
+
+fail:
+       talloc_free(list);
+       return EINVAL;
+}
index ab2a20b4631e6352cdf443db364689a0e6eb4c5a..66a491365764ac76529f34abd6cd2d85730fb854 100644 (file)
@@ -60,4 +60,13 @@ const char *ctdb_connection_to_string(TALLOC_CTX *mem_ctx,
 int ctdb_connection_from_string(const char *str, bool client_first,
                                struct ctdb_connection *conn);
 
+int ctdb_connection_list_add(struct ctdb_connection_list *conn_list,
+                            struct ctdb_connection *conn);
+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,
+                             struct ctdb_connection_list **conn_list);
+
 #endif /* __CTDB_PROTOCOL_UTIL_H__ */
index 4ca70aef108956b959f9ac4ecca1505e600051d7..fd1b067941409c6407e9a436dadab1ae0d7c90dc 100644 (file)
@@ -144,6 +144,147 @@ static void test_connection_from_string_bad(const char *conn_str)
        assert(ret != 0);
 }
 
+/*
+ * Test connection list utilities
+ */
+
+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;
+       const char *t;
+       int ret;
+
+       tmp_ctx = talloc_new(NULL);
+       assert(tmp_ctx != NULL);
+
+       ret = pipe(pipefd);
+       assert(ret == 0);
+
+       pid = fork();
+       assert(pid != -1);
+
+       if (pid == 0) {
+               close(pipefd[0]);
+
+               ret = dup2(pipefd[1], STDOUT_FILENO);
+               assert(ret != -1);
+
+               close(pipefd[1]);
+
+               printf("%s", s1);
+               fflush(stdout);
+
+               exit(0);
+       }
+
+       close(pipefd[1]);
+
+       ret = dup2(pipefd[0], STDIN_FILENO);
+       assert(ret != -1);
+
+       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);
+
+       t = ctdb_connection_list_to_string(tmp_ctx, conn_list, false);
+       assert(t != NULL);
+       ret = strcmp(t, s2);
+       assert(ret == 0);
+
+       talloc_free(tmp_ctx);
+}
+
+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;
+       int ret;
+
+       tmp_ctx = talloc_new(NULL);
+       assert(tmp_ctx != NULL);
+
+       ret = pipe(pipefd);
+       assert(ret == 0);
+
+       pid = fork();
+       assert(pid != -1);
+
+       if (pid == 0) {
+               close(pipefd[0]);
+
+               ret = dup2(pipefd[1], STDOUT_FILENO);
+               assert(ret != -1);
+
+               close(pipefd[1]);
+
+               printf("%s", s1);
+               fflush(stdout);
+
+               exit(0);
+       }
+
+       close(pipefd[1]);
+
+       ret = dup2(pipefd[0], STDIN_FILENO);
+       assert(ret != -1);
+
+       close(pipefd[0]);
+
+       ret = ctdb_connection_list_read(tmp_ctx, false, &conn_list);
+       assert(ret != 0);
+
+       talloc_free(tmp_ctx);
+}
+
+/*
+ * Use macros for these to make them easy to concatenate
+ */
+
+#define CONN4 \
+"\
+127.0.0.1:12345 127.0.0.2:54321\n\
+127.0.0.2:12345 127.0.0.1:54322\n\
+127.0.0.1:12346 127.0.0.2:54323\n\
+127.0.0.2:12345 127.0.0.1:54324\n\
+127.0.0.1:12345 127.0.0.2:54325\n\
+"
+
+#define CONN4_SORT \
+"\
+127.0.0.1:12345 127.0.0.2:54321\n\
+127.0.0.1:12345 127.0.0.2:54325\n\
+127.0.0.1:12346 127.0.0.2:54323\n\
+127.0.0.2:12345 127.0.0.1:54322\n\
+127.0.0.2:12345 127.0.0.1:54324\n\
+"
+
+#define CONN6 \
+"\
+fe80::6af7:28ff:fefa:d136:12345 fe80::6af7:28ff:fefa:d137:54321\n\
+fe80::6af7:28ff:fefa:d138:12345 fe80::6af7:28ff:fefa:d137:54322\n\
+fe80::6af7:28ff:fefa:d136:12346 fe80::6af7:28ff:fefa:d137:54323\n\
+fe80::6af7:28ff:fefa:d132:12345 fe80::6af7:28ff:fefa:d137:54324\n\
+fe80::6af7:28ff:fefa:d136:12345 fe80::6af7:28ff:fefa:d137:54325\n\
+"
+
+#define CONN6_SORT \
+"\
+fe80::6af7:28ff:fefa:d132:12345 fe80::6af7:28ff:fefa:d137:54324\n\
+fe80::6af7:28ff:fefa:d136:12345 fe80::6af7:28ff:fefa:d137:54321\n\
+fe80::6af7:28ff:fefa:d136:12345 fe80::6af7:28ff:fefa:d137:54325\n\
+fe80::6af7:28ff:fefa:d136:12346 fe80::6af7:28ff:fefa:d137:54323\n\
+fe80::6af7:28ff:fefa:d138:12345 fe80::6af7:28ff:fefa:d137:54322\n\
+"
+
 int main(int argc, char *argv[])
 {
        test_sock_addr_to_string("0.0.0.0", false);
@@ -194,5 +335,16 @@ int main(int argc, char *argv[])
        test_connection_from_string_bad("Junk!");
        test_connection_from_string_bad("More junk");
 
+       test_connection_list_read(CONN4, CONN4_SORT);
+       test_connection_list_read(CONN6, CONN6_SORT);
+       test_connection_list_read(CONN4 CONN6, CONN4_SORT CONN6_SORT);
+       test_connection_list_read(CONN4 "# Comment\n\n# Comment\n" CONN6,
+                                 CONN4_SORT CONN6_SORT);
+
+       test_connection_list_read_bad(CONN4 "# Comment\n\nJunk!!!\n" CONN6);
+       test_connection_list_read_bad(CONN4
+                                     "# Comment\n\n127.0.0.1: 127.0.0.1:124\n"
+                                     CONN6);
+
        return 0;
 }