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
;