With multichannel a tcp connection is registered first with
a temporary smbd process, that calls CTDB_CONTROL_TCP_CLIENT
first and then passes the tcp connection to the longterm smbd
that already handles all connections belonging to the specific
client_guid. That smbd process calls CTDB_CONTROL_TCP_CLIENT
again, but the 'tickle' information is already there.
When the temporary smbd process exists/disconnects from ctdb
or calls CTDB_CONTROL_TCP_CLIENT_DISCONNECTED, the 'tickle'
information is removed, while the longterm smbd process
still serves the tcp connection.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15523
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Martin Schwenke <martin@meltin.net>
(cherry picked from commit
037e8e449deb136ad5ed5e4de05439411b545b6d)
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);
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
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;
&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) {
case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED:
break;
+
+ case CTDB_CONTROL_TCP_CLIENT_PASSED:
+ break;
}
return len;
{ 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, "" },
};
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;
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
*/