From: Ronnie Sahlberg Date: Wed, 11 Jul 2007 23:22:06 +0000 (+1000) Subject: as an optimization for when we want to send multiple tickles at a time X-Git-Tag: tevent-0.9.20~348^2~2452^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a6504976808d2e2d7d5455b825bf978915d0cbbf;p=thirdparty%2Fsamba.git as an optimization for when we want to send multiple tickles at a time 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 (This used to be ctdb commit 469f3fb238a0674a2b48fdf1a7e657e32428178a) --- diff --git a/ctdb/common/system.c b/ctdb/common/system.c index 207faa36cb2..8169a05c823 100644 --- a/ctdb/common/system.c +++ b/ctdb/common/system.c @@ -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; diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index ce457b655bf..505e97d9567 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -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); diff --git a/ctdb/server/ctdb_takeover.c b/ctdb/server/ctdb_takeover.c index 312f26afe9c..8f84bb7d0a7 100644 --- a/ctdb/server/ctdb_takeover.c +++ b/ctdb/server/ctdb_takeover.c @@ -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); diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c index 9f5f743823d..55609e4f3e5 100644 --- a/ctdb/tools/ctdb.c +++ b/ctdb/tools/ctdb.c @@ -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; }