s3:build: remove global CLUSTER_SUPPORT define
[Samba.git] / source3 / lib / serverid.c
blob5d5981825d0e07485e6dfb2963aeface9bd3e37c
1 /*
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/>.
20 #include "includes.h"
21 #include "system/filesys.h"
22 #include "serverid.h"
23 #include "util_tdb.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_open.h"
26 #include "lib/tdb_wrap/tdb_wrap.h"
27 #include "lib/param/param.h"
28 #include "ctdbd_conn.h"
29 #include "messages.h"
31 struct serverid_key {
32 pid_t pid;
33 uint32_t task_id;
34 uint32_t vnn;
37 struct serverid_data {
38 uint64_t unique_id;
39 uint32_t msg_flags;
42 bool serverid_parent_init(TALLOC_CTX *mem_ctx)
44 struct tdb_wrap *db;
45 struct loadparm_context *lp_ctx;
47 lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
48 if (lp_ctx == NULL) {
49 DEBUG(0, ("loadparm_init_s3 failed\n"));
50 return false;
54 * Open the tdb in the parent process (smbd) so that our
55 * CLEAR_IF_FIRST optimization in tdb_reopen_all can properly
56 * work.
59 db = tdb_wrap_open(mem_ctx, lock_path("serverid.tdb"),
60 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT,
61 0644, lp_ctx);
62 talloc_unlink(mem_ctx, lp_ctx);
63 if (db == NULL) {
64 DEBUG(1, ("could not open serverid.tdb: %s\n",
65 strerror(errno)));
66 return false;
68 return true;
71 static struct db_context *serverid_db(void)
73 static struct db_context *db;
75 if (db != NULL) {
76 return db;
78 db = db_open(NULL, lock_path("serverid.tdb"), 0,
79 TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
80 O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2,
81 DBWRAP_FLAG_NONE);
82 return db;
85 static void serverid_fill_key(const struct server_id *id,
86 struct serverid_key *key)
88 ZERO_STRUCTP(key);
89 key->pid = id->pid;
90 key->task_id = id->task_id;
91 key->vnn = id->vnn;
94 bool serverid_register(const struct server_id id, uint32_t msg_flags)
96 struct db_context *db;
97 struct serverid_key key;
98 struct serverid_data data;
99 struct db_record *rec;
100 TDB_DATA tdbkey, tdbdata;
101 NTSTATUS status;
102 bool ret = false;
104 db = serverid_db();
105 if (db == NULL) {
106 return false;
109 serverid_fill_key(&id, &key);
110 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
112 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
113 if (rec == NULL) {
114 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
115 return false;
118 ZERO_STRUCT(data);
119 data.unique_id = id.unique_id;
120 data.msg_flags = msg_flags;
122 tdbdata = make_tdb_data((uint8_t *)&data, sizeof(data));
123 status = dbwrap_record_store(rec, tdbdata, 0);
124 if (!NT_STATUS_IS_OK(status)) {
125 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
126 nt_errstr(status)));
127 goto done;
130 if (lp_clustering() &&
131 ctdb_serverids_exist_supported(messaging_ctdbd_connection()))
133 register_with_ctdbd(messaging_ctdbd_connection(), id.unique_id);
136 ret = true;
137 done:
138 TALLOC_FREE(rec);
139 return ret;
142 bool serverid_register_msg_flags(const struct server_id id, bool do_reg,
143 uint32_t msg_flags)
145 struct db_context *db;
146 struct serverid_key key;
147 struct serverid_data *data;
148 struct db_record *rec;
149 TDB_DATA tdbkey;
150 TDB_DATA value;
151 NTSTATUS status;
152 bool ret = false;
154 db = serverid_db();
155 if (db == NULL) {
156 return false;
159 serverid_fill_key(&id, &key);
160 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
162 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
163 if (rec == NULL) {
164 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
165 return false;
168 value = dbwrap_record_get_value(rec);
170 if (value.dsize != sizeof(struct serverid_data)) {
171 DEBUG(1, ("serverid record has unexpected size %d "
172 "(wanted %d)\n", (int)value.dsize,
173 (int)sizeof(struct serverid_data)));
174 goto done;
177 data = (struct serverid_data *)value.dptr;
179 if (do_reg) {
180 data->msg_flags |= msg_flags;
181 } else {
182 data->msg_flags &= ~msg_flags;
185 status = dbwrap_record_store(rec, value, 0);
186 if (!NT_STATUS_IS_OK(status)) {
187 DEBUG(1, ("Storing serverid.tdb record failed: %s\n",
188 nt_errstr(status)));
189 goto done;
191 ret = true;
192 done:
193 TALLOC_FREE(rec);
194 return ret;
197 bool serverid_deregister(struct server_id id)
199 struct db_context *db;
200 struct serverid_key key;
201 struct db_record *rec;
202 TDB_DATA tdbkey;
203 NTSTATUS status;
204 bool ret = false;
206 db = serverid_db();
207 if (db == NULL) {
208 return false;
211 serverid_fill_key(&id, &key);
212 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
214 rec = dbwrap_fetch_locked(db, talloc_tos(), tdbkey);
215 if (rec == NULL) {
216 DEBUG(1, ("Could not fetch_lock serverid.tdb record\n"));
217 return false;
220 status = dbwrap_record_delete(rec);
221 if (!NT_STATUS_IS_OK(status)) {
222 DEBUG(1, ("Deleting serverid.tdb record failed: %s\n",
223 nt_errstr(status)));
224 goto done;
226 ret = true;
227 done:
228 TALLOC_FREE(rec);
229 return ret;
232 struct serverid_exists_state {
233 const struct server_id *id;
234 bool exists;
237 static void server_exists_parse(TDB_DATA key, TDB_DATA data, void *priv)
239 struct serverid_exists_state *state =
240 (struct serverid_exists_state *)priv;
242 if (data.dsize != sizeof(struct serverid_data)) {
243 state->exists = false;
244 return;
248 * Use memcmp, not direct compare. data.dptr might not be
249 * aligned.
251 state->exists = (memcmp(&state->id->unique_id, data.dptr,
252 sizeof(state->id->unique_id)) == 0);
255 bool serverid_exists(const struct server_id *id)
257 bool result = false;
258 bool ok = false;
260 ok = serverids_exist(id, 1, &result);
261 if (!ok) {
262 return false;
265 return result;
268 bool serverids_exist(const struct server_id *ids, int num_ids, bool *results)
270 int *todo_idx = NULL;
271 struct server_id *todo_ids = NULL;
272 bool *todo_results = NULL;
273 int todo_num = 0;
274 int *remote_idx = NULL;
275 int remote_num = 0;
276 int *verify_idx = NULL;
277 int verify_num = 0;
278 int t, idx;
279 bool result = false;
280 struct db_context *db;
282 db = serverid_db();
283 if (db == NULL) {
284 return false;
287 todo_idx = talloc_array(talloc_tos(), int, num_ids);
288 if (todo_idx == NULL) {
289 goto fail;
291 todo_ids = talloc_array(talloc_tos(), struct server_id, num_ids);
292 if (todo_ids == NULL) {
293 goto fail;
295 todo_results = talloc_array(talloc_tos(), bool, num_ids);
296 if (todo_results == NULL) {
297 goto fail;
300 remote_idx = talloc_array(talloc_tos(), int, num_ids);
301 if (remote_idx == NULL) {
302 goto fail;
304 verify_idx = talloc_array(talloc_tos(), int, num_ids);
305 if (verify_idx == NULL) {
306 goto fail;
309 for (idx=0; idx<num_ids; idx++) {
310 results[idx] = false;
312 if (server_id_is_disconnected(&ids[idx])) {
313 continue;
316 if (procid_is_me(&ids[idx])) {
317 results[idx] = true;
318 continue;
321 if (procid_is_local(&ids[idx])) {
322 bool exists = process_exists_by_pid(ids[idx].pid);
324 if (!exists) {
325 continue;
328 if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
329 results[idx] = true;
330 continue;
333 verify_idx[verify_num] = idx;
334 verify_num += 1;
335 continue;
338 if (!lp_clustering()) {
339 continue;
342 remote_idx[remote_num] = idx;
343 remote_num += 1;
346 if (remote_num != 0 &&
347 ctdb_serverids_exist_supported(messaging_ctdbd_connection()))
349 int old_remote_num = remote_num;
351 remote_num = 0;
352 todo_num = 0;
354 for (t=0; t<old_remote_num; t++) {
355 idx = remote_idx[t];
357 if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
358 remote_idx[remote_num] = idx;
359 remote_num += 1;
360 continue;
363 todo_idx[todo_num] = idx;
364 todo_ids[todo_num] = ids[idx];
365 todo_results[todo_num] = false;
366 todo_num += 1;
370 * Note: this only uses CTDB_CONTROL_CHECK_SRVIDS
371 * to verify that the server_id still exists,
372 * which means only the server_id.unique_id and
373 * server_id.vnn are verified, while server_id.pid
374 * is not verified at all.
376 * TODO: do we want to verify server_id.pid somehow?
378 if (!ctdb_serverids_exist(messaging_ctdbd_connection(),
379 todo_ids, todo_num, todo_results))
381 goto fail;
384 for (t=0; t<todo_num; t++) {
385 idx = todo_idx[t];
387 results[idx] = todo_results[t];
391 if (remote_num != 0) {
392 todo_num = 0;
394 for (t=0; t<remote_num; t++) {
395 idx = remote_idx[t];
396 todo_idx[todo_num] = idx;
397 todo_ids[todo_num] = ids[idx];
398 todo_results[todo_num] = false;
399 todo_num += 1;
402 if (!ctdb_processes_exist(messaging_ctdbd_connection(),
403 todo_ids, todo_num,
404 todo_results)) {
405 goto fail;
408 for (t=0; t<todo_num; t++) {
409 idx = todo_idx[t];
411 if (!todo_results[t]) {
412 continue;
415 if (ids[idx].unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
416 results[idx] = true;
417 continue;
420 verify_idx[verify_num] = idx;
421 verify_num += 1;
425 for (t=0; t<verify_num; t++) {
426 struct serverid_exists_state state;
427 struct serverid_key key;
428 TDB_DATA tdbkey;
429 NTSTATUS status;
431 idx = verify_idx[t];
433 serverid_fill_key(&ids[idx], &key);
434 tdbkey = make_tdb_data((uint8_t *)&key, sizeof(key));
436 state.id = &ids[idx];
437 state.exists = false;
438 status = dbwrap_parse_record(db, tdbkey, server_exists_parse, &state);
439 if (!NT_STATUS_IS_OK(status)) {
440 results[idx] = false;
441 continue;
443 results[idx] = state.exists;
446 result = true;
447 fail:
448 TALLOC_FREE(verify_idx);
449 TALLOC_FREE(remote_idx);
450 TALLOC_FREE(todo_results);
451 TALLOC_FREE(todo_ids);
452 TALLOC_FREE(todo_idx);
453 return result;
456 static bool serverid_rec_parse(const struct db_record *rec,
457 struct server_id *id, uint32_t *msg_flags)
459 struct serverid_key key;
460 struct serverid_data data;
461 TDB_DATA tdbkey;
462 TDB_DATA tdbdata;
464 tdbkey = dbwrap_record_get_key(rec);
465 tdbdata = dbwrap_record_get_value(rec);
467 if (tdbkey.dsize != sizeof(key)) {
468 DEBUG(1, ("Found invalid key length %d in serverid.tdb\n",
469 (int)tdbkey.dsize));
470 return false;
472 if (tdbdata.dsize != sizeof(data)) {
473 DEBUG(1, ("Found invalid value length %d in serverid.tdb\n",
474 (int)tdbdata.dsize));
475 return false;
478 memcpy(&key, tdbkey.dptr, sizeof(key));
479 memcpy(&data, tdbdata.dptr, sizeof(data));
481 id->pid = key.pid;
482 id->task_id = key.task_id;
483 id->vnn = key.vnn;
484 id->unique_id = data.unique_id;
485 *msg_flags = data.msg_flags;
486 return true;
489 struct serverid_traverse_read_state {
490 int (*fn)(const struct server_id *id, uint32_t msg_flags,
491 void *private_data);
492 void *private_data;
495 static int serverid_traverse_read_fn(struct db_record *rec, void *private_data)
497 struct serverid_traverse_read_state *state =
498 (struct serverid_traverse_read_state *)private_data;
499 struct server_id id;
500 uint32_t msg_flags;
502 if (!serverid_rec_parse(rec, &id, &msg_flags)) {
503 return 0;
505 return state->fn(&id, msg_flags,state->private_data);
508 bool serverid_traverse_read(int (*fn)(const struct server_id *id,
509 uint32_t msg_flags, void *private_data),
510 void *private_data)
512 struct db_context *db;
513 struct serverid_traverse_read_state state;
514 NTSTATUS status;
516 db = serverid_db();
517 if (db == NULL) {
518 return false;
520 state.fn = fn;
521 state.private_data = private_data;
523 status = dbwrap_traverse_read(db, serverid_traverse_read_fn, &state,
524 NULL);
525 return NT_STATUS_IS_OK(status);
528 struct serverid_traverse_state {
529 int (*fn)(struct db_record *rec, const struct server_id *id,
530 uint32_t msg_flags, void *private_data);
531 void *private_data;
534 static int serverid_traverse_fn(struct db_record *rec, void *private_data)
536 struct serverid_traverse_state *state =
537 (struct serverid_traverse_state *)private_data;
538 struct server_id id;
539 uint32_t msg_flags;
541 if (!serverid_rec_parse(rec, &id, &msg_flags)) {
542 return 0;
544 return state->fn(rec, &id, msg_flags, state->private_data);
547 bool serverid_traverse(int (*fn)(struct db_record *rec,
548 const struct server_id *id,
549 uint32_t msg_flags, void *private_data),
550 void *private_data)
552 struct db_context *db;
553 struct serverid_traverse_state state;
554 NTSTATUS status;
556 db = serverid_db();
557 if (db == NULL) {
558 return false;
560 state.fn = fn;
561 state.private_data = private_data;
563 status = dbwrap_traverse(db, serverid_traverse_fn, &state, NULL);
564 return NT_STATUS_IS_OK(status);
567 uint64_t serverid_get_random_unique_id(void)
569 uint64_t unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
571 while (unique_id == SERVERID_UNIQUE_ID_NOT_TO_VERIFY) {
572 generate_random_buffer((uint8_t *)&unique_id,
573 sizeof(unique_id));
576 return unique_id;