ctdb-killtcp: Merge "common" killtcp code into helper
authorMartin Schwenke <martin@meltin.net>
Fri, 11 Mar 2016 05:04:30 +0000 (16:04 +1100)
committerAmitay Isaacs <amitay@samba.org>
Fri, 1 Apr 2016 02:42:12 +0000 (04:42 +0200)
ctdb_killtcp.c is now the only place it is needed.

Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
ctdb/server/killtcp.c [deleted file]
ctdb/server/killtcp.h [deleted file]
ctdb/tools/ctdb_killtcp.c
ctdb/wscript

diff --git a/ctdb/server/killtcp.c b/ctdb/server/killtcp.c
deleted file mode 100644 (file)
index ff32fdc..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
-   CTDB TCP connection killing code
-
-   Copyright (C) Ronnie Sahlberg  2007
-   Copyright (C) Andrew Tridgell  2007
-   Copyright (C) Martin Schwenke  2016
-
-   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 <http://www.gnu.org/licenses/>.
-*/
-
-#include "replace.h"
-#include "system/network.h"
-
-#include "lib/util/debug.h"
-
-#include "protocol/protocol.h"
-#include "protocol/protocol_api.h"
-
-#include "common/rb_tree.h"
-#include "common/system.h"
-#include "common/logging.h"
-
-#include "killtcp.h"
-
-/* TCP connection to be killed */
-struct ctdb_killtcp_con {
-       ctdb_sock_addr src_addr;
-       ctdb_sock_addr dst_addr;
-       int count;
-       struct ctdb_kill_tcp *killtcp;
-};
-
-/* this function is used to create a key to represent this socketpair
-   in the killtcp tree.
-   this key is used to insert and lookup matching socketpairs that are
-   to be tickled and RST
-*/
-#define KILLTCP_KEYLEN 10
-static uint32_t *killtcp_key(ctdb_sock_addr *src, ctdb_sock_addr *dst)
-{
-       static uint32_t key[KILLTCP_KEYLEN];
-
-       bzero(key, sizeof(key));
-
-       if (src->sa.sa_family != dst->sa.sa_family) {
-               DEBUG(DEBUG_ERR, (__location__ " ERROR, different families passed :%u vs %u\n", src->sa.sa_family, dst->sa.sa_family));
-               return key;
-       }
-
-       switch (src->sa.sa_family) {
-       case AF_INET:
-               key[0]  = dst->ip.sin_addr.s_addr;
-               key[1]  = src->ip.sin_addr.s_addr;
-               key[2]  = dst->ip.sin_port;
-               key[3]  = src->ip.sin_port;
-               break;
-       case AF_INET6: {
-               uint32_t *dst6_addr32 =
-                       (uint32_t *)&(dst->ip6.sin6_addr.s6_addr);
-               uint32_t *src6_addr32 =
-                       (uint32_t *)&(src->ip6.sin6_addr.s6_addr);
-               key[0]  = dst6_addr32[3];
-               key[1]  = src6_addr32[3];
-               key[2]  = dst6_addr32[2];
-               key[3]  = src6_addr32[2];
-               key[4]  = dst6_addr32[1];
-               key[5]  = src6_addr32[1];
-               key[6]  = dst6_addr32[0];
-               key[7]  = src6_addr32[0];
-               key[8]  = dst->ip6.sin6_port;
-               key[9]  = src->ip6.sin6_port;
-               break;
-       }
-       default:
-               DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family passed :%u\n", src->sa.sa_family));
-               return key;
-       }
-
-       return key;
-}
-
-/*
-  called when we get a read event on the raw socket
- */
-static void capture_tcp_handler(struct tevent_context *ev,
-                               struct tevent_fd *fde,
-                               uint16_t flags, void *private_data)
-{
-       struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
-       struct ctdb_killtcp_con *con;
-       ctdb_sock_addr src, dst;
-       uint32_t ack_seq, seq;
-
-       if (!(flags & TEVENT_FD_READ)) {
-               return;
-       }
-
-       if (ctdb_sys_read_tcp_packet(killtcp->capture_fd,
-                               killtcp->private_data,
-                               &src, &dst,
-                               &ack_seq, &seq) != 0) {
-               /* probably a non-tcp ACK packet */
-               return;
-       }
-
-       /* check if we have this guy in our list of connections
-          to kill
-       */
-       con = trbt_lookuparray32(killtcp->connections,
-                       KILLTCP_KEYLEN, killtcp_key(&src, &dst));
-       if (con == NULL) {
-               /* no this was some other packet we can just ignore */
-               return;
-       }
-
-       /* This one has been tickled !
-          now reset him and remove him from the list.
-        */
-       DEBUG(DEBUG_INFO,
-             ("sending a tcp reset to kill connection :%d -> %s:%d\n",
-              ntohs(con->dst_addr.ip.sin_port),
-              ctdb_sock_addr_to_string(con, &con->src_addr),
-              ntohs(con->src_addr.ip.sin_port)));
-
-       ctdb_sys_send_tcp(&con->dst_addr, &con->src_addr, ack_seq, seq, 1);
-       talloc_free(con);
-}
-
-
-/* when traversing the list of all tcp connections to send tickle acks to
-   (so that we can capture the ack coming back and kill the connection
-    by a RST)
-   this callback is called for each connection we are currently trying to kill
-*/
-static int tickle_connection_traverse(void *param, void *data)
-{
-       struct ctdb_killtcp_con *con = talloc_get_type(data, struct ctdb_killtcp_con);
-
-       /* have tried too many times, just give up */
-       if (con->count >= 5) {
-               /* can't delete in traverse: reparent to delete_cons */
-               talloc_steal(param, con);
-               return 0;
-       }
-
-       /* othervise, try tickling it again */
-       con->count++;
-       ctdb_sys_send_tcp(
-               (ctdb_sock_addr *)&con->dst_addr,
-               (ctdb_sock_addr *)&con->src_addr,
-               0, 0, 0);
-       return 0;
-}
-
-
-/*
-   called every second until all sentenced connections have been reset
- */
-static void ctdb_tickle_sentenced_connections(struct tevent_context *ev,
-                                             struct tevent_timer *te,
-                                             struct timeval t, void *private_data)
-{
-       struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
-       void *delete_cons = talloc_new(NULL);
-
-       /* loop over all connections sending tickle ACKs */
-       trbt_traversearray32(killtcp->connections, KILLTCP_KEYLEN, tickle_connection_traverse, delete_cons);
-
-       /* now we've finished traverse, it's safe to do deletion. */
-       talloc_free(delete_cons);
-
-       /* If there are no more connections to kill we can remove the
-          entire killtcp structure
-        */
-       if ((killtcp->connections == NULL) ||
-           (killtcp->connections->root == NULL)) {
-               talloc_free(killtcp);
-               return;
-       }
-
-       /* try tickling them again in a seconds time
-        */
-       tevent_add_timer(ev, killtcp,
-                        tevent_timeval_current_ofs(1, 0),
-                        ctdb_tickle_sentenced_connections, killtcp);
-}
-
-/* nothing fancy here, just unconditionally replace any existing
-   connection structure with the new one.
-
-   don't even free the old one if it did exist, that one is talloc_stolen
-   by the same node in the tree anyway and will be deleted when the new data
-   is deleted
-*/
-static void *add_killtcp_callback(void *parm, void *data)
-{
-       return parm;
-}
-
-/* Add a TCP socket to the list of connections we want to RST.  The
- * list is attached to *killtcp_arg.  If this is NULL then allocate
- * the structure.  */
-int ctdb_killtcp(struct tevent_context *ev,
-                TALLOC_CTX *mem_ctx,
-                const char *iface,
-                const ctdb_sock_addr *src,
-                const ctdb_sock_addr *dst,
-                struct ctdb_kill_tcp **killtcp_arg)
-{
-       struct ctdb_kill_tcp *killtcp;
-       struct ctdb_killtcp_con *con;
-
-       if (killtcp_arg == NULL) {
-               DEBUG(DEBUG_ERR, (__location__ " killtcp_arg is NULL!\n"));
-               return -1;
-       }
-
-       killtcp = *killtcp_arg;
-
-       /* Allocate a new structure if necessary.  The structure is
-        * only freed when mem_ctx is freed. */
-       if (killtcp == NULL) {
-               killtcp = talloc_zero(mem_ctx, struct ctdb_kill_tcp);
-               if (killtcp == NULL) {
-                       DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
-                       return -1;
-               }
-
-               killtcp->capture_fd  = -1;
-               killtcp->connections = trbt_create(killtcp, 0);
-               *killtcp_arg = killtcp;
-       }
-
-       /* create a structure that describes this connection we want to
-          RST and store it in killtcp->connections
-       */
-       con = talloc(killtcp, struct ctdb_killtcp_con);
-       if (con == NULL) {
-               DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
-               return -1;
-       }
-       con->src_addr = *src;
-       con->dst_addr = *dst;
-       con->count    = 0;
-       con->killtcp  = killtcp;
-
-
-       trbt_insertarray32_callback(killtcp->connections,
-                                   KILLTCP_KEYLEN,
-                                   killtcp_key(&con->dst_addr,
-                                               &con->src_addr),
-                                   add_killtcp_callback, con);
-
-       /*
-          If we don't have a socket to listen on yet we must create it
-        */
-       if (killtcp->capture_fd == -1) {
-               killtcp->capture_fd =
-                       ctdb_sys_open_capture_socket(iface,
-                                                    &killtcp->private_data);
-               if (killtcp->capture_fd == -1) {
-                       DEBUG(DEBUG_CRIT,(__location__ " Failed to open capturing "
-                                         "socket on iface '%s' for killtcp (%s)\n",
-                                         iface, strerror(errno)));
-                       return -1;
-               }
-       }
-
-
-       if (killtcp->fde == NULL) {
-               killtcp->fde = tevent_add_fd(ev, killtcp,
-                                            killtcp->capture_fd,
-                                            TEVENT_FD_READ,
-                                            capture_tcp_handler, killtcp);
-               tevent_fd_set_auto_close(killtcp->fde);
-
-               /* We also need to set up some events to tickle all these connections
-                  until they are all reset
-               */
-               tevent_add_timer(ev, killtcp, tevent_timeval_current_ofs(1, 0),
-                                ctdb_tickle_sentenced_connections, killtcp);
-       }
-
-       /* tickle him once now */
-       ctdb_sys_send_tcp(
-               &con->dst_addr,
-               &con->src_addr,
-               0, 0, 0);
-
-       return 0;
-}
diff --git a/ctdb/server/killtcp.h b/ctdb/server/killtcp.h
deleted file mode 100644 (file)
index 24ab351..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-   CTDB TCP connection killing code
-
-   Copyright (C) Ronnie Sahlberg  2007
-   Copyright (C) Andrew Tridgell  2007
-   Copyright (C) Martin Schwenke  2016
-
-   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 <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _CTDB_KILLTCP_H_
-#define _CTDB_KILLTCP_H_
-
-#include <talloc.h>
-#include <tevent.h>
-
-#include "replace.h"
-#include "system/network.h"
-
-#include "common/rb_tree.h"
-
-#include "protocol/protocol.h"
-
-/* Contains the listening socket and the list of TCP connections to
- * kill */
-struct ctdb_kill_tcp {
-       int capture_fd;
-       struct tevent_fd *fde;
-       trbt_tree_t *connections;
-       void *private_data;
-       void *destructor_data;
-};
-
-
-/* Add a TCP socket to the list of connections we want to RST.  The
- * list is attached to *killtcp_arg.  If this is NULL then allocate
- * the structure.  */
-int ctdb_killtcp(struct tevent_context *ev,
-                TALLOC_CTX *mem_ctx,
-                const char *iface,
-                const ctdb_sock_addr *src,
-                const ctdb_sock_addr *dst,
-                struct ctdb_kill_tcp **killtcp_arg);
-
-#endif /* _CTDB_KILLTCP_H_ */
index 3b1c4d927bc398fd0ef033d45740f1afddac776e..e6a19a75ca3a2fab49edfe6aac287e1f070a36e1 100644 (file)
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <talloc.h>
+#include <tevent.h>
+
 #include "replace.h"
 #include "system/network.h"
 
 #include "lib/util/debug.h"
 
 #include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
 
