2 CTDB protocol marshalling
4 Copyright (C) Amitay Isaacs 2015
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/network.h"
26 #include "protocol_util.h"
29 enum ctdb_runstate runstate;
32 { CTDB_RUNSTATE_UNKNOWN, "UNKNOWN" },
33 { CTDB_RUNSTATE_INIT, "INIT" },
34 { CTDB_RUNSTATE_SETUP, "SETUP" },
35 { CTDB_RUNSTATE_FIRST_RECOVERY, "FIRST_RECOVERY" },
36 { CTDB_RUNSTATE_STARTUP, "STARTUP" },
37 { CTDB_RUNSTATE_RUNNING, "RUNNING" },
38 { CTDB_RUNSTATE_SHUTDOWN, "SHUTDOWN" },
42 const char *ctdb_runstate_to_string(enum ctdb_runstate runstate)
46 for (i=0; runstate_map[i].label != NULL; i++) {
47 if (runstate_map[i].runstate == runstate) {
48 return runstate_map[i].label;
52 return runstate_map[0].label;
55 enum ctdb_runstate ctdb_runstate_from_string(const char *runstate_str)
59 for (i=0; runstate_map[i].label != NULL; i++) {
60 if (strcasecmp(runstate_map[i].label,
62 return runstate_map[i].runstate;
66 return CTDB_RUNSTATE_UNKNOWN;
70 enum ctdb_event event;
73 { CTDB_EVENT_INIT, "init" },
74 { CTDB_EVENT_SETUP, "setup" },
75 { CTDB_EVENT_STARTUP, "startup" },
76 { CTDB_EVENT_START_RECOVERY, "startrecovery" },
77 { CTDB_EVENT_RECOVERED, "recovered" },
78 { CTDB_EVENT_TAKE_IP, "takeip" },
79 { CTDB_EVENT_RELEASE_IP, "releaseip" },
80 { CTDB_EVENT_MONITOR, "monitor" },
81 { CTDB_EVENT_SHUTDOWN, "shutdown" },
82 { CTDB_EVENT_UPDATE_IP, "updateip" },
83 { CTDB_EVENT_IPREALLOCATED, "ipreallocated" },
84 { CTDB_EVENT_MAX, "all" },
88 const char *ctdb_event_to_string(enum ctdb_event event)
92 for (i=0; event_map[i].label != NULL; i++) {
93 if (event_map[i].event == event) {
94 return event_map[i].label;
101 enum ctdb_event ctdb_event_from_string(const char *event_str)
105 for (i=0; event_map[i].label != NULL; i++) {
106 if (strcmp(event_map[i].label, event_str) == 0) {
107 return event_map[i].event;
111 return CTDB_EVENT_MAX;
114 int ctdb_sock_addr_to_buf(char *buf, socklen_t buflen,
115 ctdb_sock_addr *addr, bool with_port)
119 switch (addr->sa.sa_family) {
121 t = inet_ntop(addr->ip.sin_family, &addr->ip.sin_addr,
129 t = inet_ntop(addr->ip6.sin6_family, &addr->ip6.sin6_addr,
142 size_t len = strlen(buf);
145 ret = snprintf(buf+len, buflen-len,
146 ":%u", ctdb_sock_addr_port(addr));
147 if (ret >= buflen-len) {
155 const char *ctdb_sock_addr_to_string(TALLOC_CTX *mem_ctx,
156 ctdb_sock_addr *addr, bool with_port)
162 cip = talloc_size(mem_ctx, len);
168 ret = ctdb_sock_addr_to_buf(cip, len, addr, with_port);
177 static int ipv4_from_string(const char *str, struct sockaddr_in *ip)
181 *ip = (struct sockaddr_in) {
182 .sin_family = AF_INET,
185 ret = inet_pton(AF_INET, str, &ip->sin_addr);
190 #ifdef HAVE_SOCK_SIN_LEN
191 ip->sin_len = sizeof(*ip);
196 static int ipv6_from_string(const char *str, struct sockaddr_in6 *ip6)
200 *ip6 = (struct sockaddr_in6) {
201 .sin6_family = AF_INET6,
204 ret = inet_pton(AF_INET6, str, &ip6->sin6_addr);
209 #ifdef HAVE_SOCK_SIN6_LEN
210 ip6->sin6_len = sizeof(*ip6);
215 static int ip_from_string(const char *str, ctdb_sock_addr *addr)
224 ZERO_STRUCTP(addr); /* valgrind :-) */
226 /* IPv4 or IPv6 address?
228 * Use rindex() because we need the right-most ':' below for
229 * IPv4-mapped IPv6 addresses anyway...
231 p = rindex(str, ':');
233 ret = ipv4_from_string(str, &addr->ip);
235 uint8_t ipv4_mapped_prefix[12] = {
236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff
239 ret = ipv6_from_string(str, &addr->ip6);
245 * Check for IPv4-mapped IPv6 address
246 * (e.g. ::ffff:192.0.2.128) - reparse as IPv4 if
249 if (memcmp(&addr->ip6.sin6_addr.s6_addr[0],
251 sizeof(ipv4_mapped_prefix)) == 0) {
252 /* Reparse as IPv4 */
253 ret = ipv4_from_string(p+1, &addr->ip);
260 int ctdb_sock_addr_from_string(const char *str,
261 ctdb_sock_addr *addr, bool with_port)
264 char s[64]; /* Much longer than INET6_ADDRSTRLEN */
271 ret = ip_from_string(str, addr);
275 /* Parse out port number and then IP address */
277 len = strlcpy(s, str, sizeof(s));
278 if (len >= sizeof(s)) {
287 port = strtoul(p+1, &endp, 10);
288 if (endp == p+1 || *endp != '\0') {
289 /* Empty string or trailing garbage */
294 ret = ip_from_string(s, addr);
296 ctdb_sock_addr_set_port(addr, port);
301 unsigned int ctdb_sock_addr_port(ctdb_sock_addr *addr)
303 switch (addr->sa.sa_family) {
305 return ntohs(addr->ip.sin_port);
308 return ntohs(addr->ip6.sin6_port);
315 void ctdb_sock_addr_set_port(ctdb_sock_addr *addr, unsigned int port)
317 switch (addr->sa.sa_family) {
319 addr->ip.sin_port = htons(port);
322 addr->ip6.sin6_port = htons(port);
329 static int ctdb_sock_addr_cmp_family(const ctdb_sock_addr *addr1,
330 const ctdb_sock_addr *addr2)
332 /* This is somewhat arbitrary. However, when used for sorting
333 * it just needs to be consistent.
335 if (addr1->sa.sa_family < addr2->sa.sa_family) {
338 if (addr1->sa.sa_family > addr2->sa.sa_family) {
345 int ctdb_sock_addr_cmp_ip(const ctdb_sock_addr *addr1,
346 const ctdb_sock_addr *addr2)
350 ret = ctdb_sock_addr_cmp_family(addr1, addr2);
355 switch (addr1->sa.sa_family) {
357 ret = memcmp(&addr1->ip.sin_addr.s_addr,
358 &addr2->ip.sin_addr.s_addr, 4);
362 ret = memcmp(addr1->ip6.sin6_addr.s6_addr,
363 addr2->ip6.sin6_addr.s6_addr, 16);
373 int ctdb_sock_addr_cmp(const ctdb_sock_addr *addr1,
374 const ctdb_sock_addr *addr2)
378 ret = ctdb_sock_addr_cmp_ip(addr1, addr2);
383 switch (addr1->sa.sa_family) {
385 if (addr1->ip.sin_port < addr2->ip.sin_port) {
387 } else if (addr1->ip.sin_port > addr2->ip.sin_port) {
393 if (addr1->ip6.sin6_port < addr2->ip6.sin6_port) {
395 } else if (addr1->ip6.sin6_port > addr2->ip6.sin6_port) {
407 bool ctdb_sock_addr_same_ip(const ctdb_sock_addr *addr1,
408 const ctdb_sock_addr *addr2)
410 return (ctdb_sock_addr_cmp_ip(addr1, addr2) == 0);
413 bool ctdb_sock_addr_same(const ctdb_sock_addr *addr1,
414 const ctdb_sock_addr *addr2)
416 return (ctdb_sock_addr_cmp(addr1, addr2) == 0);
419 int ctdb_connection_to_buf(char *buf, size_t buflen,
420 struct ctdb_connection *conn, bool client_first)
422 char server[64], client[64];
425 ret = ctdb_sock_addr_to_buf(server, sizeof(server),
426 &conn->server, true);
431 ret = ctdb_sock_addr_to_buf(client, sizeof(client),
432 &conn->client, true);
437 if (! client_first) {
438 ret = snprintf(buf, buflen, "%s %s", server, client);
440 ret = snprintf(buf, buflen, "%s %s", client, server);
449 const char *ctdb_connection_to_string(TALLOC_CTX *mem_ctx,
450 struct ctdb_connection *conn,
453 const size_t len = 128;
457 out = talloc_size(mem_ctx, len);
462 ret = ctdb_connection_to_buf(out, len, conn, client_first);
471 int ctdb_connection_from_string(const char *str, bool client_first,
472 struct ctdb_connection *conn)
475 char *t1 = NULL, *t2 = NULL;
477 ctdb_sock_addr *first = (client_first ? &conn->client : &conn->server);
478 ctdb_sock_addr *second = (client_first ? &conn->server : &conn->client);
481 len = strlcpy(s, str, sizeof(s));
482 if (len >= sizeof(s)) {
486 t1 = strtok(s, " \t\n");
491 t2 = strtok(NULL, " \t\n\0");
496 ret = ctdb_sock_addr_from_string(t1, first, true);
501 ret = ctdb_sock_addr_from_string(t2, second, true);
506 ret = ctdb_sock_addr_cmp_family(first, second);
514 int ctdb_connection_list_add(struct ctdb_connection_list *conn_list,
515 struct ctdb_connection *conn)
519 if (conn_list == NULL) {
523 /* Ensure array is big enough */
524 len = talloc_array_length(conn_list->conn);
525 if (conn_list->num == len) {
526 conn_list->conn = talloc_realloc(conn_list, conn_list->conn,
527 struct ctdb_connection,
529 if (conn_list->conn == NULL) {
534 conn_list->conn[conn_list->num] = *conn;
540 static int connection_cmp(const void *a, const void *b)
542 const struct ctdb_connection *conn_a = a;
543 const struct ctdb_connection *conn_b = b;
546 ret = ctdb_sock_addr_cmp(&conn_a->server, &conn_b->server);
548 ret = ctdb_sock_addr_cmp(&conn_a->client, &conn_b->client);
554 int ctdb_connection_list_sort(struct ctdb_connection_list *conn_list)
556 if (conn_list == NULL) {
560 if (conn_list->num > 0) {
561 qsort(conn_list->conn, conn_list->num,
562 sizeof(struct ctdb_connection), connection_cmp);
568 const char *ctdb_connection_list_to_string(
570 struct ctdb_connection_list *conn_list, bool client_first)
575 out = talloc_strdup(mem_ctx, "");
580 if (conn_list == NULL || conn_list->num == 0) {
584 for (i = 0; i < conn_list->num; i++) {
588 ret = ctdb_connection_to_buf(buf, sizeof(buf),
589 &conn_list->conn[i], client_first);
595 out = talloc_asprintf_append(out, "%s\n", buf);
604 int ctdb_connection_list_read(TALLOC_CTX *mem_ctx, bool client_first,
605 struct ctdb_connection_list **conn_list)
607 struct ctdb_connection_list *list;
608 char line[128]; /* long enough for IPv6 */
611 if (conn_list == NULL) {
615 list = talloc_zero(mem_ctx, struct ctdb_connection_list);
620 while (fgets(line, sizeof(line), stdin) != NULL) {
622 struct ctdb_connection conn;
624 /* Skip empty lines */
625 if (line[0] == '\n') {
630 if (line[0] == '#') {
634 t = strtok(line, "\n");
639 ret = ctdb_connection_from_string(t, client_first, &conn);
644 ret = ctdb_connection_list_add(list, &conn);