summaryrefslogtreecommitdiff
path: root/source3/lib
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib')
-rw-r--r--source3/lib/messages.c21
-rw-r--r--source3/lib/serverid.c293
-rw-r--r--source3/lib/util.c9
3 files changed, 309 insertions, 14 deletions
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
index 5e11dd4e25..2fcdc24179 100644
--- a/source3/lib/messages.c
+++ b/source3/lib/messages.c
@@ -95,36 +95,29 @@ struct msg_all {
Send one of the messages for the broadcast.
****************************************************************************/
-static int traverse_fn(struct db_record *rec,
- const struct connections_key *ckey,
- const struct connections_data *crec,
- void *state)
+static int traverse_fn(struct db_record *rec, const struct server_id *id,
+ uint32_t msg_flags, void *state)
{
struct msg_all *msg_all = (struct msg_all *)state;
NTSTATUS status;
- if (crec->cnum != -1)
- return 0;
-
/* Don't send if the receiver hasn't registered an interest. */
- if(!(crec->bcast_msg_flags & msg_all->msg_flag))
+ 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,
- crec->pid, msg_all->msg_type,
+ status = messaging_send_buf(msg_all->msg_ctx, *id, msg_all->msg_type,
(uint8 *)msg_all->buf, msg_all->len);
if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
/* If the pid was not found delete the entry from connections.tdb */
- DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
- procid_str_static(&crec->pid), crec->cnum,
- crec->servicename));
+ DEBUG(2, ("pid %s doesn't exist\n", procid_str_static(id)));
rec->delete_rec(rec);
}
@@ -172,7 +165,7 @@ bool message_send_all(struct messaging_context *msg_ctx,
msg_all.n_sent = 0;
msg_all.msg_ctx = msg_ctx;
- connections_forall(traverse_fn, &msg_all);
+ serverid_traverse(traverse_fn, &msg_all);
if (n_sent)
*n_sent = msg_all.n_sent;
return True;
diff --git a/source3/lib/serverid.c b/source3/lib/serverid.c
new file mode 100644
index 0000000000..9842ead103
--- /dev/null
+++ b/source3/lib/serverid.c
@@ -0,0 +1,293 @@
+/*
+ Unix SMB/CIFS implementation.
+ Implementation of a reliable server_exists()
+ Copyright (C) Volker Lendecke 2010
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "serverid.h"
+
+struct serverid_key {
+ pid_t pid;
+#ifdef CLUSTER_SUPPORT
+ uint32_t vnn;
+#endif
+};
+
+struct serverid_data {
+ uint64_t unique_id;
+ uint32_t msg_flags;
+};
+
+static struct db_context *serverid_db(void)
+{
+ static struct db_context *db;
+
+ if (db != NULL) {
+ return db;
+ }
+ db = db_open(talloc_autofree_context(), lock_path("serverid.tdb"),
+ 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0644);
+ return db;
+}
+
+static void serverid_fill_key(const struct server_id *id,
+ struct serverid_key *key)
+{
+ ZERO_STRUCTP(key);
+ key->pid = id->pid;
+#ifdef CLUSTER_SUPPORT
+ key->vnn = id->vnn;
+#endif
+}
+
+bool serverid_register(const struct server_id *id, uint32_t msg_flags)
+{
+ struct db_context *db;
+ struct serverid_key key;
+ struct serverid_data data;
+ struct db_record *rec;
+ TDB_DATA tdbkey, tdbdata;
+ 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 = db->fetch_locked(db, talloc_tos(), tdbkey);
+ if (rec == NULL) {
+ DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
+ return false;
+ }
+
+ ZERO_STRUCT(data);
+ data.unique_id = id->unique_id;
+ data.msg_flags = msg_flags;
+
+ tdbdata = make_tdb_data((uint8_t *)&data, sizeof(data));
+ status = rec->store(rec, tdbdata, 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;
+}
+
+bool serverid_register_self(uint32_t msg_flags)
+{
+ struct server_id pid;
+
+ pid = procid_self();
+ return serverid_register(&pid, msg_flags);
+}
+
+bool serverid_deregister(const struct server_id *id)
+{
+ struct db_context *db;
+ struct serverid_key key;
+ struct db_record *rec;
+ TDB_DATA tdbkey;
+ 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 = db->fetch_locked(db, talloc_tos(), tdbkey);
+ if (rec == NULL) {
+ DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
+ return false;
+ }
+
+ status = rec->delete_rec(rec);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Deleting serverid.tdb record failed: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+ ret = true;
+done:
+ TALLOC_FREE(rec);
+ return ret;
+}
+
+bool serverid_deregister_self(void)
+{
+ struct server_id pid;
+
+ pid = procid_self();
+ return serverid_deregister(&pid);
+}
+
+struct serverid_exists_state {
+ const struct server_id *id;
+ bool exists;
+};
+
+static int server_exists_parse(TDB_DATA key, TDB_DATA data, void *priv)
+{
+ struct serverid_exists_state *state =
+ (struct serverid_exists_state *)priv;
+ uint64_t unique_id;
+
+ if (data.dsize != sizeof(struct serverid_data)) {
+ return -1;
+ }
+
+ /* memcpy, data.dptr might not be aligned */
+ memcpy(&unique_id, data.dptr, sizeof(unique_id));
+
+ state->exists = (state->id->unique_id == unique_id);
+ return 0;
+}
+
+bool serverid_exists(const struct server_id *id)
+{
+ struct db_context *db;
+ struct serverid_exists_state state;
+ struct serverid_key key;
+ TDB_DATA tdbkey;
+
+ db = serverid_db();
+ if (db == NULL) {
+ return false;
+ }
+
+ serverid_fill_key(id, &key);
+ tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
+
+ state.id = id;
+ state.exists = false;
+
+ if (db->parse_record(db, tdbkey, server_exists_parse, &state) == -1) {
+ return false;
+ }
+ return state.exists;
+}
+
+static bool serverid_rec_parse(const struct db_record *rec,
+ struct server_id *id, uint32_t *msg_flags)
+{
+ struct serverid_key key;
+ struct serverid_data data;
+
+ if (rec->key.dsize != sizeof(key)) {
+ DEBUG(1, ("Found invalid key length %d in serverid.tdb\n",
+ (int)rec->key.dsize));
+ return false;
+ }
+ if (rec->value.dsize != sizeof(data)) {
+ DEBUG(1, ("Found invalid value length %d in serverid.tdb\n",
+ (int)rec->value.dsize));
+ return false;
+ }
+
+ memcpy(&key, rec->key.dptr, sizeof(key));
+ memcpy(&data, rec->value.dptr, sizeof(data));
+
+ id->pid = key.pid;
+#ifdef CLUSTER_SUPPORT
+ id->vnn = key.vnn;
+#endif
+ id->unique_id = data.unique_id;
+ *msg_flags = data.msg_flags;
+ return true;
+}
+
+struct serverid_traverse_read_state {
+ int (*fn)(const struct server_id *id, uint32_t msg_flags,
+ void *private_data);
+ void *private_data;
+};
+
+static int serverid_traverse_read_fn(struct db_record *rec, void *private_data)
+{
+ struct serverid_traverse_read_state *state =
+ (struct serverid_traverse_read_state *)private_data;
+ struct server_id id;
+ uint32_t msg_flags;
+
+ if (!serverid_rec_parse(rec, &id, &msg_flags)) {
+ return 0;
+ }
+ return state->fn(&id, msg_flags,state->private_data);
+}
+
+bool serverid_traverse_read(int (*fn)(const struct server_id *id,
+ uint32_t msg_flags, void *private_data),
+ void *private_data)
+{
+ struct db_context *db;
+ struct serverid_traverse_read_state state;
+
+ db = serverid_db();
+ if (db == NULL) {
+ return false;
+ }
+ state.fn = fn;
+ state.private_data = private_data;
+ return db->traverse_read(db, serverid_traverse_read_fn, &state);
+}
+
+struct serverid_traverse_state {
+ int (*fn)(struct db_record *rec, const struct server_id *id,
+ uint32_t msg_flags, void *private_data);
+ void *private_data;
+};
+
+static int serverid_traverse_fn(struct db_record *rec, void *private_data)
+{
+ struct serverid_traverse_state *state =
+ (struct serverid_traverse_state *)private_data;
+ struct server_id id;
+ uint32_t msg_flags;
+
+ if (!serverid_rec_parse(rec, &id, &msg_flags)) {
+ return 0;
+ }
+ return state->fn(rec, &id, msg_flags, state->private_data);
+}
+
+bool serverid_traverse(int (*fn)(struct db_record *rec,
+ const struct server_id *id,
+ uint32_t msg_flags, void *private_data),
+ void *private_data)
+{
+ struct db_context *db;
+ struct serverid_traverse_state state;
+
+ db = serverid_db();
+ if (db == NULL) {
+ return false;
+ }
+ state.fn = fn;
+ state.private_data = private_data;
+ return db->traverse(db, serverid_traverse_fn, &state);
+}
diff --git a/source3/lib/util.c b/source3/lib/util.c
index f35a55fbed..68f26b8393 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -2647,10 +2647,18 @@ uint32 get_my_vnn(void)
return my_vnn;
}
+static uint64_t my_unique_id = 0;
+
+void set_my_unique_id(uint64_t unique_id)
+{
+ my_unique_id = unique_id;
+}
+
struct server_id pid_to_procid(pid_t pid)
{
struct server_id result;
result.pid = pid;
+ result.unique_id = my_unique_id;
#ifdef CLUSTER_SUPPORT
result.vnn = my_vnn;
#endif
@@ -2720,6 +2728,7 @@ struct server_id interpret_pid(const char *pid_string)
if (result.pid < 0) {
result.pid = -1;
}
+ result.unique_id = 0;
return result;
}