+#include "common/rb_tree.h"
 #include "common/system.h"
 #include "common/logging.h"
 
-#include "server/killtcp.h"
+
+/* Contains the listening socket and the list of TCP connections to
+ * kill */
+struct ctdb_kill_tcp {
+       int capture_fd;
+       struct tevent_fd *fde;
+       trbt_tree_t *connections;
+       void *private_data;
+       void *destructor_data;
+};
 
 static const char *prog;
 
+/* TCP connection to be killed */
+struct ctdb_killtcp_con {
+       ctdb_sock_addr src_addr;
+       ctdb_sock_addr dst_addr;
+       int count;
+       struct ctdb_kill_tcp *killtcp;
+};
+
+/* this function is used to create a key to represent this socketpair
+   in the killtcp tree.
+   this key is used to insert and lookup matching socketpairs that are
+   to be tickled and RST
+*/
+#define KILLTCP_KEYLEN 10
+static uint32_t *killtcp_key(ctdb_sock_addr *src, ctdb_sock_addr *dst)
+{
+       static uint32_t key[KILLTCP_KEYLEN];
+
+       bzero(key, sizeof(key));
+
+       if (src->sa.sa_family != dst->sa.sa_family) {
+               DEBUG(DEBUG_ERR, (__location__ " ERROR, different families passed :%u vs %u\n", src->sa.sa_family, dst->sa.sa_family));
+               return key;
+       }
+
+       switch (src->sa.sa_family) {
+       case AF_INET:
+               key[0]  = dst->ip.sin_addr.s_addr;
+               key[1]  = src->ip.sin_addr.s_addr;
+               key[2]  = dst->ip.sin_port;
+               key[3]  = src->ip.sin_port;
+               break;
+       case AF_INET6: {
+               uint32_t *dst6_addr32 =
+                       (uint32_t *)&(dst->ip6.sin6_addr.s6_addr);
+               uint32_t *src6_addr32 =
+                       (uint32_t *)&(src->ip6.sin6_addr.s6_addr);
+               key[0]  = dst6_addr32[3];
+               key[1]  = src6_addr32[3];
+               key[2]  = dst6_addr32[2];
+               key[3]  = src6_addr32[2];
+               key[4]  = dst6_addr32[1];
+               key[5]  = src6_addr32[1];
+               key[6]  = dst6_addr32[0];
+               key[7]  = src6_addr32[0];
+               key[8]  = dst->ip6.sin6_port;
+               key[9]  = src->ip6.sin6_port;
+               break;
+       }
+       default:
+               DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family passed :%u\n", src->sa.sa_family));
+               return key;
+       }
+
+       return key;
+}
+
+/*
+  called when we get a read event on the raw socket
+ */
+static void capture_tcp_handler(struct tevent_context *ev,
+                               struct tevent_fd *fde,
+                               uint16_t flags, void *private_data)
+{
+       struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
+       struct ctdb_killtcp_con *con;
+       ctdb_sock_addr src, dst;
+       uint32_t ack_seq, seq;
+
+       if (!(flags & TEVENT_FD_READ)) {
+               return;
+       }
+
+       if (ctdb_sys_read_tcp_packet(killtcp->capture_fd,
+                               killtcp->private_data,
+                               &src, &dst,
+                               &ack_seq, &seq) != 0) {
+               /* probably a non-tcp ACK packet */
+               return;
+       }
+
+       /* check if we have this guy in our list of connections
+          to kill
+       */
+       con = trbt_lookuparray32(killtcp->connections,
+                       KILLTCP_KEYLEN, killtcp_key(&src, &dst));
+       if (con == NULL) {
+               /* no this was some other packet we can just ignore */
+               return;
+       }
+
+       /* This one has been tickled !
+          now reset him and remove him from the list.
+        */
+       DEBUG(DEBUG_INFO,
+             ("sending a tcp reset to kill connection :%d -> %s:%d\n",
+              ntohs(con->dst_addr.ip.sin_port),
+              ctdb_sock_addr_to_string(con, &con->src_addr),
+              ntohs(con->src_addr.ip.sin_port)));
+
+       ctdb_sys_send_tcp(&con->dst_addr, &con->src_addr, ack_seq, seq, 1);
+       talloc_free(con);
+}
+
+
+/* when traversing the list of all tcp connections to send tickle acks to
+   (so that we can capture the ack coming back and kill the connection
+    by a RST)
+   this callback is called for each connection we are currently trying to kill
+*/
+static int tickle_connection_traverse(void *param, void *data)
+{
+       struct ctdb_killtcp_con *con = talloc_get_type(data, struct ctdb_killtcp_con);
+
+       /* have tried too many times, just give up */
+       if (con->count >= 5) {
+               /* can't delete in traverse: reparent to delete_cons */
+               talloc_steal(param, con);
+               return 0;
+       }
+
+       /* othervise, try tickling it again */
+       con->count++;
+       ctdb_sys_send_tcp(
+               (ctdb_sock_addr *)&con->dst_addr,
+               (ctdb_sock_addr *)&con->src_addr,
+               0, 0, 0);
+       return 0;
+}
+
+
+/*
+   called every second until all sentenced connections have been reset
+ */
+static void ctdb_tickle_sentenced_connections(struct tevent_context *ev,
+                                             struct tevent_timer *te,
+                                             struct timeval t, void *private_data)
+{
+       struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
+       void *delete_cons = talloc_new(NULL);
+
+       /* loop over all connections sending tickle ACKs */
+       trbt_traversearray32(killtcp->connections, KILLTCP_KEYLEN, tickle_connection_traverse, delete_cons);
+
+       /* now we've finished traverse, it's safe to do deletion. */
+       talloc_free(delete_cons);
+
+       /* If there are no more connections to kill we can remove the
+          entire killtcp structure
+        */
+       if ((killtcp->connections == NULL) ||
+           (killtcp->connections->root == NULL)) {
+               talloc_free(killtcp);
+               return;
+       }
+
+       /* try tickling them again in a seconds time
+        */
+       tevent_add_timer(ev, killtcp,
+                        tevent_timeval_current_ofs(1, 0),
+                        ctdb_tickle_sentenced_connections, killtcp);
+}
+
+/* nothing fancy here, just unconditionally replace any existing
+   connection structure with the new one.
+
+   don't even free the old one if it did exist, that one is talloc_stolen
+   by the same node in the tree anyway and will be deleted when the new data
+   is deleted
+*/
+static void *add_killtcp_callback(void *parm, void *data)
+{
+       return parm;
+}
+
+/* Add a TCP socket to the list of connections we want to RST.  The
+ * list is attached to *killtcp_arg.  If this is NULL then allocate
+ * the structure.  */
+static int ctdb_killtcp(struct tevent_context *ev,
+                       TALLOC_CTX *mem_ctx,
+                       const char *iface,
+                       const ctdb_sock_addr *src,
+                       const ctdb_sock_addr *dst,
+                       struct ctdb_kill_tcp **killtcp_arg)
+{
+       struct ctdb_kill_tcp *killtcp;
+       struct ctdb_killtcp_con *con;
+
+       if (killtcp_arg == NULL) {
+               DEBUG(DEBUG_ERR, (__location__ " killtcp_arg is NULL!\n"));
+               return -1;
+       }
+
+       killtcp = *killtcp_arg;
+
+       /* Allocate a new structure if necessary.  The structure is
+        * only freed when mem_ctx is freed. */
+       if (killtcp == NULL) {
+               killtcp = talloc_zero(mem_ctx, struct ctdb_kill_tcp);
+               if (killtcp == NULL) {
+                       DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
+                       return -1;
+               }
+
+               killtcp->capture_fd  = -1;
+               killtcp->connections = trbt_create(killtcp, 0);
+               *killtcp_arg = killtcp;
+       }
+
+       /* create a structure that describes this connection we want to
+          RST and store it in killtcp->connections
+       */
+       con = talloc(killtcp, struct ctdb_killtcp_con);
+       if (con == NULL) {
+               DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
+               return -1;
+       }
+       con->src_addr = *src;
+       con->dst_addr = *dst;
+       con->count    = 0;
+       con->killtcp  = killtcp;
+
+
+       trbt_insertarray32_callback(killtcp->connections,
+                                   KILLTCP_KEYLEN,
+                                   killtcp_key(&con->dst_addr,
+                                               &con->src_addr),
+                                   add_killtcp_callback, con);
+
+       /*
+          If we don't have a socket to listen on yet we must create it
+        */
+       if (killtcp->capture_fd == -1) {
+               killtcp->capture_fd =
+                       ctdb_sys_open_capture_socket(iface,
+                                                    &killtcp->private_data);
+               if (killtcp->capture_fd == -1) {
+                       DEBUG(DEBUG_CRIT,(__location__ " Failed to open capturing "
+                                         "socket on iface '%s' for killtcp (%s)\n",
+                                         iface, strerror(errno)));
+                       return -1;
+               }
+       }
+
+
+       if (killtcp->fde == NULL) {
+               killtcp->fde = tevent_add_fd(ev, killtcp,
+                                            killtcp->capture_fd,
+                                            TEVENT_FD_READ,
+                                            capture_tcp_handler, killtcp);
+               tevent_fd_set_auto_close(killtcp->fde);
+
+               /* We also need to set up some events to tickle all these connections
+                  until they are all reset
+               */
+               tevent_add_timer(ev, killtcp, tevent_timeval_current_ofs(1, 0),
+                                ctdb_tickle_sentenced_connections, killtcp);
+       }
+
+       /* tickle him once now */
+       ctdb_sys_send_tcp(
+               &con->dst_addr,
+               &con->src_addr,
+               0, 0, 0);
+
+       return 0;
+}
+
 static int ctdb_killtcp_destructor(struct ctdb_kill_tcp *killtcp)
 {
        bool *done = killtcp->destructor_data;
index a73910b8193958fdef25da18ad13e157ca32c678..41048fb8fc8fe27368bd68b8d9f2e6ed645a8cd1 100755 (executable)
@@ -421,7 +421,7 @@ def build(bld):
                      manpages='ctdb.1')
 
     bld.SAMBA_BINARY('ctdb_killtcp',
-                     source='tools/ctdb_killtcp.c server/killtcp.c',
+                     source='tools/ctdb_killtcp.c',
                      deps='''ctdb-protocol ctdb-util ctdb-system
                              samba-util replace''',
                      install_path='${CTDB_HELPER_BINDIR}')