2 Unix SMB/CIFS implementation.
3 Implementation of a reliable server_exists()
4 Copyright (C) Volker Lendecke 2010
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "system/filesys.h"
22 #include "lib/util/server_id.h"
25 #include "dbwrap/dbwrap.h"
26 #include "dbwrap/dbwrap_open.h"
27 #include "lib/tdb_wrap/tdb_wrap.h"
28 #include "lib/param/param.h"
29 #include "ctdbd_conn.h"
31 #include "lib/messages_ctdb.h"
32 #include "lib/messages_dgm.h"
40 struct serverid_data {
45 static struct db_context *serverid_db(void)
47 static struct db_context *db;
54 db_path = lock_path("serverid.tdb");
55 if (db_path == NULL) {
59 db = db_open(NULL, db_path, 0,
60 TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
61 O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2,
67 bool serverid_parent_init(TALLOC_CTX *mem_ctx)
69 struct db_context *db;
73 DEBUG(1, ("could not open serverid.tdb: %s\n",
81 static void serverid_fill_key(const struct server_id *id,
82 struct serverid_key *key)
86 key->task_id = id->task_id;
90 bool serverid_register(const struct server_id id, uint32_t msg_flags)
92 struct db_context *db;
93 struct serverid_key key;
94 struct serverid_data data;
95 struct db_record *rec;
96 TDB_DATA tdbkey, tdbdata;
105 serverid_fill_key(&id, &key);
106 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
108 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
110 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
115 data.unique_id = id.unique_id;
116 data.msg_flags = msg_flags;
118 tdbdata = make_tdb_data((uint8_t *)&data, sizeof(data));
119 status = dbwrap_record_store(rec, tdbdata, 0);
120 if (!NT_STATUS_IS_OK(status)) {
121 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
126 if (lp_clustering()) {
127 register_with_ctdbd(messaging_ctdb_connection(), id.unique_id,
137 bool serverid_deregister(struct server_id id)
139 struct db_context *db;
140 struct serverid_key key;
141 struct db_record *rec;
151 serverid_fill_key(&id, &key);
152 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
154 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
156 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
160 status = dbwrap_record_delete(rec);
161 if (!NT_STATUS_IS_OK(status)) {
162 DEBUG(1, ("Deleting serverid.tdb record failed: %s\n",
172 static bool serverid_exists_local(const struct server_id *id)
174 bool exists = process_exists_by_pid(id->pid);
182 if (id->unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
186 ret = messaging_dgm_get_unique(id->pid, &unique);
191 return (unique == id->unique_id);
194 bool serverid_exists(const struct server_id *id)
196 if (procid_is_local(id)) {
197 return serverid_exists_local(id);
200 if (lp_clustering()) {
201 return ctdbd_process_exists(messaging_ctdb_connection(),
202 id->vnn, id->pid, id->unique_id);
208 static bool serverid_rec_parse(const struct db_record *rec,
209 struct server_id *id, uint32_t *msg_flags)
211 struct serverid_key key;
212 struct serverid_data data;
216 tdbkey = dbwrap_record_get_key(rec);
217 tdbdata = dbwrap_record_get_value(rec);
219 if (tdbkey.dsize != sizeof(key)) {
220 DEBUG(1, ("Found invalid key length %d in serverid.tdb\n",
224 if (tdbdata.dsize != sizeof(data)) {
225 DEBUG(1, ("Found invalid value length %d in serverid.tdb\n",
226 (int)tdbdata.dsize));
230 memcpy(&key, tdbkey.dptr, sizeof(key));
231 memcpy(&data, tdbdata.dptr, sizeof(data));
234 id->task_id = key.task_id;
236 id->unique_id = data.unique_id;
237 *msg_flags = data.msg_flags;
241 struct serverid_traverse_read_state {
242 int (*fn)(const struct server_id *id, uint32_t msg_flags,
247 static int serverid_traverse_read_fn(struct db_record *rec, void *private_data)
249 struct serverid_traverse_read_state *state =
250 (struct serverid_traverse_read_state *)private_data;
254 if (!serverid_rec_parse(rec, &id, &msg_flags)) {
257 return state->fn(&id, msg_flags,state->private_data);
260 bool serverid_traverse_read(int (*fn)(const struct server_id *id,
261 uint32_t msg_flags, void *private_data),
264 struct db_context *db;
265 struct serverid_traverse_read_state state;
273 state.private_data = private_data;
275 status = dbwrap_traverse_read(db, serverid_traverse_read_fn, &state,
277 return NT_STATUS_IS_OK(status);
280 struct serverid_traverse_state {
281 int (*fn)(struct db_record *rec, const struct server_id *id,
282 uint32_t msg_flags, void *private_data);
286 static int serverid_traverse_fn(struct db_record *rec, void *private_data)
288 struct serverid_traverse_state *state =
289 (struct serverid_traverse_state *)private_data;
293 if (!serverid_rec_parse(rec, &id, &msg_flags)) {
296 return state->fn(rec, &id, msg_flags, state->private_data);
299 bool serverid_traverse(int (*fn)(struct db_record *rec,
300 const struct server_id *id,
301 uint32_t msg_flags, void *private_data),
304 struct db_context *db;
305 struct serverid_traverse_state state;
313 state.private_data = private_data;
315 status = dbwrap_traverse(db, serverid_traverse_fn, &state, NULL);
316 return NT_STATUS_IS_OK(status);
320 struct messaging_context *msg_ctx;
328 /****************************************************************************
329 Send one of the messages for the broadcast.
330 ****************************************************************************/
332 static int traverse_fn(struct db_record *rec, const struct server_id *id,
333 uint32_t msg_flags, void *state)
335 struct msg_all *msg_all = (struct msg_all *)state;
338 /* Don't send if the receiver hasn't registered an interest. */
340 if((msg_flags & msg_all->msg_flag) == 0) {
344 /* If the msg send fails because the pid was not found (i.e. smbd died),
345 * the msg has already been deleted from the messages.tdb.*/
347 status = messaging_send_buf(msg_all->msg_ctx, *id, msg_all->msg_type,
348 (const uint8_t *)msg_all->buf, msg_all->len);
350 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
351 struct server_id_buf idbuf;
354 * If the pid was not found delete the entry from
358 DEBUG(2, ("pid %s doesn't exist\n",
359 server_id_str_buf(*id, &idbuf)));
361 dbwrap_record_delete(rec);
368 * Send a message to all smbd processes.
370 * It isn't very efficient, but should be OK for the sorts of
371 * applications that use it. When we need efficient broadcast we can add
374 * @param n_sent Set to the number of messages sent. This should be
375 * equal to the number of processes, but be careful for races.
377 * @retval True for success.
379 bool message_send_all(struct messaging_context *msg_ctx,
381 const void *buf, size_t len,
384 struct msg_all msg_all;
386 msg_all.msg_type = msg_type;
387 if (msg_type < 0x100) {
388 msg_all.msg_flag = FLAG_MSG_GENERAL;
389 } else if (msg_type > 0x100 && msg_type < 0x200) {
390 msg_all.msg_flag = FLAG_MSG_NMBD;
391 } else if (msg_type > 0x200 && msg_type < 0x300) {
392 msg_all.msg_flag = FLAG_MSG_PRINT_GENERAL;
393 } else if (msg_type > 0x300 && msg_type < 0x400) {
394 msg_all.msg_flag = FLAG_MSG_SMBD;
395 } else if (msg_type > 0x400 && msg_type < 0x600) {
396 msg_all.msg_flag = FLAG_MSG_WINBIND;
397 } else if (msg_type > 4000 && msg_type < 5000) {
398 msg_all.msg_flag = FLAG_MSG_DBWRAP;
406 msg_all.msg_ctx = msg_ctx;
408 serverid_traverse(traverse_fn, &msg_all);
410 *n_sent = msg_all.n_sent;