summaryrefslogtreecommitdiff
path: root/source3/lib/messages.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2000-09-11 07:02:43 +0000
committerAndrew Tridgell <tridge@samba.org>2000-09-11 07:02:43 +0000
commit3689e4ffc10fceb4c39814ef58fe31697e7dd976 (patch)
tree805fc5690a3b97e4e72866519760ee86a038c781 /source3/lib/messages.c
parente0f9de0c49dde82610b0da406b4685e787f69725 (diff)
downloadsamba-3689e4ffc10fceb4c39814ef58fe31697e7dd976.tar.gz
samba-3689e4ffc10fceb4c39814ef58fe31697e7dd976.tar.bz2
samba-3689e4ffc10fceb4c39814ef58fe31697e7dd976.zip
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. (This used to be commit 2a34ee95f3929cff131db6c5a2b4820194c05b2d)
Diffstat (limited to 'source3/lib/messages.c')
-rw-r--r--source3/lib/messages.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/source3/lib/messages.c b/source3/lib/messages.c
new file mode 100644
index 0000000000..30eef40ec9
--- /dev/null
+++ b/source3/lib/messages.c
@@ -0,0 +1,237 @@
+/*
+ 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;
+ }
+ }
+}