📄 messages.c
字号:
/* Unix SMB/CIFS implementation. Samba internal messaging functions Copyright (C) Andrew Tridgell 2000 Copyright (C) 2001 by Martin Pool Copyright (C) 2002 by Jeremy Allison 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.*//** @defgroup messages Internal messaging framework @{ @file messages.c @brief Module for internal messaging between Samba daemons. The idea is that if a part of Samba wants to do communication with another Samba process then it will do a message_register() of a dispatch function, and use message_send_pid() to send messages to that process. The dispatch function is given the pid of the sender, and it can use that to reply by message_send_pid(). See ping_message() for a simple example. @caution Dispatch functions must be able to cope with incoming messages on an *odd* byte boundary. This system doesn't have any inherent size limitations but is not very efficient for large messages or when messages are sent in very quick succession.*/#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 1struct message_rec { int msg_version; int msg_type; struct process_id dest; struct process_id src; size_t len;};/* we have a linked list of dispatch handlers */static struct dispatch_fns { struct dispatch_fns *next, *prev; int msg_type; void (*fn)(int msg_type, struct process_id pid, void *buf, size_t len);} *dispatch_fns;/**************************************************************************** Notifications come in as signals.****************************************************************************/static void sig_usr1(void){ received_signal = 1; sys_select_signal(SIGUSR1);}/**************************************************************************** A useful function for testing the message system.****************************************************************************/static void ping_message(int msg_type, struct process_id src, void *buf, size_t len){ const char *msg = buf ? buf : "none"; DEBUG(1,("INFO: Received PING message from PID %s [%s]\n", procid_str_static(&src), msg)); message_send_pid(src, MSG_PONG, buf, len, True);}/**************************************************************************** Initialise the messaging functions. ****************************************************************************/BOOL message_init(void){ if (tdb) return True; tdb = tdb_open_log(lock_path("messages.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT, O_RDWR|O_CREAT,0600); if (!tdb) { DEBUG(0,("ERROR: Failed to initialise messages database\n")); return False; } CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1); message_register(MSG_PING, ping_message); /* Register some debugging related messages */ register_msg_pool_usage(); register_dmalloc_msgs(); return True;}/******************************************************************* Form a static tdb key from a pid.******************************************************************/static TDB_DATA message_key_pid(struct process_id pid){ static char key[20]; TDB_DATA kbuf; slprintf(key, sizeof(key)-1, "PID/%s", procid_str_static(&pid)); kbuf.dptr = (char *)key; kbuf.dsize = strlen(key)+1; 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(struct process_id procid){ pid_t pid = procid.pid; /* * Doing kill with a non-positive pid causes messages to be * sent to places we don't want. */ SMB_ASSERT(pid > 0); 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(procid)); } 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.****************************************************************************/static BOOL message_send_pid_internal(struct process_id pid, int msg_type, const void *buf, size_t len, BOOL duplicates_allowed, unsigned int timeout){ TDB_DATA kbuf; TDB_DATA dbuf; TDB_DATA old_dbuf; struct message_rec rec; char *ptr; struct message_rec prec; /* * Doing kill with a non-positive pid causes messages to be * sent to places we don't want. */ SMB_ASSERT(procid_to_pid(&pid) > 0); rec.msg_version = MESSAGE_VERSION; rec.msg_type = msg_type; rec.dest = pid; rec.src = procid_self(); rec.len = len; kbuf = message_key_pid(pid); dbuf.dptr = (void *)SMB_MALLOC(len + sizeof(rec)); if (!dbuf.dptr) return False; memcpy(dbuf.dptr, &rec, sizeof(rec)); if (len > 0) memcpy((void *)((char*)dbuf.dptr+sizeof(rec)), buf, len); dbuf.dsize = len + sizeof(rec); if (duplicates_allowed) { /* If duplicates are allowed we can just append the message and return. */ /* lock the record for the destination */ if (timeout) { if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout)); return False; } } else { if (tdb_chainlock(tdb, kbuf) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n")); return False; } } tdb_append(tdb, kbuf, dbuf); tdb_chainunlock(tdb, kbuf); SAFE_FREE(dbuf.dptr); errno = 0; /* paranoia */ return message_notify(pid); } /* lock the record for the destination */ if (timeout) { if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout)); return False; } } else { if (tdb_chainlock(tdb, kbuf) == -1) { DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n")); return False; } } old_dbuf = tdb_fetch(tdb, kbuf); if (!old_dbuf.dptr) { /* its a new record */ tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); tdb_chainunlock(tdb, kbuf); SAFE_FREE(dbuf.dptr); errno = 0; /* paranoia */ return message_notify(pid); } /* Not a new record. Check for duplicates. */ for(ptr = (char *)old_dbuf.dptr; ptr < old_dbuf.dptr + old_dbuf.dsize; ) { /* * First check if the message header matches, then, if it's a non-zero * sized message, check if the data matches. If so it's a duplicate and * we can discard it. JRA. */ if (!memcmp(ptr, &rec, sizeof(rec))) { if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) { tdb_chainunlock(tdb, kbuf); DEBUG(10,("message_send_pid_internal: discarding duplicate message.\n")); SAFE_FREE(dbuf.dptr); SAFE_FREE(old_dbuf.dptr); return True; } } memcpy(&prec, ptr, sizeof(prec)); ptr += sizeof(rec) + prec.len; } /* we're adding to an existing entry */ tdb_append(tdb, kbuf, dbuf); tdb_chainunlock(tdb, kbuf); SAFE_FREE(old_dbuf.dptr); SAFE_FREE(dbuf.dptr); errno = 0; /* paranoia */ return message_notify(pid);}/**************************************************************************** Send a message to a particular pid - no timeout.****************************************************************************/BOOL message_send_pid(struct process_id pid, int msg_type, const void *buf, size_t len, BOOL duplicates_allowed){ return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed, 0);}/**************************************************************************** Send a message to a particular pid, with timeout in seconds.****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -