lib: Move "message_send_all" to serverid.c
[nivanova/samba-autobuild/.git] / source3 / lib / serverid.c
index cb495205640c7af52486cd2cf536fff6d76f8011..f2c64001d7407bf92c1be0d69c50b310013474a1 100644 (file)
@@ -27,6 +27,7 @@
 #include "lib/param/param.h"
 #include "ctdbd_conn.h"
 #include "messages.h"
+#include "lib/messages_dgm.h"
 
 struct serverid_key {
        pid_t pid;
@@ -39,46 +40,40 @@ struct serverid_data {
        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,
@@ -125,66 +120,12 @@ bool serverid_register(const struct server_id id, uint32_t msg_flags)
                          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);
@@ -226,230 +167,40 @@ done:
        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,
@@ -563,14 +314,97 @@ bool serverid_traverse(int (*fn)(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;
 }