as an optimization for when we want to send multiple tickles at a time
authorRonnie Sahlberg <sahlberg@ronnie>
Wed, 11 Jul 2007 23:22:06 +0000 (09:22 +1000)
committerRonnie Sahlberg <sahlberg@ronnie>
Wed, 11 Jul 2007 23:22:06 +0000 (09:22 +1000)
let the caller create the sending socket and use a single socket instead
of one new one for each tickle.
pass a sending socket to ctdb_sys_send_tcp()

ctdb_sys_kill_tcp is not longer used so remove it

set the socketflags for close on exec and nonblocking in the helper that
creates the sockets instead of in the caller

add a helper to create a sending socket to send tickles from

common/system.c
include/ctdb_private.h
server/ctdb_takeover.c
tools/ctdb.c

index 207faa36cb2f6b1b03b31829f6979a684c785049..8169a05c823f3c8503790ffc41ff70ca77b0b66b 100644 (file)
@@ -183,12 +183,12 @@ static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
   This can also be used to send RST segments (if rst is true) and also
   if correct seq and ack numbers are provided.
  */
-int ctdb_sys_send_tcp(const struct sockaddr_in *dest, 
+int ctdb_sys_send_tcp(int s,
+                     const struct sockaddr_in *dest, 
                      const struct sockaddr_in *src,
                      uint32_t seq, uint32_t ack, int rst)
 {
-       int s, ret;
-       uint32_t one = 1;
+       int ret;
        struct {
                struct iphdr ip;
                struct tcphdr tcp;
@@ -200,21 +200,6 @@ int ctdb_sys_send_tcp(const struct sockaddr_in *dest,
                return -1;
        }
 
-       s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
-       if (s == -1) {
-               DEBUG(0,(__location__ " failed to open raw socket (%s)\n",
-                        strerror(errno)));
-               return -1;
-       }
-
-       ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
-       if (ret != 0) {
-               DEBUG(0,(__location__ " failed to setup IP headers (%s)\n",
-                        strerror(errno)));
-               close(s);
-               return -1;
-       }
-
        ZERO_STRUCT(pkt);
        pkt.ip.version  = 4;
        pkt.ip.ihl      = sizeof(pkt.ip)/4;
@@ -240,11 +225,9 @@ int ctdb_sys_send_tcp(const struct sockaddr_in *dest,
        ret = sendto(s, &pkt, sizeof(pkt), 0, dest, sizeof(*dest));
        if (ret != sizeof(pkt)) {
                DEBUG(0,(__location__ " failed sendto (%s)\n", strerror(errno)));
-               close(s);
                return -1;
        }
 
-       close(s);
        return 0;
 }
 
@@ -273,30 +256,11 @@ bool ctdb_sys_have_ip(const char *ip)
        return ret == 0;
 }
 
-static void ctdb_wait_handler(struct event_context *ev, struct timed_event *te, 
-                             struct timeval yt, void *p)
-{
-       uint32_t *timed_out = (uint32_t *)p;
-       (*timed_out) = 1;
-}
-
-/* This function is used to kill (RST) the specified tcp connection.
-
-   This function is not asynchronous and will block until the operation
-   was successful or it timesout.
+/* This function is used to open a raw socket to capture from
  */
-int ctdb_sys_kill_tcp(struct event_context *ev,
-                     const struct sockaddr_in *dst, 
-                     const struct sockaddr_in *src)
+int ctdb_sys_open_capture_socket(void)
 {
-       int s, ret;
-       uint32_t timedout;
-       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
-#define RCVPKTSIZE 100
-       char pkt[RCVPKTSIZE];
-       struct ether_header *eth;
-       struct iphdr *ip;
-       struct tcphdr *tcp;
+       int s;
 
        /* Open a socket to capture all traffic */
        s=socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
@@ -305,103 +269,41 @@ int ctdb_sys_kill_tcp(struct event_context *ev,
                return -1;
        }
 
-       /* We wait for up to 1 second for the ACK coming back */
-       timedout = 0;
-       event_add_timed(ev, tmp_ctx, timeval_current_ofs(1, 0), ctdb_wait_handler, &timedout);
-
-       /* Send a tickle ack to probe what the real seq/ack numbers are */
-       ctdb_sys_send_tcp(dst, src, 0, 0, 0);
-
-       /* Wait until we either time out or we succeeds in sending the RST */
-       while (timedout==0) {
-               event_loop_once(ev);
-
-               ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
-               if (ret < sizeof(*eth)+sizeof(*ip)) {
-                       continue;
-               }
-
-               /* Ethernet */
-               eth = (struct ether_header *)pkt;
-               /* We only want IP packets */
-               if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
-                       continue;
-               }
-       
-               /* IP */
-               ip = (struct iphdr *)(eth+1);
-               /* We only want IPv4 packets */
-               if (ip->version != 4) {
-                       continue;
-               }
-               /* Dont look at fragments */
-               if ((ntohs(ip->frag_off)&0x1fff) != 0) {
-                       continue;
-               }
-               /* we only want TCP */
-               if (ip->protocol != IPPROTO_TCP) {
-                       continue;
-               }
-
-               /* We only want packets sent from the guy we tickled */
-               if (ip->saddr != dst->sin_addr.s_addr) {
-                       continue;
-               }
-               /* We only want packets sent to us */
-               if (ip->daddr != src->sin_addr.s_addr) {
-                       continue;
-               }
-
-               /* make sure its not a short packet */
-               if (offsetof(struct tcphdr, ack_seq) + 4 + 
-                   (ip->ihl*4) + sizeof(*eth) > ret) {
-                       continue;
-               }
-
-               /* TCP */
-               tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
-               
-               /* We only want replies from the port we tickled */
-               if (tcp->source != dst->sin_port) {
-                       continue;
-               }
-               if (tcp->dest != src->sin_port) {
-                       continue;
-               }
-
-               ctdb_sys_send_tcp(dst, src, tcp->ack_seq, tcp->seq, 1);
-
-               close(s);
-               talloc_free(tmp_ctx);
-
-               return 0;
-       }
-
-       close(s);
-       talloc_free(tmp_ctx);
-       DEBUG(0,(__location__ " timedout waiting for tickle ack reply\n"));
+       set_nonblocking(s);
+       set_close_on_exec(s);
 
-       return -1;
+       return s;
 }
 
-
-
-/* This function is used to open a raw socket to capture from
+/* This function is used to open a raw socket to send tickles from
  */
-int ctdb_sys_open_capture_socket(void)
+int ctdb_sys_open_sending_socket(void)
 {
-       int s;
+       int s, ret;
+       uint32_t one = 1;
 
-       /* Open a socket to capture all traffic */
-       s=socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-       if (s == -1){
-               DEBUG(0,(__location__ " failed to open raw socket\n"));
+       s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
+       if (s == -1) {
+               DEBUG(0,(__location__ " failed to open raw socket (%s)\n",
+                        strerror(errno)));
+               return -1;
+       }
+
+       ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
+       if (ret != 0) {
+               DEBUG(0,(__location__ " failed to setup IP headers (%s)\n",
+                        strerror(errno)));
+               close(s);
                return -1;
        }
 
+       set_nonblocking(s);
+       set_close_on_exec(s);
+
        return s;
 }
 
+
 int ctdb_sys_read_tcp_packet(struct ctdb_kill_tcp *killtcp)
 {
        int ret;
@@ -469,7 +371,7 @@ int ctdb_sys_read_tcp_packet(struct ctdb_kill_tcp *killtcp)
                /* This one has been tickled !
                   now reset him and remove him from the list.
                 */
-               ctdb_sys_send_tcp(&conn->dst, &conn->src, tcp->ack_seq, tcp->seq, 1);
+               ctdb_sys_send_tcp(killtcp->sending_fd, &conn->dst, &conn->src, tcp->ack_seq, tcp->seq, 1);
                talloc_free(conn);
 
                return 0;
index ce457b655bf54d5515b099e27fdd0330551973f4..505e97d95672e54f100e6ff8822e5d953cf12fb4 100644 (file)
@@ -990,12 +990,10 @@ int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
 /* from takeover/system.c */
 int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface);
 bool ctdb_sys_have_ip(const char *ip);
-int ctdb_sys_send_tcp(const struct sockaddr_in *dest, 
+int ctdb_sys_send_tcp(int fd,
+                     const struct sockaddr_in *dest, 
                      const struct sockaddr_in *src,
                      uint32_t seq, uint32_t ack, int rst);
-int ctdb_sys_kill_tcp(struct event_context *ev,
-                     const struct sockaddr_in *dest, 
-                     const struct sockaddr_in *src);
 
 int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist);
 int ctdb_set_event_script(struct ctdb_context *ctdb, const char *script);
@@ -1061,10 +1059,12 @@ struct ctdb_killtcp_connection {
 struct ctdb_kill_tcp {
        struct ctdb_context *ctdb;
        int capture_fd;
+       int sending_fd;
        struct fd_event *fde;
        struct ctdb_killtcp_connection *connections;
 };
 int ctdb_sys_open_capture_socket(void);
+int ctdb_sys_open_sending_socket(void);
 int ctdb_killtcp_add_connection(struct ctdb_context *ctdb, struct sockaddr_in *src, struct sockaddr_in *dst);
 int ctdb_sys_read_tcp_packet(struct ctdb_kill_tcp *killtcp);
 
index 312f26afe9c4c3bfc9b6f3830fab4544a309c75e..8f84bb7d0a7cffeae3b9e0a568315bb4629199e7 100644 (file)
@@ -69,7 +69,7 @@ static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *
 {
        struct ctdb_takeover_arp *arp = talloc_get_type(private_data, 
                                                        struct ctdb_takeover_arp);
-       int ret;
+       int s, ret;
        struct ctdb_tcp_list *tcp;
 
        ret = ctdb_sys_send_arp(&arp->sin, arp->ctdb->takeover.interface);
@@ -77,25 +77,32 @@ static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *
                DEBUG(0,(__location__ " sending of arp failed (%s)\n", strerror(errno)));
        }
 
+       s = ctdb_sys_open_sending_socket();
+       if (s == -1) {
+               DEBUG(0,(__location__ " failed to open raw socket for sending tickles\n"));
+               return;
+       }
+
        for (tcp=arp->tcp_list;tcp;tcp=tcp->next) {
                DEBUG(2,("sending tcp tickle ack for %u->%s:%u\n",
                         (unsigned)ntohs(tcp->daddr.sin_port), 
                         inet_ntoa(tcp->saddr.sin_addr),
                         (unsigned)ntohs(tcp->saddr.sin_port)));
-               ret = ctdb_sys_send_tcp(&tcp->saddr, &tcp->daddr, 0, 0, 0);
+               ret = ctdb_sys_send_tcp(s, &tcp->saddr, &tcp->daddr, 0, 0, 0);
                if (ret != 0) {
                        DEBUG(0,(__location__ " Failed to send tcp tickle ack for %s\n",
                                 inet_ntoa(tcp->saddr.sin_addr)));
                }
        }
 
+       close(s);
        arp->count++;
 
        if (arp->count == CTDB_ARP_REPEAT) {
                talloc_free(arp);
                return;
        }
-       
+
        event_add_timed(arp->ctdb->ev, arp->ctdb->takeover.last_ctx, 
                        timeval_current_ofs(CTDB_ARP_INTERVAL, 0), 
                        ctdb_control_send_arp, arp);
@@ -869,7 +876,7 @@ static void ctdb_tickle_sentenced_connections(struct event_context *ev, struct t
 
                        continue;
                }
-               ctdb_sys_send_tcp(&conn->dst, &conn->src, 0, 0, 0);
+               ctdb_sys_send_tcp(killtcp->sending_fd, &conn->dst, &conn->src, 0, 0, 0);
        }
 
        /* If there are no more connections to kill we can remove the
@@ -891,8 +898,14 @@ static void ctdb_tickle_sentenced_connections(struct event_context *ev, struct t
  */
 static int ctdb_killtcp_destructor(struct ctdb_kill_tcp *killtcp)
 {
-       close(killtcp->capture_fd);
-       killtcp->capture_fd    = -1;
+       if (killtcp->capture_fd != -1) {
+               close(killtcp->capture_fd);
+               killtcp->capture_fd    = -1;
+       }
+       if (killtcp->sending_fd != -1) {
+               close(killtcp->sending_fd);
+               killtcp->sending_fd    = -1;
+       }
        killtcp->ctdb->killtcp = NULL;
 
        return 0;
@@ -921,6 +934,7 @@ int ctdb_killtcp_add_connection(struct ctdb_context *ctdb, struct sockaddr_in *s
 
                killtcp->ctdb        = ctdb;
                killtcp->capture_fd  = -1;
+               killtcp->sending_fd  = -1;
                killtcp->connections = NULL;
                ctdb->killtcp        = killtcp;
                talloc_set_destructor(killtcp, ctdb_killtcp_destructor);
@@ -934,11 +948,17 @@ int ctdb_killtcp_add_connection(struct ctdb_context *ctdb, struct sockaddr_in *s
                        DEBUG(0,(__location__ " Failed to open capturing socket for killtcp\n"));
                        goto failed;
                }
-
-               set_nonblocking(killtcp->capture_fd);
-               set_close_on_exec(killtcp->capture_fd);
        }
 
+       /* If we dont have a socket to send from yet we must create it
+        */
+       if (killtcp->sending_fd == -1) {
+               killtcp->sending_fd = ctdb_sys_open_sending_socket();
+               if (killtcp->sending_fd == -1) {
+                       DEBUG(0,(__location__ " Failed to open sending socket for killtcp\n"));
+                       goto failed;
+               }
+       }
 
        conn = talloc(killtcp, struct ctdb_killtcp_connection);
        CTDB_NO_MEMORY(ctdb, conn);
index 9f5f743823dcae0cfcab7ea9d293652f95b5063c..55609e4f3e58bd3e5486eaa56fa4ea7056ebe5d8 100644 (file)
@@ -338,7 +338,7 @@ static int kill_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
  */
 static int tickle_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-       int ret;
+       int s, ret;
        struct sockaddr_in src, dst;
 
        if (argc < 2) {
@@ -355,7 +355,14 @@ static int tickle_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
                return -1;
        }
 
-       ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
+       s = ctdb_sys_open_sending_socket();
+       if (s == -1) {
+               printf("Failed to open socket for sending tickle\n");
+               return 0;
+       }
+
+       ret = ctdb_sys_send_tcp(s, &src, &dst, 0, 0, 0);
+       close(s);
        if (ret==0) {
                return 0;
        }