diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index ca350df2cf4..80278123778 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -895,6 +895,9 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, int32_t ctdb_control_tcp_client_disconnected(struct ctdb_context *ctdb, uint32_t client_id, TDB_DATA indata); +int32_t ctdb_control_tcp_client_passed(struct ctdb_context *ctdb, + uint32_t client_id, + TDB_DATA indata); int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata, bool tcp_update_needed); int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata); diff --git a/ctdb/protocol/protocol.h b/ctdb/protocol/protocol.h index 42b992ae6db..3b66c403ab8 100644 --- a/ctdb/protocol/protocol.h +++ b/ctdb/protocol/protocol.h @@ -382,6 +382,7 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0, CTDB_CONTROL_DISABLE_NODE = 157, CTDB_CONTROL_ENABLE_NODE = 158, CTDB_CONTROL_TCP_CLIENT_DISCONNECTED = 159, + CTDB_CONTROL_TCP_CLIENT_PASSED = 160, }; #define MAX_COUNT_BUCKETS 16 diff --git a/ctdb/protocol/protocol_control.c b/ctdb/protocol/protocol_control.c index 5e2cf13c579..83ed6cb4ee1 100644 --- a/ctdb/protocol/protocol_control.c +++ b/ctdb/protocol/protocol_control.c @@ -414,6 +414,10 @@ static size_t ctdb_req_control_data_len(struct ctdb_req_control_data *cd) case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED: len = ctdb_connection_len(cd->data.conn); break; + + case CTDB_CONTROL_TCP_CLIENT_PASSED: + len = ctdb_connection_len(cd->data.conn); + break; } return len; @@ -1028,6 +1032,14 @@ static int ctdb_req_control_data_pull(uint8_t *buf, size_t buflen, &cd->data.conn, &np); break; + + case CTDB_CONTROL_TCP_CLIENT_PASSED: + ret = ctdb_connection_pull(buf, + buflen, + mem_ctx, + &cd->data.conn, + &np); + break; } if (ret != 0) { @@ -1391,6 +1403,9 @@ static size_t ctdb_reply_control_data_len(struct ctdb_reply_control_data *cd) case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED: break; + + case CTDB_CONTROL_TCP_CLIENT_PASSED: + break; } return len; diff --git a/ctdb/protocol/protocol_debug.c b/ctdb/protocol/protocol_debug.c index 2dc4a702eae..ae091b04d32 100644 --- a/ctdb/protocol/protocol_debug.c +++ b/ctdb/protocol/protocol_debug.c @@ -246,6 +246,7 @@ static void ctdb_opcode_print(uint32_t opcode, FILE *fp) { CTDB_CONTROL_DISABLE_NODE, "DISABLE_NODE" }, { CTDB_CONTROL_ENABLE_NODE, "ENABLE_NODE" }, { CTDB_CONTROL_TCP_CLIENT_DISCONNECTED, "TCP_CLIENT_DISCONNECTED" }, + { CTDB_CONTROL_TCP_CLIENT_PASSED, "TCP_CLIENT_PASSED" }, { MAP_END, "" }, }; diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c index 3ea93f52cfe..422c4cf1e58 100644 --- a/ctdb/server/ctdb_control.c +++ b/ctdb/server/ctdb_control.c @@ -872,6 +872,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection)); return ctdb_control_tcp_client_disconnected(ctdb, client_id, indata); + case CTDB_CONTROL_TCP_CLIENT_PASSED: + CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection)); + return ctdb_control_tcp_client_passed(ctdb, client_id, indata); + default: DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode)); return -1; diff --git a/ctdb/server/ctdb_takeover.c b/ctdb/server/ctdb_takeover.c index da3077e5140..1668e569739 100644 --- a/ctdb/server/ctdb_takeover.c +++ b/ctdb/server/ctdb_takeover.c @@ -1463,6 +1463,55 @@ int32_t ctdb_control_tcp_client_disconnected(struct ctdb_context *ctdb, return 0; } +/* + called by a client to inform us of a TCP connection was passed to a different + "client" (typically with multichannel to another smbd process). + */ +int32_t ctdb_control_tcp_client_passed(struct ctdb_context *ctdb, + uint32_t client_id, + TDB_DATA indata) +{ + struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client); + struct ctdb_connection *tcp_sock = NULL; + int ret; + char conn_str[132] = { 0, }; + bool found = false; + + tcp_sock = (struct ctdb_connection *)indata.dptr; + + ctdb_canonicalize_ip_inplace(&tcp_sock->src); + ctdb_canonicalize_ip_inplace(&tcp_sock->dst); + + ret = ctdb_connection_to_buf(conn_str, + sizeof(conn_str), + tcp_sock, + false, + " -> "); + if (ret != 0) { + strlcpy(conn_str, "UNKNOWN", sizeof(conn_str)); + } + + found = ctdb_client_remove_tcp(client, tcp_sock); + if (!found) { + DBG_DEBUG("TCP connection from %s not found " + "(client_id %u pid %u).\n", + conn_str, client_id, client->pid); + return 0; + } + + D_INFO("TCP connection from %s " + "(client_id %u pid %u) passed to another client\n", + conn_str, client_id, client->pid); + + /* + * We don't call CTDB_CONTROL_TCP_REMOVE + * nor ctdb_remove_connection() as the connection + * is still alive, but handled by another client + */ + + return 0; +} + /* find a tcp address on a list */