1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-29 21:47:30 +03:00
samba-mirror/source/lib/messages.c
Andrew Tridgell 2a34ee95f3 the first cut of the internal messaging system.
The motivation for this system is to replace the UDP message for
oplocks, but this commit only does the "set debug level" message.
-

238 lines
6.0 KiB
C

/*
Unix SMB/Netbios implementation.
Version 3.0
Samba internal messaging functions
Copyright (C) Andrew Tridgell 2000
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* this module is used for internal messaging between Samba daemons. */
#include "includes.h"
/* the locking database handle */
static TDB_CONTEXT *tdb;
static int received_signal;
/* change the message version with any incompatible changes in the protocol */
#define MESSAGE_VERSION 1
struct message_rec {
int msg_version;
enum message_type msg_type;
pid_t dest;
pid_t src;
size_t len;
};
/****************************************************************************
notifications come in as signals
****************************************************************************/
static void sig_usr1(void)
{
received_signal = 1;
sys_select_signal();
}
/****************************************************************************
Initialise the messaging functions.
****************************************************************************/
BOOL message_init(void)
{
if (tdb) return True;
tdb = tdb_open(lock_path("messages.tdb"),
0, TDB_CLEAR_IF_FIRST,
O_RDWR|O_CREAT,0600);
if (!tdb) {
DEBUG(0,("ERROR: Failed to initialise messages database\n"));
return False;
}
CatchSignal(SIGUSR1, sig_usr1);
return True;
}
/*******************************************************************
form a static tdb key from a pid
******************************************************************/
static TDB_DATA message_key_pid(pid_t pid)
{
static char key[20];
TDB_DATA kbuf;
slprintf(key, sizeof(key), "PID/%d", (int)pid);
kbuf.dptr = (char *)key;
kbuf.dsize = sizeof(key);
return kbuf;
}
/****************************************************************************
notify a process that it has a message. If the process doesn't exist
then delete its record in the database
****************************************************************************/
static BOOL message_notify(pid_t pid)
{
if (kill(pid, SIGUSR1) == -1) {
if (errno == ESRCH) {
DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid));
tdb_delete(tdb, message_key_pid(pid));
} else {
DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno)));
}
return False;
}
return True;
}
/****************************************************************************
send a message to a particular pid
****************************************************************************/
BOOL message_send_pid(pid_t pid, enum message_type msg_type, void *buf, size_t len)
{
TDB_DATA kbuf;
TDB_DATA dbuf;
struct message_rec rec;
void *p;
rec.msg_version = MESSAGE_VERSION;
rec.msg_type = msg_type;
rec.dest = pid;
rec.src = sys_getpid();
rec.len = len;
kbuf = message_key_pid(pid);
/* lock the record for the destination */
tdb_lockchain(tdb, kbuf);
dbuf = tdb_fetch(tdb, kbuf);
if (!dbuf.dptr) {
/* its a new record */
p = (void *)malloc(len + sizeof(rec));
if (!p) goto failed;
memcpy(p, &rec, sizeof(rec));
memcpy(p+sizeof(rec), buf, len);
dbuf.dptr = p;
dbuf.dsize = len + sizeof(rec);
tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
free(p);
goto ok;
}
/* we're adding to an existing entry */
p = (void *)malloc(dbuf.dsize + len + sizeof(rec));
if (!p) goto failed;
memcpy(p, dbuf.dptr, dbuf.dsize);
memcpy(p+dbuf.dsize, &rec, sizeof(rec));
memcpy(p+dbuf.dsize+sizeof(rec), buf, len);
dbuf.dptr = p;
dbuf.dsize += len + sizeof(rec);
tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
free(dbuf.dptr);
free(p);
ok:
tdb_unlockchain(tdb, kbuf);
return message_notify(pid);
failed:
tdb_unlockchain(tdb, kbuf);
return False;
}
/****************************************************************************
retrieve the next message for the current process
****************************************************************************/
static BOOL message_recv(enum message_type *msg_type, pid_t *src, void **buf, size_t *len)
{
TDB_DATA kbuf;
TDB_DATA dbuf;
struct message_rec rec;
kbuf = message_key_pid(sys_getpid());
tdb_lockchain(tdb, kbuf);
dbuf = tdb_fetch(tdb, kbuf);
if (dbuf.dptr == NULL || dbuf.dsize == 0) goto failed;
memcpy(&rec, dbuf.dptr, sizeof(rec));
if (rec.msg_version != MESSAGE_VERSION) {
DEBUG(0,("message version %d received (expected %d)\n", rec.msg_version, MESSAGE_VERSION));
goto failed;
}
(*buf) = (void *)malloc(rec.len);
if (!(*buf)) goto failed;
memcpy(*buf, dbuf.dptr+sizeof(rec), rec.len);
*len = rec.len;
*msg_type = rec.msg_type;
*src = rec.src;
memmove(dbuf.dptr, dbuf.dptr+sizeof(rec)+rec.len, dbuf.dsize - (sizeof(rec)+rec.len));
dbuf.dsize -= sizeof(rec)+rec.len;
tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
free(dbuf.dptr);
tdb_unlockchain(tdb, kbuf);
return True;
failed:
tdb_unlockchain(tdb, kbuf);
return False;
}
/****************************************************************************
receive and dispatch any messages pending for this process
****************************************************************************/
void message_dispatch(void)
{
enum message_type msg_type;
pid_t src;
void *buf;
size_t len;
if (!received_signal) return;
received_signal = 0;
while (message_recv(&msg_type, &src, &buf, &len)) {
switch (msg_type) {
case MSG_DEBUG:
debug_message(src, buf, len);
break;
default:
DEBUG(0,("Unknown message type %d from %d\n", msg_type, (int)src));
break;
}
}
}