#include "lib/param/param.h"
#include "ctdbd_conn.h"
#include "messages.h"
+#include "lib/messages_dgm.h"
struct serverid_key {
pid_t pid;
uint32_t msg_flags;
};
-bool serverid_parent_init(TALLOC_CTX *mem_ctx)
+static struct db_context *serverid_db(void)
{
- struct tdb_wrap *db;
- struct loadparm_context *lp_ctx;
+ static struct db_context *db;
+ char *db_path;
- lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
- if (lp_ctx == NULL) {
- DEBUG(0, ("loadparm_init_s3 failed\n"));
- return false;
+ if (db != NULL) {
+ return db;
}
- /*
- * Open the tdb in the parent process (smbd) so that our
- * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
- * work.
- */
+ db_path = lock_path("serverid.tdb");
+ if (db_path == NULL) {
+ return NULL;
+ }
- db = tdb_wrap_open(mem_ctx, lock_path("serverid.tdb"),
- 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT,
- 0644, lp_ctx);
- talloc_unlink(mem_ctx, lp_ctx);
+ db = db_open(NULL, db_path, 0,
+ TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
+ O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2,
+ DBWRAP_FLAG_NONE);
+ TALLOC_FREE(db_path);
+ return db;
+}
+
+bool serverid_parent_init(TALLOC_CTX *mem_ctx)
+{
+ struct db_context *db;
+
+ db = serverid_db();
if (db == NULL) {
DEBUG(1, ("could not open serverid.tdb: %s\n",
strerror(errno)));
return false;
}
- return true;
-}
-
-static struct db_context *serverid_db(void)
-{
- static struct db_context *db;
- if (db != NULL) {
- return db;
- }
- db = db_open(NULL, lock_path("serverid.tdb"), 0,
- TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
- O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2);
- return db;
+ return true;
}
static void serverid_fill_key(const struct server_id *id,
nt_errstr(status)));
goto done;
}
-#ifdef HAVE_CTDB_CONTROL_CHECK_SRVIDS_DECL
- if (lp_clustering()) {
- register_with_ctdbd(messaging_ctdbd_connection(), id.unique_id);
- }
-#endif
- ret = true;
-done:
- TALLOC_FREE(rec);
- return ret;
-}
-
-bool serverid_register_msg_flags(const struct server_id id, bool do_reg,
- uint32_t msg_flags)
-{
- struct db_context *db;
- struct serverid_key key;
- struct serverid_data *data;
- struct db_record *rec;
- TDB_DATA tdbkey;
- TDB_DATA value;
- NTSTATUS status;
- bool ret = false;
-
- db = serverid_db();
- if (db == NULL) {
- return false;
- }
-
- serverid_fill_key(&id, &key);
- tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
-
- rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
- if (rec == NULL) {
- DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
- return false;
- }
-
- value = dbwrap_record_get_value(rec);
-
- if (value.dsize != sizeof(struct serverid_data)) {
- DEBUG(1, ("serverid record has unexpected size %d "
- "(wanted %d)\n", (int)value.dsize,
- (int)sizeof(struct serverid_data)));
- goto done;
- }
-
- data = (struct serverid_data *)value.dptr;
- if (do_reg) {
- data->msg_flags |= msg_flags;
- } else {
- data->msg_flags &= ~msg_flags;
+ if (lp_clustering()) {
+ register_with_ctdbd(messaging_ctdbd_connection(), id.unique_id,
+ NULL, NULL);
}
- status = dbwrap_record_store(rec, value, 0);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
- nt_errstr(status)));
- goto done;
- }
ret = true;
done:
TALLOC_FREE(rec);
return ret;
}
-struct serverid_exists_state {
- const struct server_id *id;
- bool exists;
-};
-
-static void server_exists_parse(TDB_DATA key, TDB_DATA data, void *priv)
+static bool serverid_exists_local(const struct server_id *id)
{
- struct serverid_exists_state *state =
- (struct serverid_exists_state *)priv;
+ bool exists = process_exists_by_pid(id->pid);
+ uint64_t unique;
+ int ret;
- if (data.dsize != sizeof(struct serverid_data)) {
- state->exists = false;
- return;
+ if (!exists) {
+ return false;
}
- /*
- * Use memcmp, not direct compare. data.dptr might not be
- * aligned.
- */
- state->exists = (memcmp(&state->id->unique_id, data.dptr,
- sizeof(state->id->unique_id)) == 0);
-}
-
-bool serverid_exists(const struct server_id *id)
-{
- bool result = false;
- bool ok = false;
+ if (id->unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
+ return true;
+ }
- ok = serverids_exist(id, 1, &result);
- if (!ok) {
+ ret = messaging_dgm_get_unique(id->pid, &unique);
+ if (ret != 0) {
return false;
}
- return result;
+ return (unique == id->unique_id);
}
-bool serverids_exist(const struct server_id *ids, int num_ids, bool *results)
+bool serverid_exists(const struct server_id *id)
{
- int *todo_idx = NULL;
- struct server_id *todo_ids = NULL;
- bool *todo_results = NULL;
- int todo_num = 0;
- int *remote_idx = NULL;
- int remote_num = 0;
- int *verify_idx = NULL;
- int verify_num = 0;
- int t, idx;
- bool result = false;
- struct db_context *db;
-
- db = serverid_db();
- if (db == NULL) {
- return false;
- }
-
- todo_idx = talloc_array(talloc_tos(), int, num_ids);
- if (todo_idx == NULL) {
- goto fail;
- }
- todo_ids = talloc_array(talloc_tos(), struct server_id, num_ids);
- if (todo_ids == NULL) {
- goto fail;
- }
- todo_results = talloc_array(talloc_tos(), bool, num_ids);
- if (todo_results == NULL) {
- goto fail;
- }
-
- remote_idx = talloc_array(talloc_tos(), int, num_ids);
- if (remote_idx == NULL) {
- goto fail;
- }
- verify_idx = talloc_array(talloc_tos(), int, num_ids);
- if (verify_idx == NULL) {
- goto fail;
- }
-
- for (idx=0; idx<num_ids; idx++) {
- results[idx] = false;
-
- if (server_id_is_disconnected(&ids[idx])) {
- continue;
- }
-
- if (procid_is_me(&ids[idx])) {
- results[idx] = true;
- continue;
- }
-
- if (procid_is_local(&ids[idx])) {
- bool exists = process_exists_by_pid(ids[idx].pid);
-
- if (!exists) {
- continue;
- }
-
- if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
- results[idx] = true;
- continue;
- }
-
- verify_idx[verify_num] = idx;
- verify_num += 1;
- continue;
- }
-
- if (!lp_clustering()) {
- continue;
- }
-
- remote_idx[remote_num] = idx;
- remote_num += 1;
- }
-
-#ifdef HAVE_CTDB_CONTROL_CHECK_SRVIDS_DECL
- if (remote_num != 0) {
- int old_remote_num = remote_num;
-
- remote_num = 0;
- todo_num = 0;
-
- for (t=0; t<old_remote_num; t++) {
- idx = remote_idx[t];
-
- if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
- remote_idx[remote_num] = idx;
- remote_num += 1;
- continue;
- }
-
- todo_idx[todo_num] = idx;
- todo_ids[todo_num] = ids[idx];
- todo_results[todo_num] = false;
- todo_num += 1;
- }
-
- /*
- * Note: this only uses CTDB_CONTROL_CHECK_SRVIDS
- * to verify that the server_id still exists,
- * which means only the server_id.unique_id and
- * server_id.vnn are verified, while server_id.pid
- * is not verified at all.
- *
- * TODO: do we want to verify server_id.pid somehow?
- */
- if (!ctdb_serverids_exist(messaging_ctdbd_connection(),
- todo_ids, todo_num, todo_results))
- {
- goto fail;
- }
-
- for (t=0; t<todo_num; t++) {
- idx = todo_idx[t];
-
- results[idx] = todo_results[t];
- }
- }
-#endif
-
- if (remote_num != 0) {
- todo_num = 0;
-
- for (t=0; t<remote_num; t++) {
- idx = remote_idx[t];
- todo_idx[todo_num] = idx;
- todo_ids[todo_num] = ids[idx];
- todo_results[todo_num] = false;
- todo_num += 1;
- }
-
-#ifdef CLUSTER_SUPPORT
- if (!ctdb_processes_exist(messaging_ctdbd_connection(),
- todo_ids, todo_num,
- todo_results)) {
- goto fail;
- }
-#endif
-
- for (t=0; t<todo_num; t++) {
- idx = todo_idx[t];
-
- if (!todo_results[t]) {
- continue;
- }
-
- if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
- results[idx] = true;
- continue;
- }
-
- verify_idx[verify_num] = idx;
- verify_num += 1;
- }
+ if (procid_is_local(id)) {
+ return serverid_exists_local(id);
}
- for (t=0; t<verify_num; t++) {
- struct serverid_exists_state state;
- struct serverid_key key;
- TDB_DATA tdbkey;
- NTSTATUS status;
-
- idx = verify_idx[t];
-
- serverid_fill_key(&ids[idx], &key);
- tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
-
- state.id = &ids[idx];
- state.exists = false;
- status = dbwrap_parse_record(db, tdbkey, server_exists_parse, &state);
- if (!NT_STATUS_IS_OK(status)) {
- results[idx] = false;
- continue;
- }
- results[idx] = state.exists;
+ if (lp_clustering()) {
+ return ctdbd_process_exists(messaging_ctdbd_connection(),
+ id->vnn, id->pid);
}
- result = true;
-fail:
- TALLOC_FREE(verify_idx);
- TALLOC_FREE(remote_idx);
- TALLOC_FREE(todo_results);
- TALLOC_FREE(todo_ids);
- TALLOC_FREE(todo_idx);
- return result;
+ return false;
}
static bool serverid_rec_parse(const struct db_record *rec,
return NT_STATUS_IS_OK(status);
}
-uint64_t serverid_get_random_unique_id(void)
+struct msg_all {
+ struct messaging_context *msg_ctx;
+ int msg_type;
+ uint32_t msg_flag;
+ const void *buf;
+ size_t len;
+ int n_sent;
+};
+
+/****************************************************************************
+ Send one of the messages for the broadcast.
+****************************************************************************/
+
+static int traverse_fn(struct db_record *rec, const struct server_id *id,
+ uint32_t msg_flags, void *state)
{
- uint64_t unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
+ struct msg_all *msg_all = (struct msg_all *)state;
+ NTSTATUS status;
+
+ /* Don't send if the receiver hasn't registered an interest. */
+
+ if((msg_flags & msg_all->msg_flag) == 0) {
+ return 0;
+ }
+
+ /* If the msg send fails because the pid was not found (i.e. smbd died),
+ * the msg has already been deleted from the messages.tdb.*/
+
+ status = messaging_send_buf(msg_all->msg_ctx, *id, msg_all->msg_type,
+ (const uint8_t *)msg_all->buf, msg_all->len);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
+ struct server_id_buf idbuf;
+
+ /*
+ * If the pid was not found delete the entry from
+ * serverid.tdb
+ */
+
+ DEBUG(2, ("pid %s doesn't exist\n",
+ server_id_str_buf(*id, &idbuf)));
- while (unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
- generate_random_buffer((uint8_t *)&unique_id,
- sizeof(unique_id));
+ dbwrap_record_delete(rec);
+ }
+ msg_all->n_sent++;
+ return 0;
+}
+
+/**
+ * Send a message to all smbd processes.
+ *
+ * It isn't very efficient, but should be OK for the sorts of
+ * applications that use it. When we need efficient broadcast we can add
+ * it.
+ *
+ * @param n_sent Set to the number of messages sent. This should be
+ * equal to the number of processes, but be careful for races.
+ *
+ * @retval True for success.
+ **/
+bool message_send_all(struct messaging_context *msg_ctx,
+ int msg_type,
+ const void *buf, size_t len,
+ int *n_sent)
+{
+ struct msg_all msg_all;
+
+ msg_all.msg_type = msg_type;
+ if (msg_type < 0x100) {
+ msg_all.msg_flag = FLAG_MSG_GENERAL;
+ } else if (msg_type > 0x100 && msg_type < 0x200) {
+ msg_all.msg_flag = FLAG_MSG_NMBD;
+ } else if (msg_type > 0x200 && msg_type < 0x300) {
+ msg_all.msg_flag = FLAG_MSG_PRINT_GENERAL;
+ } else if (msg_type > 0x300 && msg_type < 0x400) {
+ msg_all.msg_flag = FLAG_MSG_SMBD;
+ } else if (msg_type > 0x400 && msg_type < 0x600) {
+ msg_all.msg_flag = FLAG_MSG_WINBIND;
+ } else if (msg_type > 4000 && msg_type < 5000) {
+ msg_all.msg_flag = FLAG_MSG_DBWRAP;
+ } else {
+ return false;
}
- return unique_id;
+ msg_all.buf = buf;
+ msg_all.len = len;
+ msg_all.n_sent = 0;
+ msg_all.msg_ctx = msg_ctx;
+
+ serverid_traverse(traverse_fn, &msg_all);
+ if (n_sent)
+ *n_sent = msg_all.n_sent;
+ return true;
}