X-Git-Url: http://git.samba.org/samba.git/?p=ira%2Fwip.git;a=blobdiff_plain;f=source3%2Flib%2Fctdbd_conn.c;h=8dba3b2d770695c81e9bbf5df2a64f9f85db2302;hp=d9d3421fa7c66ffc6edb4a45e8a8a741f4a107e8;hb=474020b1aeca8c527ea9aac6c39c6fb8386ace23;hpb=894a02ef4d53010c59cf7304f935288c99356874 diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index d9d3421fa7c..8dba3b2d770 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -3,17 +3,17 @@ Samba internal messaging functions Copyright (C) 2007 by Volker Lendecke Copyright (C) 2007 by Andrew Tridgell - + 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 . */ @@ -36,14 +36,14 @@ struct ctdbd_connection { uint64 rand_srvid; struct packet_context *pkt; struct fd_event *fde; - + void (*release_ip_handler)(const char *ip_addr, void *private_data); void *release_ip_priv; }; static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, uint32_t vnn, uint32 opcode, - uint64_t srvid, TDB_DATA data, + uint64_t srvid, uint32_t flags, TDB_DATA data, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int *cstatus); @@ -60,6 +60,20 @@ static void cluster_fatal(const char *why) _exit(0); } +/* + * + */ +static void ctdb_packet_dump(struct ctdb_req_header *hdr) +{ + if (DEBUGLEVEL < 10) { + return; + } + DEBUGADD(10, ("len=%d, magic=%x, vers=%d, gen=%d, op=%d, reqid=%d\n", + (int)hdr->length, (int)hdr->ctdb_magic, + (int)hdr->ctdb_version, (int)hdr->generation, + (int)hdr->operation, (int)hdr->reqid)); +} + /* * Register a srvid with ctdbd */ @@ -69,7 +83,7 @@ static NTSTATUS register_with_ctdbd(struct ctdbd_connection *conn, int cstatus; return ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_REGISTER_SRVID, srvid, + CTDB_CONTROL_REGISTER_SRVID, srvid, 0, tdb_null, NULL, NULL, &cstatus); } @@ -81,7 +95,7 @@ static NTSTATUS get_cluster_vnn(struct ctdbd_connection *conn, uint32 *vnn) int32_t cstatus=-1; NTSTATUS status; status = ctdbd_control(conn, - CTDB_CURRENT_NODE, CTDB_CONTROL_GET_VNN, 0, + CTDB_CURRENT_NODE, CTDB_CONTROL_GET_PNN, 0, 0, tdb_null, NULL, NULL, &cstatus); if (!NT_STATUS_IS_OK(status)) { cluster_fatal("ctdbd_control failed\n"); @@ -121,8 +135,8 @@ static NTSTATUS ctdbd_connect(TALLOC_CTX *mem_ctx, addr.sun_family = AF_UNIX; strncpy(addr.sun_path, sockname, sizeof(addr.sun_path)); - if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - DEBUG(0, ("connect(%s) failed: %s\n", sockname, + if (sys_connect(fd, (struct sockaddr *)(void *)&addr) == -1) { + DEBUG(1, ("connect(%s) failed: %s\n", sockname, strerror(errno))); close(fd); return map_nt_error_from_unix(errno); @@ -141,33 +155,33 @@ static NTSTATUS ctdbd_connect(TALLOC_CTX *mem_ctx, * Do we have a complete ctdb packet in the queue? */ -static BOOL ctdb_req_complete(const struct data_blob *data, +static bool ctdb_req_complete(const uint8_t *buf, size_t available, size_t *length, void *private_data) { uint32 msglen; - if (data->length < sizeof(msglen)) { + if (available < sizeof(msglen)) { return False; } - msglen = *((uint32 *)data->data); + msglen = *((uint32 *)buf); DEBUG(10, ("msglen = %d\n", msglen)); if (msglen < sizeof(struct ctdb_req_header)) { DEBUG(0, ("Got invalid msglen: %d, expected at least %d for " - "the req_header\n", msglen, - sizeof(struct ctdb_req_header))); + "the req_header\n", (int)msglen, + (int)sizeof(struct ctdb_req_header))); cluster_fatal("ctdbd protocol error\n"); } - if (data->length >= msglen) { - *length = msglen; - return True; + if (available < msglen) { + return false; } - return False; + *length = msglen; + return true; } /* @@ -186,7 +200,7 @@ struct deferred_msg_state { static void deferred_message_dispatch(struct event_context *event_ctx, struct timed_event *te, - const struct timeval *now, + struct timeval now, void *private_data) { struct deferred_msg_state *state = talloc_get_type_abort( @@ -206,16 +220,13 @@ struct req_pull_state { * Pull a ctdb request out of the incoming packet queue */ -static NTSTATUS ctdb_req_pull(const struct data_blob *data, +static NTSTATUS ctdb_req_pull(uint8_t *buf, size_t length, void *private_data) { struct req_pull_state *state = (struct req_pull_state *)private_data; - state->req = data_blob_talloc(state->mem_ctx, data->data, - data->length); - if (state->req.data == NULL) { - return NT_STATUS_NO_MEMORY; - } + state->req.data = talloc_move(state->mem_ctx, &buf); + state->req.length = length; return NT_STATUS_OK; } @@ -229,7 +240,7 @@ static struct messaging_rec *ctdb_pull_messaging_rec(TALLOC_CTX *mem_ctx, { struct messaging_rec *result; DATA_BLOB blob; - NTSTATUS status; + enum ndr_err_code ndr_err; if ((overall_length < offsetof(struct ctdb_req_message, data)) || (overall_length @@ -245,20 +256,36 @@ static struct messaging_rec *ctdb_pull_messaging_rec(TALLOC_CTX *mem_ctx, blob = data_blob_const(msg->data, msg->datalen); - status = ndr_pull_struct_blob( + ndr_err = ndr_pull_struct_blob( &blob, result, result, (ndr_pull_flags_fn_t)ndr_pull_messaging_rec); - if (!NT_STATUS_IS_OK(status)) { + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(0, ("ndr_pull_struct_blob failed: %s\n", - nt_errstr(status))); + ndr_errstr(ndr_err))); TALLOC_FREE(result); return NULL; } + if (DEBUGLEVEL >= 10) { + DEBUG(10, ("ctdb_pull_messaging_rec:\n")); + NDR_PRINT_DEBUG(messaging_rec, result); + } + return result; } +static NTSTATUS ctdb_packet_fd_read_sync(struct packet_context *ctx) +{ + struct timeval timeout; + struct timeval *ptimeout; + + timeout = timeval_set(lp_ctdb_timeout(), 0); + ptimeout = (timeout.tv_sec != 0) ? &timeout : NULL; + + return packet_fd_read_sync(ctx, ptimeout); +} + /* * Read a full ctdbd request. If we have a messaging context, defer incoming * messages that might come in between. @@ -273,7 +300,7 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32 reqid, again: - status = packet_fd_read_sync(conn->pkt); + status = ctdb_packet_fd_read_sync(conn->pkt); if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_BUSY)) { /* EAGAIN */ @@ -288,6 +315,8 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32 reqid, cluster_fatal("ctdbd died\n"); } + next_pkt: + ZERO_STRUCT(state); state.mem_ctx = mem_ctx; @@ -296,6 +325,7 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32 reqid, /* * Not enough data */ + DEBUG(10, ("not enough data from ctdb socket, retrying\n")); goto again; } @@ -306,6 +336,9 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32 reqid, hdr = (struct ctdb_req_header *)state.req.data; + DEBUG(10, ("Received ctdb packet\n")); + ctdb_packet_dump(hdr); + if (hdr->operation == CTDB_REQ_MESSAGE) { struct timed_event *evt; struct deferred_msg_state *msg_state; @@ -313,10 +346,11 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32 reqid, if (conn->msg_ctx == NULL) { DEBUG(1, ("Got a message without having a msg ctx, " - "dropping msg %llu\n", msg->srvid)); - goto again; + "dropping msg %llu\n", + (long long unsigned)msg->srvid)); + goto next_pkt; } - + if ((conn->release_ip_handler != NULL) && (msg->srvid == CTDB_SRVID_RELEASE_IP)) { /* must be dispatched immediately */ @@ -324,13 +358,31 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32 reqid, conn->release_ip_handler((const char *)msg->data, conn->release_ip_priv); TALLOC_FREE(hdr); - goto again; + goto next_pkt; + } + + if ((msg->srvid == CTDB_SRVID_RECONFIGURE) + || (msg->srvid == CTDB_SRVID_SAMBA_NOTIFY)) { + + DEBUG(1, ("ctdb_read_req: Got %s message\n", + (msg->srvid == CTDB_SRVID_RECONFIGURE) + ? "cluster reconfigure" : "SAMBA_NOTIFY")); + + messaging_send(conn->msg_ctx, + messaging_server_id(conn->msg_ctx), + MSG_SMB_BRL_VALIDATE, &data_blob_null); + messaging_send(conn->msg_ctx, + messaging_server_id(conn->msg_ctx), + MSG_DBWRAP_G_LOCK_RETRY, + &data_blob_null); + TALLOC_FREE(hdr); + goto next_pkt; } - if (!(msg_state = TALLOC_P(NULL, struct deferred_msg_state))) { + if (!(msg_state = TALLOC_P(talloc_autofree_context(), struct deferred_msg_state))) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(hdr); - goto again; + goto next_pkt; } if (!(msg_state->rec = ctdb_pull_messaging_rec( @@ -338,13 +390,13 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32 reqid, DEBUG(0, ("ctdbd_pull_messaging_rec failed\n")); TALLOC_FREE(msg_state); TALLOC_FREE(hdr); - goto again; + goto next_pkt; } TALLOC_FREE(hdr); msg_state->msg_ctx = conn->msg_ctx; - + /* * We're waiting for a call reply, but an async message has * crossed. Defer dispatching to the toplevel event loop. @@ -352,17 +404,16 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection *conn, uint32 reqid, evt = event_add_timed(conn->msg_ctx->event_ctx, conn->msg_ctx->event_ctx, timeval_zero(), - "deferred_message_dispatch", deferred_message_dispatch, msg_state); if (evt == NULL) { DEBUG(0, ("event_add_timed failed\n")); TALLOC_FREE(msg_state); TALLOC_FREE(hdr); - goto again; + goto next_pkt; } - - goto again; + + goto next_pkt; } if (hdr->reqid != reqid) { @@ -452,6 +503,11 @@ NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, goto fail; } + status = register_with_ctdbd(conn, CTDB_SRVID_SAMBA_NOTIFY); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + *pconn = conn; return NT_STATUS_OK; @@ -460,10 +516,20 @@ NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, return status; } +struct messaging_context *ctdb_conn_msg_ctx(struct ctdbd_connection *conn) +{ + return conn->msg_ctx; +} + +int ctdbd_conn_get_fd(struct ctdbd_connection *conn) +{ + return packet_get_fd(conn->pkt); +} + /* * Packet handler to receive and handle a ctdb message */ -static NTSTATUS ctdb_handle_message(const struct data_blob *data, +static NTSTATUS ctdb_handle_message(uint8_t *buf, size_t length, void *private_data) { struct ctdbd_connection *conn = talloc_get_type_abort( @@ -471,11 +537,12 @@ static NTSTATUS ctdb_handle_message(const struct data_blob *data, struct ctdb_req_message *msg; struct messaging_rec *msg_rec; - msg = (struct ctdb_req_message *)data->data; + msg = (struct ctdb_req_message *)buf; if (msg->hdr.operation != CTDB_REQ_MESSAGE) { DEBUG(0, ("Received async msg of type %u, discarding\n", msg->hdr.operation)); + TALLOC_FREE(buf); return NT_STATUS_INVALID_PARAMETER; } @@ -485,46 +552,51 @@ static NTSTATUS ctdb_handle_message(const struct data_blob *data, DEBUG(10, ("received CTDB_SRVID_RELEASE_IP\n")); conn->release_ip_handler((const char *)msg->data, conn->release_ip_priv); + TALLOC_FREE(buf); return NT_STATUS_OK; } SMB_ASSERT(conn->msg_ctx != NULL); - if (msg->srvid == CTDB_SRVID_RECONFIGURE) { + if ((msg->srvid == CTDB_SRVID_RECONFIGURE) + || (msg->srvid == CTDB_SRVID_SAMBA_NOTIFY)){ DEBUG(0,("Got cluster reconfigure message\n")); /* - * when the cluster is reconfigured, we need to clean the brl - * database + * when the cluster is reconfigured or someone of the + * family has passed away (SAMBA_NOTIFY), we need to + * clean the brl database */ - messaging_send(conn->msg_ctx, procid_self(), + messaging_send(conn->msg_ctx, + messaging_server_id(conn->msg_ctx), MSG_SMB_BRL_VALIDATE, &data_blob_null); - /* - * it's possible that we have just rejoined the cluster after - * an outage. In that case our pending locks could have been - * removed from the lockdb, so retry them once more - */ - message_send_all(conn->msg_ctx, MSG_SMB_UNLOCK, NULL, 0, NULL); + messaging_send(conn->msg_ctx, + messaging_server_id(conn->msg_ctx), + MSG_DBWRAP_G_LOCK_RETRY, + &data_blob_null); + TALLOC_FREE(buf); return NT_STATUS_OK; - } /* only messages to our pid or the broadcast are valid here */ if (msg->srvid != sys_getpid() && msg->srvid != MSG_SRVID_SAMBA) { DEBUG(0,("Got unexpected message with srvid=%llu\n", (unsigned long long)msg->srvid)); + TALLOC_FREE(buf); return NT_STATUS_OK; } - if (!(msg_rec = ctdb_pull_messaging_rec(NULL, data->length, msg))) { + if (!(msg_rec = ctdb_pull_messaging_rec(NULL, length, msg))) { DEBUG(10, ("ctdb_pull_messaging_rec failed\n")); + TALLOC_FREE(buf); return NT_STATUS_NO_MEMORY; } messaging_dispatch_rec(conn->msg_ctx, msg_rec); TALLOC_FREE(msg_rec); + TALLOC_FREE(buf); return NT_STATUS_OK; } @@ -594,19 +666,21 @@ NTSTATUS ctdbd_messaging_send(struct ctdbd_connection *conn, TALLOC_CTX *mem_ctx; DATA_BLOB blob; NTSTATUS status; + enum ndr_err_code ndr_err; if (!(mem_ctx = talloc_init("ctdbd_messaging_send"))) { DEBUG(0, ("talloc failed\n")); return NT_STATUS_NO_MEMORY; } - status = ndr_push_struct_blob( + ndr_err = ndr_push_struct_blob( &blob, mem_ctx, msg, (ndr_push_flags_fn_t)ndr_push_messaging_rec); - if (!NT_STATUS_IS_OK(status)) { + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(0, ("ndr_push_struct_blob failed: %s\n", - nt_errstr(status))); + ndr_errstr(ndr_err))); + status = ndr_map_error2ntstatus(ndr_err); goto fail; } @@ -621,6 +695,9 @@ NTSTATUS ctdbd_messaging_send(struct ctdbd_connection *conn, r.srvid = dst_srvid; r.datalen = blob.length; + DEBUG(10, ("ctdbd_messaging_send: Sending ctdb packet\n")); + ctdb_packet_dump(&r.hdr); + status = packet_send( conn->pkt, 2, data_blob_const(&r, offsetof(struct ctdb_req_message, data)), @@ -649,7 +726,8 @@ NTSTATUS ctdbd_messaging_send(struct ctdbd_connection *conn, */ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, uint32_t vnn, uint32 opcode, - uint64_t srvid, TDB_DATA data, + uint64_t srvid, uint32_t flags, + TDB_DATA data, TALLOC_CTX *mem_ctx, TDB_DATA *outdata, int *cstatus) { @@ -658,6 +736,9 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, struct ctdbd_connection *new_conn = NULL; NTSTATUS status; + /* the samba3 ctdb code can't handle NOREPLY yet */ + flags &= ~CTDB_CTRL_FLAG_NOREPLY; + if (conn == NULL) { status = ctdbd_init_connection(NULL, &new_conn); @@ -681,10 +762,13 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, req.srvid = srvid; req.datalen = data.dsize; + DEBUG(10, ("ctdbd_control: Sending ctdb packet\n")); + ctdb_packet_dump(&req.hdr); + status = packet_send( conn->pkt, 2, data_blob_const(&req, offsetof(struct ctdb_req_control, data)), - data); + data_blob_const(data.dptr, data.dsize)); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("packet_send failed: %s\n", nt_errstr(status))); @@ -698,6 +782,11 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, cluster_fatal("cluster dispatch daemon control write error\n"); } + if (flags & CTDB_CTRL_FLAG_NOREPLY) { + TALLOC_FREE(new_conn); + return NT_STATUS_OK; + } + status = ctdb_read_req(conn, req.hdr.reqid, NULL, (void *)&reply); if (!NT_STATUS_IS_OK(status)) { @@ -733,7 +822,7 @@ static NTSTATUS ctdbd_control(struct ctdbd_connection *conn, /* * see if a remote process exists */ -BOOL ctdbd_process_exists(struct ctdbd_connection *conn, uint32 vnn, pid_t pid) +bool ctdbd_process_exists(struct ctdbd_connection *conn, uint32 vnn, pid_t pid) { NTSTATUS status; TDB_DATA data; @@ -742,7 +831,7 @@ BOOL ctdbd_process_exists(struct ctdbd_connection *conn, uint32 vnn, pid_t pid) data.dptr = (uint8_t*)&pid; data.dsize = sizeof(pid); - status = ctdbd_control(conn, vnn, CTDB_CONTROL_PROCESS_EXISTS, 0, + status = ctdbd_control(conn, vnn, CTDB_CONTROL_PROCESS_EXISTS, 0, 0, data, NULL, NULL, &cstatus); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, (__location__ " ctdb_control for process_exists " @@ -767,7 +856,7 @@ char *ctdbd_dbpath(struct ctdbd_connection *conn, data.dsize = sizeof(db_id); status = ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_GETDBPATH, 0, data, + CTDB_CONTROL_GETDBPATH, 0, 0, data, mem_ctx, &data, &cstatus); if (!NT_STATUS_IS_OK(status) || cstatus != 0) { DEBUG(0,(__location__ " ctdb_control for getdbpath failed\n")); @@ -786,13 +875,16 @@ NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, NTSTATUS status; TDB_DATA data; int32_t cstatus; + bool persistent = (tdb_flags & TDB_CLEAR_IF_FIRST) == 0; data.dptr = (uint8_t*)name; data.dsize = strlen(name)+1; status = ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_DB_ATTACH, 0, data, - NULL, &data, &cstatus); + persistent + ? CTDB_CONTROL_DB_ATTACH_PERSISTENT + : CTDB_CONTROL_DB_ATTACH, + 0, 0, data, NULL, &data, &cstatus); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, (__location__ " ctdb_control for db_attach " "failed: %s\n", nt_errstr(status))); @@ -815,7 +907,7 @@ NTSTATUS ctdbd_db_attach(struct ctdbd_connection *conn, data.dsize = sizeof(*db_id); status = ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_ENABLE_SEQNUM, 0, data, + CTDB_CONTROL_ENABLE_SEQNUM, 0, 0, data, NULL, NULL, &cstatus); if (!NT_STATUS_IS_OK(status) || cstatus != 0) { DEBUG(0,(__location__ " ctdb_control for enable seqnum " @@ -838,7 +930,7 @@ NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32 db_id, NTSTATUS status; ZERO_STRUCT(req); - + req.hdr.length = offsetof(struct ctdb_req_call, data) + key.dsize; req.hdr.ctdb_magic = CTDB_MAGIC; req.hdr.ctdb_version = CTDB_VERSION; @@ -849,10 +941,13 @@ NTSTATUS ctdbd_migrate(struct ctdbd_connection *conn, uint32 db_id, req.db_id = db_id; req.keylen = key.dsize; + DEBUG(10, ("ctdbd_migrate: Sending ctdb packet\n")); + ctdb_packet_dump(&req.hdr); + status = packet_send( conn->pkt, 2, data_blob_const(&req, offsetof(struct ctdb_req_call, data)), - key); + data_blob_const(key.dptr, key.dsize)); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("packet_send failed: %s\n", nt_errstr(status))); @@ -897,7 +992,7 @@ NTSTATUS ctdbd_fetch(struct ctdbd_connection *conn, uint32 db_id, NTSTATUS status; ZERO_STRUCT(req); - + req.hdr.length = offsetof(struct ctdb_req_call, data) + key.dsize; req.hdr.ctdb_magic = CTDB_MAGIC; req.hdr.ctdb_version = CTDB_VERSION; @@ -911,7 +1006,7 @@ NTSTATUS ctdbd_fetch(struct ctdbd_connection *conn, uint32 db_id, status = packet_send( conn->pkt, 2, data_blob_const(&req, offsetof(struct ctdb_req_call, data)), - key); + data_blob_const(key.dptr, key.dsize)); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("packet_send failed: %s\n", nt_errstr(status))); @@ -968,7 +1063,7 @@ struct ctdbd_traverse_state { * Handle a traverse record coming in on the ctdbd connection */ -static NTSTATUS ctdb_traverse_handler(const struct data_blob *blob, +static NTSTATUS ctdb_traverse_handler(uint8_t *buf, size_t length, void *private_data) { struct ctdbd_traverse_state *state = @@ -978,11 +1073,11 @@ static NTSTATUS ctdb_traverse_handler(const struct data_blob *blob, struct ctdb_rec_data *d; TDB_DATA key, data; - m = (struct ctdb_req_message *)blob->data; + m = (struct ctdb_req_message *)buf; - if (blob->length < sizeof(*m) || m->hdr.length != blob->length) { - DEBUG(0, ("Got invalid message of length %d\n", - (int)blob->length)); + if (length < sizeof(*m) || m->hdr.length != length) { + DEBUG(0, ("Got invalid message of length %d\n", (int)length)); + TALLOC_FREE(buf); return NT_STATUS_UNEXPECTED_IO_ERROR; } @@ -990,6 +1085,7 @@ static NTSTATUS ctdb_traverse_handler(const struct data_blob *blob, if (m->datalen < sizeof(uint32_t) || m->datalen != d->length) { DEBUG(0, ("Got invalid traverse data of length %d\n", (int)m->datalen)); + TALLOC_FREE(buf); return NT_STATUS_UNEXPECTED_IO_ERROR; } @@ -1006,6 +1102,7 @@ static NTSTATUS ctdb_traverse_handler(const struct data_blob *blob, if (data.dsize < sizeof(struct ctdb_ltdb_header)) { DEBUG(0, ("Got invalid ltdb header length %d\n", (int)data.dsize)); + TALLOC_FREE(buf); return NT_STATUS_UNEXPECTED_IO_ERROR; } data.dsize -= sizeof(struct ctdb_ltdb_header); @@ -1015,6 +1112,7 @@ static NTSTATUS ctdb_traverse_handler(const struct data_blob *blob, state->fn(key, data, state->private_data); } + TALLOC_FREE(buf); return NT_STATUS_OK; } @@ -1038,6 +1136,11 @@ NTSTATUS ctdbd_traverse(uint32 db_id, struct ctdbd_traverse_state state; status = ctdbd_init_connection(NULL, &conn); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("ctdbd_init_connection failed: %s\n", + nt_errstr(status))); + return status; + } t.db_id = db_id; t.srvid = conn->rand_srvid; @@ -1047,7 +1150,7 @@ NTSTATUS ctdbd_traverse(uint32 db_id, data.dsize = sizeof(t); status = ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_TRAVERSE_START, conn->rand_srvid, + CTDB_CONTROL_TRAVERSE_START, conn->rand_srvid, 0, data, NULL, NULL, &cstatus); if (!NT_STATUS_IS_OK(status) || (cstatus != 0)) { @@ -1089,7 +1192,7 @@ NTSTATUS ctdbd_traverse(uint32 db_id, break; } - status = packet_fd_read_sync(conn->pkt); + status = ctdb_packet_fd_read_sync(conn->pkt); if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { /* @@ -1100,6 +1203,7 @@ NTSTATUS ctdbd_traverse(uint32 db_id, if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { status = NT_STATUS_OK; + break; } if (!NT_STATUS_IS_OK(status)) { @@ -1113,26 +1217,86 @@ NTSTATUS ctdbd_traverse(uint32 db_id, return status; } +/* + This is used to canonicalize a ctdb_sock_addr structure. +*/ +static void smbd_ctdb_canonicalize_ip(const struct sockaddr_storage *in, + struct sockaddr_storage *out) +{ + memcpy(out, in, sizeof (*out)); + +#ifdef HAVE_IPV6 + if (in->ss_family == AF_INET6) { + const char prefix[12] = { 0,0,0,0,0,0,0,0,0,0,0xff,0xff }; + const struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)in; + struct sockaddr_in *out4 = (struct sockaddr_in *)out; + if (memcmp(&in6->sin6_addr, prefix, 12) == 0) { + memset(out, 0, sizeof(*out)); +#ifdef HAVE_SOCK_SIN_LEN + out4->sin_len = sizeof(*out); +#endif + out4->sin_family = AF_INET; + out4->sin_port = in6->sin6_port; + memcpy(&out4->sin_addr, &in6->sin6_addr.s6_addr32[3], 4); + } + } +#endif +} + /* * Register us as a server for a particular tcp connection */ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, - const struct sockaddr_in *server, - const struct sockaddr_in *client, + const struct sockaddr_storage *_server, + const struct sockaddr_storage *_client, void (*release_ip_handler)(const char *ip_addr, void *private_data), void *private_data) { - struct ctdb_control_tcp p; + /* + * we still use ctdb_control_tcp for ipv4 + * because we want to work against older ctdb + * versions at runtime + */ + struct ctdb_control_tcp p4; +#ifdef HAVE_STRUCT_CTDB_CONTROL_TCP_ADDR + struct ctdb_control_tcp_addr p; +#endif TDB_DATA data; NTSTATUS status; + struct sockaddr_storage client; + struct sockaddr_storage server; /* * Only one connection so far */ SMB_ASSERT(conn->release_ip_handler == NULL); + smbd_ctdb_canonicalize_ip(_client, &client); + smbd_ctdb_canonicalize_ip(_server, &server); + + switch (client.ss_family) { + case AF_INET: + p4.dest = *(struct sockaddr_in *)(void *)&server; + p4.src = *(struct sockaddr_in *)(void *)&client; + data.dptr = (uint8_t *)&p4; + data.dsize = sizeof(p4); + break; +#ifdef HAVE_STRUCT_CTDB_CONTROL_TCP_ADDR + case AF_INET6: + p.dest.ip6 = *(struct sockaddr_in6 *)(void *)&server; + p.src.ip6 = *(struct sockaddr_in6 *)(void *)&client; + data.dptr = (uint8_t *)&p; + data.dsize = sizeof(p); + break; +#endif + default: + return NT_STATUS_INTERNAL_ERROR; + } + + conn->release_ip_handler = release_ip_handler; + /* * We want to be told about IP releases */ @@ -1142,19 +1306,13 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn, return status; } - p.dest = *server; - p.src = *client; - /* * inform ctdb of our tcp connection, so if IP takeover happens ctdb * can send an extra ack to trigger a reset for our client, so it * immediately reconnects */ - data.dptr = (uint8_t *)&p; - data.dsize = sizeof(p); - return ctdbd_control(conn, CTDB_CURRENT_NODE, - CTDB_CONTROL_TCP_CLIENT, + CTDB_CONTROL_TCP_CLIENT, 0, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL, NULL); } @@ -1166,6 +1324,61 @@ NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn) return register_with_ctdbd(conn, CTDB_SRVID_RECONFIGURE); } +/* + call a control on the local node + */ +NTSTATUS ctdbd_control_local(struct ctdbd_connection *conn, uint32 opcode, + uint64_t srvid, uint32_t flags, TDB_DATA data, + TALLOC_CTX *mem_ctx, TDB_DATA *outdata, + int *cstatus) +{ + return ctdbd_control(conn, CTDB_CURRENT_NODE, opcode, srvid, flags, data, mem_ctx, outdata, cstatus); +} + +NTSTATUS ctdb_watch_us(struct ctdbd_connection *conn) +{ + struct ctdb_client_notify_register reg_data; + size_t struct_len; + NTSTATUS status; + int cstatus; + + reg_data.srvid = CTDB_SRVID_SAMBA_NOTIFY; + reg_data.len = 1; + reg_data.notify_data[0] = 0; + + struct_len = offsetof(struct ctdb_client_notify_register, + notify_data) + reg_data.len; + + status = ctdbd_control_local( + conn, CTDB_CONTROL_REGISTER_NOTIFY, conn->rand_srvid, 0, + make_tdb_data((uint8_t *)®_data, struct_len), + NULL, NULL, &cstatus); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("ctdbd_control_local failed: %s\n", + nt_errstr(status))); + } + return status; +} + +NTSTATUS ctdb_unwatch(struct ctdbd_connection *conn) +{ + struct ctdb_client_notify_deregister dereg_data; + NTSTATUS status; + int cstatus; + + dereg_data.srvid = CTDB_SRVID_SAMBA_NOTIFY; + + status = ctdbd_control_local( + conn, CTDB_CONTROL_DEREGISTER_NOTIFY, conn->rand_srvid, 0, + make_tdb_data((uint8_t *)&dereg_data, sizeof(dereg_data)), + NULL, NULL, &cstatus); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("ctdbd_control_local failed: %s\n", + nt_errstr(status))); + } + return status; +} + #else NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,