2000-09-11 11:02:43 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-09-11 11:02:43 +04:00
Samba internal messaging functions
Copyright ( C ) Andrew Tridgell 2000
2001-12-21 03:37:49 +03:00
Copyright ( C ) 2001 by Martin Pool
2003-01-10 23:17:02 +03:00
Copyright ( C ) 2002 by Jeremy Allison
2007-05-21 00:11:23 +04:00
Copyright ( C ) 2007 by Volker Lendecke
2011-10-31 15:41:09 +04:00
2000-09-11 11:02:43 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2000-09-11 11:02:43 +04:00
( at your option ) any later version .
2011-10-31 15:41:09 +04:00
2000-09-11 11:02:43 +04:00
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 .
2011-10-31 15:41:09 +04:00
2000-09-11 11:02:43 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2000-09-11 11:02:43 +04:00
*/
2001-12-19 10:49:25 +03:00
/**
2003-03-18 01:42:56 +03:00
@ defgroup messages Internal messaging framework
@ {
@ file messages . c
2011-10-31 15:41:09 +04:00
2003-03-18 01:42:56 +03:00
@ brief Module for internal messaging between Samba daemons .
2000-09-12 04:47:11 +04:00
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 .
2001-12-19 10:49:25 +03:00
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 .
2003-03-18 01:42:56 +03:00
@ caution Dispatch functions must be able to cope with incoming
2003-01-10 23:17:02 +03:00
messages on an * odd * byte boundary .
2000-09-12 04:47:11 +04:00
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 .
*/
2000-09-11 11:02:43 +04:00
# include "includes.h"
2017-01-01 23:00:55 +03:00
# include "lib/util/server_id.h"
2011-07-07 19:42:08 +04:00
# include "dbwrap/dbwrap.h"
2011-02-25 01:05:57 +03:00
# include "serverid.h"
2011-03-24 17:31:06 +03:00
# include "messages.h"
2013-12-30 14:26:52 +04:00
# include "lib/util/tevent_unix.h"
2014-04-11 15:08:56 +04:00
# include "lib/background.h"
2014-07-27 14:31:21 +04:00
# include "lib/messages_dgm.h"
2017-06-01 20:25:48 +03:00
# include "lib/messages_ctdbd.h"
2015-02-14 18:48:54 +03:00
# include "lib/util/iov_buf.h"
2014-10-17 16:09:03 +04:00
# include "lib/util/server_id_db.h"
2014-10-04 13:21:18 +04:00
# include "lib/messages_dgm_ref.h"
2015-02-11 18:28:55 +03:00
# include "lib/messages_util.h"
2000-09-11 11:02:43 +04:00
2007-05-22 02:17:13 +04:00
struct messaging_callback {
struct messaging_callback * prev , * next ;
2015-05-10 02:33:10 +03:00
uint32_t msg_type ;
2007-05-22 02:17:13 +04:00
void ( * fn ) ( struct messaging_context * msg , void * private_data ,
uint32_t msg_type ,
struct server_id server_id , DATA_BLOB * data ) ;
r21064: The core of this patch is
void message_register(int msg_type,
void (*fn)(int msg_type, struct process_id pid,
- void *buf, size_t len))
+ void *buf, size_t len,
+ void *private_data),
+ void *private_data)
{
struct dispatch_fns *dfn;
So this adds a (so far unused) private pointer that is passed from
message_register to the message handler. A prerequisite to implement a tiny
samba4-API compatible wrapper around our messaging system. That itself is
necessary for the Samba4 notify system.
Yes, I know, I could import the whole Samba4 messaging system, but I want to
do it step by step and I think getting notify in is more important in this
step.
Volker
(This used to be commit c8ae60ed65dcce9660ee39c75488f2838cf9a28b)
2007-01-31 01:22:06 +03:00
void * private_data ;
2007-05-22 02:17:13 +04:00
} ;
2006-04-08 21:25:31 +04:00
2017-06-22 09:34:34 +03:00
struct messaging_registered_ev {
struct tevent_context * ev ;
2017-06-22 09:54:56 +03:00
struct tevent_immediate * im ;
2017-06-22 09:34:34 +03:00
size_t refcount ;
} ;
2014-05-29 18:44:55 +04:00
struct messaging_context {
struct server_id id ;
struct tevent_context * event_ctx ;
struct messaging_callback * callbacks ;
2017-06-22 09:54:56 +03:00
struct messaging_rec * posted_msgs ;
2017-06-22 09:34:34 +03:00
struct messaging_registered_ev * event_contexts ;
2014-05-29 18:44:55 +04:00
struct tevent_req * * new_waiters ;
2017-06-17 10:46:43 +03:00
size_t num_new_waiters ;
2014-05-29 18:44:55 +04:00
struct tevent_req * * waiters ;
2017-06-17 10:46:43 +03:00
size_t num_waiters ;
2014-05-29 18:44:55 +04:00
2014-10-04 13:21:18 +04:00
void * msg_dgm_ref ;
2014-05-29 18:44:55 +04:00
struct messaging_backend * remote ;
2014-10-17 16:09:03 +04:00
struct server_id_db * names_db ;
2014-05-29 18:44:55 +04:00
} ;
2016-09-24 05:06:56 +03:00
static struct messaging_rec * messaging_rec_dup ( TALLOC_CTX * mem_ctx ,
struct messaging_rec * rec ) ;
2017-06-22 09:54:56 +03:00
static bool messaging_dispatch_classic ( struct messaging_context * msg_ctx ,
struct messaging_rec * rec ) ;
2017-06-17 16:43:14 +03:00
static bool messaging_dispatch_waiters ( struct messaging_context * msg_ctx ,
struct tevent_context * ev ,
struct messaging_rec * rec ) ;
2015-05-24 22:25:56 +03:00
static void messaging_dispatch_rec ( struct messaging_context * msg_ctx ,
2016-09-24 05:28:10 +03:00
struct tevent_context * ev ,
2015-05-24 22:25:56 +03:00
struct messaging_rec * rec ) ;
2000-09-12 10:57:25 +04:00
/****************************************************************************
2001-11-21 01:55:46 +03:00
A useful function for testing the message system .
2000-09-12 10:57:25 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-11-21 01:55:46 +03:00
2007-05-22 02:17:13 +04:00
static void ping_message ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id src ,
DATA_BLOB * data )
2000-09-12 10:57:25 +04:00
{
2014-07-09 17:06:45 +04:00
struct server_id_buf idbuf ;
2014-07-09 17:17:13 +04:00
DEBUG ( 1 , ( " INFO: Received PING message from PID %s [%.*s] \n " ,
server_id_str_buf ( src , & idbuf ) , ( int ) data - > length ,
data - > data ? ( char * ) data - > data : " " ) ) ;
2007-05-22 02:17:13 +04:00
messaging_send ( msg_ctx , src , MSG_PONG , data ) ;
2000-09-12 10:57:25 +04:00
}
2001-11-21 01:55:46 +03:00
2017-06-24 09:38:19 +03:00
struct messaging_rec * messaging_rec_create (
2016-09-24 05:06:56 +03:00
TALLOC_CTX * mem_ctx , struct server_id src , struct server_id dst ,
uint32_t msg_type , const struct iovec * iov , int iovlen ,
const int * fds , size_t num_fds )
{
ssize_t buflen ;
uint8_t * buf ;
struct messaging_rec * result ;
if ( num_fds > INT8_MAX ) {
return NULL ;
}
buflen = iov_buflen ( iov , iovlen ) ;
if ( buflen = = - 1 ) {
return NULL ;
}
buf = talloc_array ( mem_ctx , uint8_t , buflen ) ;
if ( buf = = NULL ) {
return NULL ;
}
iov_buf ( iov , iovlen , buf , buflen ) ;
{
struct messaging_rec rec ;
int64_t fds64 [ num_fds ] ;
size_t i ;
for ( i = 0 ; i < num_fds ; i + + ) {
fds64 [ i ] = fds [ i ] ;
}
rec = ( struct messaging_rec ) {
. msg_version = MESSAGE_VERSION , . msg_type = msg_type ,
. src = src , . dest = dst ,
. buf . data = buf , . buf . length = buflen ,
. num_fds = num_fds , . fds = fds64 ,
} ;
result = messaging_rec_dup ( mem_ctx , & rec ) ;
}
TALLOC_FREE ( buf ) ;
return result ;
}
2017-06-22 09:34:34 +03:00
static bool messaging_register_event_context ( struct messaging_context * ctx ,
struct tevent_context * ev )
{
size_t i , num_event_contexts ;
struct messaging_registered_ev * free_reg = NULL ;
struct messaging_registered_ev * tmp ;
num_event_contexts = talloc_array_length ( ctx - > event_contexts ) ;
for ( i = 0 ; i < num_event_contexts ; i + + ) {
struct messaging_registered_ev * reg = & ctx - > event_contexts [ i ] ;
if ( reg - > ev = = ev ) {
reg - > refcount + = 1 ;
return true ;
}
if ( reg - > refcount = = 0 ) {
if ( reg - > ev ! = NULL ) {
abort ( ) ;
}
free_reg = reg ;
}
}
if ( free_reg = = NULL ) {
tmp = talloc_realloc ( ctx , ctx - > event_contexts ,
struct messaging_registered_ev ,
num_event_contexts + 1 ) ;
if ( tmp = = NULL ) {
return false ;
}
ctx - > event_contexts = tmp ;
free_reg = & ctx - > event_contexts [ num_event_contexts ] ;
}
* free_reg = ( struct messaging_registered_ev ) { . ev = ev , . refcount = 1 } ;
return true ;
}
static bool messaging_deregister_event_context ( struct messaging_context * ctx ,
struct tevent_context * ev )
{
size_t i , num_event_contexts ;
num_event_contexts = talloc_array_length ( ctx - > event_contexts ) ;
for ( i = 0 ; i < num_event_contexts ; i + + ) {
struct messaging_registered_ev * reg = & ctx - > event_contexts [ i ] ;
if ( reg - > ev = = ev ) {
if ( reg - > refcount = = 0 ) {
return false ;
}
reg - > refcount - = 1 ;
if ( reg - > refcount = = 0 ) {
/*
* Not strictly necessary , just
* paranoia
*/
reg - > ev = NULL ;
2017-06-22 09:54:56 +03:00
/*
* Do not talloc_free ( reg - > im ) ,
* recycle immediates events .
*/
2017-06-22 09:34:34 +03:00
}
return true ;
}
}
return false ;
}
2017-06-22 09:54:56 +03:00
static void messaging_post_main_event_context ( struct tevent_context * ev ,
struct tevent_immediate * im ,
void * private_data )
{
struct messaging_context * ctx = talloc_get_type_abort (
private_data , struct messaging_context ) ;
while ( ctx - > posted_msgs ! = NULL ) {
struct messaging_rec * rec = ctx - > posted_msgs ;
bool consumed ;
DLIST_REMOVE ( ctx - > posted_msgs , rec ) ;
consumed = messaging_dispatch_classic ( ctx , rec ) ;
if ( ! consumed ) {
consumed = messaging_dispatch_waiters (
ctx , ctx - > event_ctx , rec ) ;
}
if ( ! consumed ) {
uint8_t i ;
for ( i = 0 ; i < rec - > num_fds ; i + + ) {
close ( rec - > fds [ i ] ) ;
}
}
TALLOC_FREE ( rec ) ;
}
}
static void messaging_post_sub_event_context ( struct tevent_context * ev ,
struct tevent_immediate * im ,
void * private_data )
{
struct messaging_context * ctx = talloc_get_type_abort (
private_data , struct messaging_context ) ;
struct messaging_rec * rec , * next ;
for ( rec = ctx - > posted_msgs ; rec ! = NULL ; rec = next ) {
bool consumed ;
next = rec - > next ;
consumed = messaging_dispatch_waiters ( ctx , ev , rec ) ;
if ( consumed ) {
DLIST_REMOVE ( ctx - > posted_msgs , rec ) ;
TALLOC_FREE ( rec ) ;
}
}
}
static bool messaging_alert_event_contexts ( struct messaging_context * ctx )
{
size_t i , num_event_contexts ;
num_event_contexts = talloc_array_length ( ctx - > event_contexts ) ;
for ( i = 0 ; i < num_event_contexts ; i + + ) {
struct messaging_registered_ev * reg = & ctx - > event_contexts [ i ] ;
if ( reg - > refcount = = 0 ) {
continue ;
}
if ( reg - > im = = NULL ) {
reg - > im = tevent_create_immediate (
ctx - > event_contexts ) ;
}
if ( reg - > im = = NULL ) {
DBG_WARNING ( " Could not create immediate \n " ) ;
continue ;
}
/*
* We depend on schedule_immediate to work
* multiple times . Might be a bit inefficient ,
* but this needs to be proven in tests . The
* alternatively would be to track whether the
* immediate has already been scheduled . For
* now , avoid that complexity here .
*/
if ( reg - > ev = = ctx - > event_ctx ) {
tevent_schedule_immediate (
reg - > im , reg - > ev ,
messaging_post_main_event_context ,
ctx ) ;
} else {
tevent_schedule_immediate (
reg - > im , reg - > ev ,
messaging_post_sub_event_context ,
ctx ) ;
}
}
return true ;
}
2016-09-24 04:36:15 +03:00
static void messaging_recv_cb ( struct tevent_context * ev ,
const uint8_t * msg , size_t msg_len ,
2014-09-30 13:29:22 +04:00
int * fds , size_t num_fds ,
2014-07-17 13:44:41 +04:00
void * private_data )
{
struct messaging_context * msg_ctx = talloc_get_type_abort (
private_data , struct messaging_context ) ;
2014-07-27 14:29:26 +04:00
struct server_id_buf idbuf ;
2014-07-17 13:44:41 +04:00
struct messaging_rec rec ;
2014-06-24 09:39:05 +04:00
int64_t fds64 [ MIN ( num_fds , INT8_MAX ) ] ;
size_t i ;
2014-07-17 13:44:41 +04:00
2015-05-25 20:50:46 +03:00
if ( msg_len < MESSAGE_HDR_LENGTH ) {
2016-07-25 18:05:37 +03:00
DBG_WARNING ( " message too short: %zu \n " , msg_len ) ;
2015-06-23 12:03:47 +03:00
goto close_fail ;
2014-07-27 14:29:26 +04:00
}
2014-06-24 09:39:05 +04:00
if ( num_fds > INT8_MAX ) {
2016-07-25 18:05:37 +03:00
DBG_WARNING ( " too many fds: %zu \n " , num_fds ) ;
2015-06-23 12:03:47 +03:00
goto close_fail ;
2014-06-24 09:39:05 +04:00
}
2014-09-30 11:48:18 +04:00
/*
* " consume " the fds by copying them and setting
* the original variable to - 1
*/
2014-06-24 09:39:05 +04:00
for ( i = 0 ; i < num_fds ; i + + ) {
fds64 [ i ] = fds [ i ] ;
2014-09-30 11:48:18 +04:00
fds [ i ] = - 1 ;
2014-06-24 09:39:05 +04:00
}
2014-07-17 13:44:41 +04:00
rec = ( struct messaging_rec ) {
. msg_version = MESSAGE_VERSION ,
2015-05-25 20:50:46 +03:00
. buf . data = discard_const_p ( uint8_t , msg ) + MESSAGE_HDR_LENGTH ,
. buf . length = msg_len - MESSAGE_HDR_LENGTH ,
2014-06-24 09:39:05 +04:00
. num_fds = num_fds ,
. fds = fds64 ,
2014-07-17 13:44:41 +04:00
} ;
2015-02-11 18:28:55 +03:00
message_hdr_get ( & rec . msg_type , & rec . src , & rec . dest , msg ) ;
2016-07-25 18:05:37 +03:00
DBG_DEBUG ( " Received message 0x%x len %zu (num_fds:%zu) from %s \n " ,
( unsigned ) rec . msg_type , rec . buf . length , num_fds ,
server_id_str_buf ( rec . src , & idbuf ) ) ;
2015-02-11 18:28:55 +03:00
2016-09-24 05:28:10 +03:00
messaging_dispatch_rec ( msg_ctx , ev , & rec ) ;
2015-06-23 12:03:47 +03:00
return ;
close_fail :
for ( i = 0 ; i < num_fds ; i + + ) {
close ( fds [ i ] ) ;
}
2014-07-17 13:44:41 +04:00
}
2014-09-10 18:13:18 +04:00
static int messaging_context_destructor ( struct messaging_context * ctx )
{
2017-06-17 10:46:43 +03:00
size_t i ;
2014-10-22 19:11:43 +04:00
for ( i = 0 ; i < ctx - > num_new_waiters ; i + + ) {
if ( ctx - > new_waiters [ i ] ! = NULL ) {
tevent_req_set_cleanup_fn ( ctx - > new_waiters [ i ] , NULL ) ;
ctx - > new_waiters [ i ] = NULL ;
}
}
for ( i = 0 ; i < ctx - > num_waiters ; i + + ) {
if ( ctx - > waiters [ i ] ! = NULL ) {
tevent_req_set_cleanup_fn ( ctx - > waiters [ i ] , NULL ) ;
ctx - > waiters [ i ] = NULL ;
}
}
2017-06-22 09:54:56 +03:00
/*
* The immediates from messaging_alert_event_contexts
* reference " ctx " . Don ' t let them outlive the
* messaging_context we ' re destroying here .
*/
TALLOC_FREE ( ctx - > event_contexts ) ;
2014-09-10 18:13:18 +04:00
return 0 ;
}
2014-10-04 12:58:15 +04:00
static const char * private_path ( const char * name )
{
return talloc_asprintf ( talloc_tos ( ) , " %s/%s " , lp_private_dir ( ) , name ) ;
}
2016-11-14 11:42:51 +03:00
static NTSTATUS messaging_init_internal ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct messaging_context * * pmsg_ctx )
2007-01-31 15:01:52 +03:00
{
2016-11-14 11:42:51 +03:00
TALLOC_CTX * frame ;
2007-01-31 15:01:52 +03:00
struct messaging_context * ctx ;
2016-11-14 11:42:51 +03:00
NTSTATUS status = NT_STATUS_UNSUCCESSFUL ;
2014-06-10 19:21:10 +04:00
int ret ;
2014-10-04 12:58:15 +04:00
const char * lck_path ;
const char * priv_path ;
bool ok ;
2007-01-31 15:01:52 +03:00
2015-09-16 13:44:43 +03:00
lck_path = lock_path ( " msg.lock " ) ;
2014-10-04 12:58:15 +04:00
if ( lck_path = = NULL ) {
2016-11-14 11:42:51 +03:00
return NT_STATUS_NO_MEMORY ;
2014-10-04 12:58:15 +04:00
}
2016-11-14 11:42:51 +03:00
ok = directory_create_or_exist_strict ( lck_path ,
sec_initial_uid ( ) ,
2014-10-04 12:58:15 +04:00
0755 ) ;
if ( ! ok ) {
2016-11-14 11:42:51 +03:00
DBG_DEBUG ( " Could not create lock directory: %s \n " ,
strerror ( errno ) ) ;
return NT_STATUS_ACCESS_DENIED ;
2014-10-04 12:58:15 +04:00
}
2015-09-16 13:44:43 +03:00
priv_path = private_path ( " msg.sock " ) ;
2015-09-16 13:42:48 +03:00
if ( priv_path = = NULL ) {
2016-11-14 11:42:51 +03:00
return NT_STATUS_NO_MEMORY ;
2015-09-16 13:42:48 +03:00
}
2014-10-04 12:58:15 +04:00
ok = directory_create_or_exist_strict ( priv_path , sec_initial_uid ( ) ,
0700 ) ;
if ( ! ok ) {
2016-11-14 11:42:51 +03:00
DBG_DEBUG ( " Could not create msg directory: %s \n " ,
strerror ( errno ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
frame = talloc_stackframe ( ) ;
if ( frame = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
ctx = talloc_zero ( frame , struct messaging_context ) ;
if ( ctx = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
2014-10-04 12:58:15 +04:00
}
2016-11-14 11:42:51 +03:00
ctx - > id = ( struct server_id ) {
. pid = getpid ( ) , . vnn = NONCLUSTER_VNN
} ;
ctx - > event_ctx = ev ;
2007-05-24 18:47:24 +04:00
2017-06-22 09:34:34 +03:00
ok = messaging_register_event_context ( ctx , ev ) ;
if ( ! ok ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
2016-11-14 11:42:51 +03:00
sec_init ( ) ;
ctx - > msg_dgm_ref = messaging_dgm_ref ( ctx ,
ctx - > event_ctx ,
& ctx - > id . unique_id ,
priv_path ,
lck_path ,
messaging_recv_cb ,
ctx ,
& ret ) ;
2014-10-04 13:21:18 +04:00
if ( ctx - > msg_dgm_ref = = NULL ) {
DEBUG ( 2 , ( " messaging_dgm_ref failed: %s \n " , strerror ( ret ) ) ) ;
2017-06-07 15:43:07 +03:00
status = map_nt_error_from_unix ( ret ) ;
2016-11-14 11:42:51 +03:00
goto done ;
2007-05-15 19:14:32 +04:00
}
2014-09-10 18:13:18 +04:00
talloc_set_destructor ( ctx , messaging_context_destructor ) ;
2007-06-10 21:02:09 +04:00
if ( lp_clustering ( ) ) {
2015-10-03 06:42:05 +03:00
ret = messaging_ctdbd_init ( ctx , ctx , & ctx - > remote ) ;
2007-06-10 21:02:09 +04:00
2015-10-03 06:42:05 +03:00
if ( ret ! = 0 ) {
2011-06-06 14:41:26 +04:00
DEBUG ( 2 , ( " messaging_ctdbd_init failed: %s \n " ,
2015-10-03 06:42:05 +03:00
strerror ( ret ) ) ) ;
2017-06-07 15:43:07 +03:00
status = map_nt_error_from_unix ( ret ) ;
2016-11-14 11:42:51 +03:00
goto done ;
2007-06-10 21:02:09 +04:00
}
}
2010-08-31 18:51:28 +04:00
ctx - > id . vnn = get_my_vnn ( ) ;
2007-06-10 21:02:09 +04:00
2016-11-14 11:42:51 +03:00
ctx - > names_db = server_id_db_init ( ctx ,
ctx - > id ,
lp_lock_directory ( ) ,
0 ,
TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST ) ;
2015-06-11 17:34:12 +03:00
if ( ctx - > names_db = = NULL ) {
2016-11-14 11:42:51 +03:00
DBG_DEBUG ( " server_id_db_init failed \n " ) ;
2017-06-07 15:43:07 +03:00
status = NT_STATUS_NO_MEMORY ;
2016-11-14 11:42:51 +03:00
goto done ;
2015-06-11 17:34:12 +03:00
}
2007-05-24 15:09:37 +04:00
messaging_register ( ctx , NULL , MSG_PING , ping_message ) ;
/* Register some debugging related messages */
register_msg_pool_usage ( ctx ) ;
register_dmalloc_msgs ( ctx ) ;
debug_register_msgs ( ctx ) ;
2016-04-18 17:40:22 +03:00
{
struct server_id_buf tmp ;
DBG_DEBUG ( " my id: %s \n " , server_id_str_buf ( ctx - > id , & tmp ) ) ;
}
2016-11-14 11:42:51 +03:00
* pmsg_ctx = talloc_steal ( mem_ctx , ctx ) ;
status = NT_STATUS_OK ;
done :
TALLOC_FREE ( frame ) ;
return status ;
}
struct messaging_context * messaging_init ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev )
{
struct messaging_context * ctx = NULL ;
NTSTATUS status ;
status = messaging_init_internal ( mem_ctx ,
ev ,
& ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NULL ;
}
2007-01-31 15:01:52 +03:00
return ctx ;
}
2016-11-14 11:49:20 +03:00
NTSTATUS messaging_init_client ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct messaging_context * * pmsg_ctx )
{
return messaging_init_internal ( mem_ctx ,
ev ,
pmsg_ctx ) ;
}
2010-07-04 19:57:57 +04:00
struct server_id messaging_server_id ( const struct messaging_context * msg_ctx )
{
return msg_ctx - > id ;
}
2007-06-10 21:02:09 +04:00
/*
* re - init after a fork
*/
2011-12-12 17:55:54 +04:00
NTSTATUS messaging_reinit ( struct messaging_context * msg_ctx )
2007-06-10 21:02:09 +04:00
{
2014-06-10 19:21:10 +04:00
int ret ;
2016-06-07 10:58:24 +03:00
char * lck_path ;
2009-01-14 14:25:31 +03:00
2014-10-04 13:21:18 +04:00
TALLOC_FREE ( msg_ctx - > msg_dgm_ref ) ;
2009-01-14 14:25:31 +03:00
2015-10-12 18:26:34 +03:00
msg_ctx - > id = ( struct server_id ) {
. pid = getpid ( ) , . vnn = msg_ctx - > id . vnn
} ;
2010-07-04 18:18:12 +04:00
2016-06-07 10:58:24 +03:00
lck_path = lock_path ( " msg.lock " ) ;
if ( lck_path = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2014-10-04 13:21:18 +04:00
msg_ctx - > msg_dgm_ref = messaging_dgm_ref (
2015-10-12 22:30:30 +03:00
msg_ctx , msg_ctx - > event_ctx , & msg_ctx - > id . unique_id ,
2016-06-07 10:58:24 +03:00
private_path ( " msg.sock " ) , lck_path ,
2014-10-04 13:21:18 +04:00
messaging_recv_cb , msg_ctx , & ret ) ;
if ( msg_ctx - > msg_dgm_ref = = NULL ) {
DEBUG ( 2 , ( " messaging_dgm_ref failed: %s \n " , strerror ( ret ) ) ) ;
2014-06-10 19:21:10 +04:00
return map_nt_error_from_unix ( ret ) ;
2009-01-14 14:25:31 +03:00
}
2007-06-10 21:02:09 +04:00
if ( lp_clustering ( ) ) {
2016-07-09 15:33:52 +03:00
ret = messaging_ctdbd_reinit ( msg_ctx , msg_ctx ,
msg_ctx - > remote ) ;
2007-06-10 21:02:09 +04:00
2015-10-03 06:42:05 +03:00
if ( ret ! = 0 ) {
2011-06-06 14:41:26 +04:00
DEBUG ( 1 , ( " messaging_ctdbd_init failed: %s \n " ,
2015-10-03 06:42:05 +03:00
strerror ( ret ) ) ) ;
return map_nt_error_from_unix ( ret ) ;
2007-06-10 21:02:09 +04:00
}
}
2014-10-17 16:09:03 +04:00
server_id_db_reinit ( msg_ctx - > names_db , msg_ctx - > id ) ;
2007-06-10 21:02:09 +04:00
return NT_STATUS_OK ;
}
2007-01-31 15:01:52 +03:00
/*
* Register a dispatch function for a particular message type . Allow multiple
* registrants
*/
2007-05-22 02:17:13 +04:00
NTSTATUS messaging_register ( struct messaging_context * msg_ctx ,
void * private_data ,
2007-01-31 15:01:52 +03:00
uint32_t msg_type ,
void ( * fn ) ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data ) )
{
struct messaging_callback * cb ;
2012-01-24 16:18:42 +04:00
DEBUG ( 5 , ( " Registering messaging pointer for type %u - "
" private_data=%p \n " ,
( unsigned ) msg_type , private_data ) ) ;
2007-05-22 02:17:13 +04:00
/*
* Only one callback per type
*/
for ( cb = msg_ctx - > callbacks ; cb ! = NULL ; cb = cb - > next ) {
2009-03-10 08:45:45 +03:00
/* we allow a second registration of the same message
type if it has a different private pointer . This is
needed in , for example , the internal notify code ,
which creates a new notify context for each tree
connect , and expects to receive messages to each of
them . */
if ( cb - > msg_type = = msg_type & & private_data = = cb - > private_data ) {
DEBUG ( 5 , ( " Overriding messaging pointer for type %u - private_data=%p \n " ,
( unsigned ) msg_type , private_data ) ) ;
2007-05-22 02:17:13 +04:00
cb - > fn = fn ;
cb - > private_data = private_data ;
return NT_STATUS_OK ;
}
}
if ( ! ( cb = talloc ( msg_ctx , struct messaging_callback ) ) ) {
2007-01-31 15:01:52 +03:00
return NT_STATUS_NO_MEMORY ;
}
cb - > msg_type = msg_type ;
cb - > fn = fn ;
cb - > private_data = private_data ;
2007-05-22 02:17:13 +04:00
DLIST_ADD ( msg_ctx - > callbacks , cb ) ;
2007-01-31 15:01:52 +03:00
return NT_STATUS_OK ;
}
/*
De - register the function for a particular message type .
*/
void messaging_deregister ( struct messaging_context * ctx , uint32_t msg_type ,
void * private_data )
{
struct messaging_callback * cb , * next ;
for ( cb = ctx - > callbacks ; cb ; cb = next ) {
next = cb - > next ;
if ( ( cb - > msg_type = = msg_type )
& & ( cb - > private_data = = private_data ) ) {
2009-03-10 08:45:45 +03:00
DEBUG ( 5 , ( " Deregistering messaging pointer for type %u - private_data=%p \n " ,
( unsigned ) msg_type , private_data ) ) ;
2007-01-31 15:01:52 +03:00
DLIST_REMOVE ( ctx - > callbacks , cb ) ;
TALLOC_FREE ( cb ) ;
}
}
}
2007-01-31 16:05:36 +03:00
/*
Send a message to a particular server
*/
2007-05-15 00:31:28 +04:00
NTSTATUS messaging_send ( struct messaging_context * msg_ctx ,
2007-05-24 15:09:37 +04:00
struct server_id server , uint32_t msg_type ,
const DATA_BLOB * data )
2007-01-31 16:05:36 +03:00
{
2016-06-23 14:24:02 +03:00
struct iovec iov = { 0 } ;
2014-01-08 19:13:11 +04:00
2016-06-23 14:24:02 +03:00
if ( data ! = NULL ) {
iov . iov_base = data - > data ;
iov . iov_len = data - > length ;
} ;
2014-01-08 19:13:11 +04:00
2014-05-17 17:19:18 +04:00
return messaging_send_iov ( msg_ctx , server , msg_type , & iov , 1 , NULL , 0 ) ;
2007-01-31 16:05:36 +03:00
}
2007-01-31 15:01:52 +03:00
2007-05-15 00:31:28 +04:00
NTSTATUS messaging_send_buf ( struct messaging_context * msg_ctx ,
struct server_id server , uint32_t msg_type ,
2013-02-18 18:46:52 +04:00
const uint8_t * buf , size_t len )
2007-05-15 00:31:28 +04:00
{
DATA_BLOB blob = data_blob_const ( buf , len ) ;
return messaging_send ( msg_ctx , server , msg_type , & blob ) ;
}
2016-07-25 17:31:18 +03:00
static int messaging_post_self ( struct messaging_context * msg_ctx ,
struct server_id src , struct server_id dst ,
uint32_t msg_type ,
const struct iovec * iov , int iovlen ,
const int * fds , size_t num_fds )
{
2017-06-22 09:54:56 +03:00
struct messaging_rec * rec ;
bool ok ;
2016-07-25 17:31:18 +03:00
2017-06-22 09:54:56 +03:00
rec = messaging_rec_create (
msg_ctx , src , dst , msg_type , iov , iovlen , fds , num_fds ) ;
if ( rec = = NULL ) {
2016-07-25 17:31:18 +03:00
return ENOMEM ;
}
2017-06-22 09:54:56 +03:00
ok = messaging_alert_event_contexts ( msg_ctx ) ;
if ( ! ok ) {
TALLOC_FREE ( rec ) ;
return ENOMEM ;
2016-07-25 17:31:18 +03:00
}
2017-06-22 09:54:56 +03:00
DLIST_ADD_END ( msg_ctx - > posted_msgs , rec ) ;
2016-07-25 17:31:18 +03:00
2017-06-22 09:54:56 +03:00
return 0 ;
2016-07-25 17:31:18 +03:00
}
2015-10-03 06:42:05 +03:00
int messaging_send_iov_from ( struct messaging_context * msg_ctx ,
struct server_id src , struct server_id dst ,
uint32_t msg_type ,
const struct iovec * iov , int iovlen ,
const int * fds , size_t num_fds )
2014-02-25 16:15:58 +04:00
{
2014-06-04 18:36:57 +04:00
int ret ;
2015-02-11 18:28:55 +03:00
uint8_t hdr [ MESSAGE_HDR_LENGTH ] ;
2014-07-27 14:29:26 +04:00
struct iovec iov2 [ iovlen + 1 ] ;
2014-06-04 18:36:57 +04:00
2014-11-12 18:42:59 +03:00
if ( server_id_is_disconnected ( & dst ) ) {
2015-10-03 06:42:05 +03:00
return EINVAL ;
2014-05-13 13:55:37 +04:00
}
2014-02-25 16:15:58 +04:00
2014-05-17 17:19:18 +04:00
if ( num_fds > INT8_MAX ) {
2015-10-03 06:42:05 +03:00
return EINVAL ;
2014-05-17 17:19:18 +04:00
}
2016-04-26 17:24:33 +03:00
if ( dst . vnn ! = msg_ctx - > id . vnn ) {
2014-05-17 17:19:18 +04:00
if ( num_fds > 0 ) {
2015-10-03 06:42:05 +03:00
return ENOSYS ;
2014-05-17 17:19:18 +04:00
}
2014-11-12 18:42:59 +03:00
ret = msg_ctx - > remote - > send_fn ( src , dst ,
2014-06-04 18:36:57 +04:00
msg_type , iov , iovlen ,
2014-05-17 17:16:02 +04:00
NULL , 0 ,
2014-06-04 18:36:57 +04:00
msg_ctx - > remote ) ;
2015-10-03 06:42:05 +03:00
return ret ;
2014-02-25 16:15:58 +04:00
}
2016-07-25 17:31:18 +03:00
if ( server_id_equal ( & dst , & msg_ctx - > id ) ) {
ret = messaging_post_self ( msg_ctx , src , dst , msg_type ,
iov , iovlen , fds , num_fds ) ;
return ret ;
}
2015-02-11 18:28:55 +03:00
message_hdr_put ( hdr , msg_type , src , dst ) ;
iov2 [ 0 ] = ( struct iovec ) { . iov_base = hdr , . iov_len = sizeof ( hdr ) } ;
2014-07-27 14:29:26 +04:00
memcpy ( & iov2 [ 1 ] , iov , iovlen * sizeof ( * iov ) ) ;
2014-11-12 18:42:59 +03:00
ret = messaging_dgm_send ( dst . pid , iov2 , iovlen + 1 , fds , num_fds ) ;
2016-09-01 15:08:55 +03:00
if ( ret = = EACCES ) {
become_root ( ) ;
ret = messaging_dgm_send ( dst . pid , iov2 , iovlen + 1 ,
fds , num_fds ) ;
unbecome_root ( ) ;
2017-01-10 15:30:54 +03:00
}
if ( ret = = ECONNREFUSED ) {
/*
* Linux returns this when a socket exists in the file
* system without a listening process . This is not
* documented in susv4 or the linux manpages , but it ' s
* easily testable . For the higher levels this is the
* same as " destination does not exist "
*/
ret = ENOENT ;
2016-09-01 15:08:55 +03:00
}
2014-07-17 15:34:24 +04:00
2015-10-03 06:42:05 +03:00
return ret ;
2014-02-25 16:15:58 +04:00
}
2014-11-12 18:42:59 +03:00
NTSTATUS messaging_send_iov ( struct messaging_context * msg_ctx ,
struct server_id dst , uint32_t msg_type ,
const struct iovec * iov , int iovlen ,
const int * fds , size_t num_fds )
{
2015-10-03 06:42:05 +03:00
int ret ;
ret = messaging_send_iov_from ( msg_ctx , msg_ctx - > id , dst , msg_type ,
iov , iovlen , fds , num_fds ) ;
if ( ret ! = 0 ) {
return map_nt_error_from_unix ( ret ) ;
}
return NT_STATUS_OK ;
2014-11-12 18:42:59 +03:00
}
2013-12-30 14:26:52 +04:00
static struct messaging_rec * messaging_rec_dup ( TALLOC_CTX * mem_ctx ,
struct messaging_rec * rec )
{
struct messaging_rec * result ;
2014-06-24 09:39:05 +04:00
size_t fds_size = sizeof ( int64_t ) * rec - > num_fds ;
2016-07-22 16:59:32 +03:00
size_t payload_len ;
payload_len = rec - > buf . length + fds_size ;
if ( payload_len < rec - > buf . length ) {
/* overflow */
return NULL ;
}
2013-12-30 14:26:52 +04:00
2014-06-24 09:39:05 +04:00
result = talloc_pooled_object ( mem_ctx , struct messaging_rec , 2 ,
2016-07-22 16:59:32 +03:00
payload_len ) ;
2013-12-30 14:26:52 +04:00
if ( result = = NULL ) {
return NULL ;
}
* result = * rec ;
/* Doesn't fail, see talloc_pooled_object */
result - > buf . data = talloc_memdup ( result , rec - > buf . data ,
rec - > buf . length ) ;
2014-06-24 09:39:05 +04:00
result - > fds = NULL ;
if ( result - > num_fds > 0 ) {
2014-12-13 11:52:42 +03:00
result - > fds = talloc_memdup ( result , rec - > fds , fds_size ) ;
2014-06-24 09:39:05 +04:00
}
2013-12-30 14:26:52 +04:00
return result ;
}
2014-04-24 13:05:53 +04:00
struct messaging_filtered_read_state {
2013-12-30 14:26:52 +04:00
struct tevent_context * ev ;
struct messaging_context * msg_ctx ;
2016-10-01 07:53:44 +03:00
struct messaging_dgm_fde * fde ;
2014-04-24 13:05:53 +04:00
bool ( * filter ) ( struct messaging_rec * rec , void * private_data ) ;
void * private_data ;
2013-12-30 14:26:52 +04:00
struct messaging_rec * rec ;
} ;
2014-04-24 13:05:53 +04:00
static void messaging_filtered_read_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state ) ;
2013-12-30 14:26:52 +04:00
2014-04-24 13:05:53 +04:00
struct tevent_req * messaging_filtered_read_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
struct messaging_context * msg_ctx ,
bool ( * filter ) ( struct messaging_rec * rec , void * private_data ) ,
void * private_data )
2013-12-30 14:26:52 +04:00
{
struct tevent_req * req ;
2014-04-24 13:05:53 +04:00
struct messaging_filtered_read_state * state ;
2014-04-29 16:14:24 +04:00
size_t new_waiters_len ;
2017-06-22 09:34:34 +03:00
bool ok ;
2013-12-30 14:26:52 +04:00
req = tevent_req_create ( mem_ctx , & state ,
2014-04-24 13:05:53 +04:00
struct messaging_filtered_read_state ) ;
2013-12-30 14:26:52 +04:00
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > msg_ctx = msg_ctx ;
2014-04-24 13:05:53 +04:00
state - > filter = filter ;
state - > private_data = private_data ;
2013-12-30 14:26:52 +04:00
2014-05-06 11:39:01 +04:00
/*
* We have to defer the callback here , as we might be called from
* within a different tevent_context than state - > ev
*/
tevent_req_defer_callback ( req , state - > ev ) ;
2016-10-01 07:53:44 +03:00
state - > fde = messaging_dgm_register_tevent_context ( state , ev ) ;
if ( tevent_req_nomem ( state - > fde , req ) ) {
2014-05-06 11:39:01 +04:00
return tevent_req_post ( req , ev ) ;
}
2014-05-02 13:20:40 +04:00
/*
* We add ourselves to the " new_waiters " array , not the " waiters "
* array . If we are called from within messaging_read_done ,
* messaging_dispatch_rec will be in an active for - loop on
* " waiters " . We must be careful not to mess with this array , because
* it could mean that a single event is being delivered twice .
*/
2014-04-29 16:14:24 +04:00
new_waiters_len = talloc_array_length ( msg_ctx - > new_waiters ) ;
2013-12-30 14:26:52 +04:00
2014-04-29 16:14:24 +04:00
if ( new_waiters_len = = msg_ctx - > num_new_waiters ) {
2013-12-30 14:26:52 +04:00
struct tevent_req * * tmp ;
2014-04-29 16:14:24 +04:00
tmp = talloc_realloc ( msg_ctx , msg_ctx - > new_waiters ,
struct tevent_req * , new_waiters_len + 1 ) ;
2013-12-30 14:26:52 +04:00
if ( tevent_req_nomem ( tmp , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2014-04-29 16:14:24 +04:00
msg_ctx - > new_waiters = tmp ;
2013-12-30 14:26:52 +04:00
}
2014-04-29 16:14:24 +04:00
msg_ctx - > new_waiters [ msg_ctx - > num_new_waiters ] = req ;
msg_ctx - > num_new_waiters + = 1 ;
2014-04-24 13:05:53 +04:00
tevent_req_set_cleanup_fn ( req , messaging_filtered_read_cleanup ) ;
2013-12-30 14:26:52 +04:00
2017-06-22 09:34:34 +03:00
ok = messaging_register_event_context ( msg_ctx , ev ) ;
if ( ! ok ) {
tevent_req_oom ( req ) ;
return tevent_req_post ( req , ev ) ;
}
2013-12-30 14:26:52 +04:00
return req ;
}
2014-04-24 13:05:53 +04:00
static void messaging_filtered_read_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
2013-12-30 14:26:52 +04:00
{
2014-04-24 13:05:53 +04:00
struct messaging_filtered_read_state * state = tevent_req_data (
req , struct messaging_filtered_read_state ) ;
2013-12-30 14:26:52 +04:00
struct messaging_context * msg_ctx = state - > msg_ctx ;
2017-06-17 10:46:43 +03:00
size_t i ;
2017-06-22 09:34:34 +03:00
bool ok ;
2013-12-30 14:26:52 +04:00
tevent_req_set_cleanup_fn ( req , NULL ) ;
2016-10-01 07:53:44 +03:00
TALLOC_FREE ( state - > fde ) ;
2014-05-06 11:39:01 +04:00
2017-06-22 09:34:34 +03:00
ok = messaging_deregister_event_context ( msg_ctx , state - > ev ) ;
if ( ! ok ) {
abort ( ) ;
}
2014-05-02 13:20:40 +04:00
/*
* Just set the [ new_ ] waiters entry to NULL , be careful not to mess
* with the other " waiters " array contents . We are often called from
* within " messaging_dispatch_rec " , which loops over
* " waiters " . Messing with the " waiters " array will mess up that
* for - loop .
*/
2013-12-30 14:26:52 +04:00
for ( i = 0 ; i < msg_ctx - > num_waiters ; i + + ) {
2014-04-29 16:14:24 +04:00
if ( msg_ctx - > waiters [ i ] = = req ) {
msg_ctx - > waiters [ i ] = NULL ;
return ;
}
}
for ( i = 0 ; i < msg_ctx - > num_new_waiters ; i + + ) {
if ( msg_ctx - > new_waiters [ i ] = = req ) {
msg_ctx - > new_waiters [ i ] = NULL ;
2013-12-30 14:26:52 +04:00
return ;
}
}
}
2014-04-24 13:05:53 +04:00
static void messaging_filtered_read_done ( struct tevent_req * req ,
struct messaging_rec * rec )
2013-12-30 14:26:52 +04:00
{
2014-04-24 13:05:53 +04:00
struct messaging_filtered_read_state * state = tevent_req_data (
req , struct messaging_filtered_read_state ) ;
2013-12-30 14:26:52 +04:00
state - > rec = messaging_rec_dup ( state , rec ) ;
if ( tevent_req_nomem ( state - > rec , req ) ) {
return ;
}
tevent_req_done ( req ) ;
}
2014-04-24 13:05:53 +04:00
int messaging_filtered_read_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct messaging_rec * * presult )
{
struct messaging_filtered_read_state * state = tevent_req_data (
req , struct messaging_filtered_read_state ) ;
int err ;
if ( tevent_req_is_unix_error ( req , & err ) ) {
tevent_req_received ( req ) ;
return err ;
}
2016-09-26 18:16:15 +03:00
if ( presult ! = NULL ) {
* presult = talloc_move ( mem_ctx , & state - > rec ) ;
}
2014-04-24 13:05:53 +04:00
return 0 ;
}
struct messaging_read_state {
uint32_t msg_type ;
struct messaging_rec * rec ;
} ;
static bool messaging_read_filter ( struct messaging_rec * rec ,
void * private_data ) ;
static void messaging_read_done ( struct tevent_req * subreq ) ;
struct tevent_req * messaging_read_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct messaging_context * msg ,
uint32_t msg_type )
{
struct tevent_req * req , * subreq ;
struct messaging_read_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct messaging_read_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > msg_type = msg_type ;
subreq = messaging_filtered_read_send ( state , ev , msg ,
messaging_read_filter , state ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , messaging_read_done , req ) ;
return req ;
}
static bool messaging_read_filter ( struct messaging_rec * rec ,
void * private_data )
{
struct messaging_read_state * state = talloc_get_type_abort (
private_data , struct messaging_read_state ) ;
2014-06-24 09:39:05 +04:00
if ( rec - > num_fds ! = 0 ) {
return false ;
}
2014-04-24 13:05:53 +04:00
return rec - > msg_type = = state - > msg_type ;
}
static void messaging_read_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct messaging_read_state * state = tevent_req_data (
req , struct messaging_read_state ) ;
int ret ;
ret = messaging_filtered_read_recv ( subreq , state , & state - > rec ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_error ( req , ret ) ) {
return ;
}
tevent_req_done ( req ) ;
}
2013-12-30 14:26:52 +04:00
int messaging_read_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
struct messaging_rec * * presult )
{
struct messaging_read_state * state = tevent_req_data (
req , struct messaging_read_state ) ;
int err ;
if ( tevent_req_is_unix_error ( req , & err ) ) {
return err ;
}
2014-04-29 16:12:26 +04:00
if ( presult ! = NULL ) {
* presult = talloc_move ( mem_ctx , & state - > rec ) ;
}
2013-12-30 14:26:52 +04:00
return 0 ;
}
2014-04-29 16:14:24 +04:00
static bool messaging_append_new_waiters ( struct messaging_context * msg_ctx )
{
if ( msg_ctx - > num_new_waiters = = 0 ) {
return true ;
}
if ( talloc_array_length ( msg_ctx - > waiters ) <
( msg_ctx - > num_waiters + msg_ctx - > num_new_waiters ) ) {
struct tevent_req * * tmp ;
tmp = talloc_realloc (
msg_ctx , msg_ctx - > waiters , struct tevent_req * ,
msg_ctx - > num_waiters + msg_ctx - > num_new_waiters ) ;
if ( tmp = = NULL ) {
DEBUG ( 1 , ( " %s: talloc failed \n " , __func__ ) ) ;
return false ;
}
msg_ctx - > waiters = tmp ;
}
memcpy ( & msg_ctx - > waiters [ msg_ctx - > num_waiters ] , msg_ctx - > new_waiters ,
sizeof ( struct tevent_req * ) * msg_ctx - > num_new_waiters ) ;
msg_ctx - > num_waiters + = msg_ctx - > num_new_waiters ;
msg_ctx - > num_new_waiters = 0 ;
return true ;
}
2017-06-17 09:48:16 +03:00
static bool messaging_dispatch_classic ( struct messaging_context * msg_ctx ,
2016-09-24 05:35:10 +03:00
struct messaging_rec * rec )
2007-05-24 18:47:24 +04:00
{
struct messaging_callback * cb , * next ;
for ( cb = msg_ctx - > callbacks ; cb ! = NULL ; cb = next ) {
2016-09-24 05:35:10 +03:00
size_t j ;
2007-05-24 18:47:24 +04:00
next = cb - > next ;
2014-05-07 11:44:57 +04:00
if ( cb - > msg_type ! = rec - > msg_type ) {
continue ;
}
2014-06-24 09:39:05 +04:00
/*
* the old style callbacks don ' t support fd passing
*/
for ( j = 0 ; j < rec - > num_fds ; j + + ) {
int fd = rec - > fds [ j ] ;
close ( fd ) ;
}
rec - > num_fds = 0 ;
rec - > fds = NULL ;
2014-11-13 13:38:40 +03:00
cb - > fn ( msg_ctx , cb - > private_data , rec - > msg_type ,
rec - > src , & rec - > buf ) ;
2017-06-17 09:48:16 +03:00
return true ;
2007-05-24 18:47:24 +04:00
}
2017-06-17 09:48:16 +03:00
return false ;
2016-09-24 05:35:10 +03:00
}
2017-06-17 16:43:14 +03:00
static bool messaging_dispatch_waiters ( struct messaging_context * msg_ctx ,
struct tevent_context * ev ,
struct messaging_rec * rec )
2016-09-24 05:35:10 +03:00
{
2017-06-17 10:46:43 +03:00
size_t i ;
2013-12-30 14:26:52 +04:00
2014-04-29 16:14:24 +04:00
if ( ! messaging_append_new_waiters ( msg_ctx ) ) {
2017-06-17 16:43:14 +03:00
return false ;
2014-04-29 16:14:24 +04:00
}
i = 0 ;
while ( i < msg_ctx - > num_waiters ) {
struct tevent_req * req ;
2014-04-24 13:05:53 +04:00
struct messaging_filtered_read_state * state ;
2014-04-29 16:14:24 +04:00
req = msg_ctx - > waiters [ i ] ;
if ( req = = NULL ) {
/*
* This got cleaned up . In the meantime ,
* move everything down one . We need
* to keep the order of waiters , as
* other code may depend on this .
*/
2014-05-14 11:31:20 +04:00
if ( i < msg_ctx - > num_waiters - 1 ) {
2014-04-29 16:14:24 +04:00
memmove ( & msg_ctx - > waiters [ i ] ,
& msg_ctx - > waiters [ i + 1 ] ,
sizeof ( struct tevent_req * ) *
2014-05-02 13:12:52 +04:00
( msg_ctx - > num_waiters - i - 1 ) ) ;
2014-04-29 16:14:24 +04:00
}
msg_ctx - > num_waiters - = 1 ;
continue ;
}
2013-12-30 14:26:52 +04:00
2014-04-24 13:05:53 +04:00
state = tevent_req_data (
req , struct messaging_filtered_read_state ) ;
2016-09-24 05:35:10 +03:00
if ( ( ev = = state - > ev ) & &
state - > filter ( rec , state - > private_data ) ) {
2014-04-24 13:05:53 +04:00
messaging_filtered_read_done ( req , rec ) ;
2017-06-17 16:43:14 +03:00
return true ;
2013-12-30 14:26:52 +04:00
}
2014-04-29 16:14:24 +04:00
i + = 1 ;
2013-12-30 14:26:52 +04:00
}
2014-06-24 09:39:05 +04:00
2017-06-17 16:43:14 +03:00
return false ;
}
/*
Dispatch one messaging_rec
*/
static void messaging_dispatch_rec ( struct messaging_context * msg_ctx ,
struct tevent_context * ev ,
struct messaging_rec * rec )
{
bool consumed ;
size_t i ;
if ( ev = = msg_ctx - > event_ctx ) {
consumed = messaging_dispatch_classic ( msg_ctx , rec ) ;
if ( consumed ) {
return ;
}
}
consumed = messaging_dispatch_waiters ( msg_ctx , ev , rec ) ;
if ( consumed ) {
return ;
}
2016-09-24 05:35:10 +03:00
if ( ev ! = msg_ctx - > event_ctx ) {
struct iovec iov ;
int fds [ rec - > num_fds ] ;
int ret ;
/*
* We ' ve been listening on a nested event
* context . Messages need to be handled in the main
* event context , so post to ourselves
*/
iov . iov_base = rec - > buf . data ;
iov . iov_len = rec - > buf . length ;
for ( i = 0 ; i < rec - > num_fds ; i + + ) {
fds [ i ] = rec - > fds [ i ] ;
}
ret = messaging_post_self (
msg_ctx , rec - > src , rec - > dest , rec - > msg_type ,
& iov , 1 , fds , rec - > num_fds ) ;
if ( ret = = 0 ) {
return ;
}
}
2014-06-24 09:39:05 +04:00
/*
* If the fd - array isn ' t used , just close it .
*/
2017-06-17 10:46:43 +03:00
for ( i = 0 ; i < rec - > num_fds ; i + + ) {
int fd = rec - > fds [ i ] ;
2014-06-24 09:39:05 +04:00
close ( fd ) ;
}
rec - > num_fds = 0 ;
rec - > fds = NULL ;
2007-05-24 18:47:24 +04:00
}
2014-04-11 15:08:56 +04:00
static int mess_parent_dgm_cleanup ( void * private_data ) ;
static void mess_parent_dgm_cleanup_done ( struct tevent_req * req ) ;
bool messaging_parent_dgm_cleanup_init ( struct messaging_context * msg )
{
struct tevent_req * req ;
req = background_job_send (
msg , msg - > event_ctx , msg , NULL , 0 ,
2014-05-02 13:12:52 +04:00
lp_parm_int ( - 1 , " messaging " , " messaging dgm cleanup interval " ,
60 * 15 ) ,
2014-04-11 15:08:56 +04:00
mess_parent_dgm_cleanup , msg ) ;
if ( req = = NULL ) {
return false ;
}
tevent_req_set_callback ( req , mess_parent_dgm_cleanup_done , msg ) ;
return true ;
}
static int mess_parent_dgm_cleanup ( void * private_data )
{
2014-06-04 18:47:05 +04:00
int ret ;
2014-04-11 15:08:56 +04:00
2014-09-10 18:13:18 +04:00
ret = messaging_dgm_wipe ( ) ;
2014-06-04 18:47:05 +04:00
DEBUG ( 10 , ( " messaging_dgm_wipe returned %s \n " ,
ret ? strerror ( ret ) : " ok " ) ) ;
2014-05-02 13:12:52 +04:00
return lp_parm_int ( - 1 , " messaging " , " messaging dgm cleanup interval " ,
60 * 15 ) ;
2014-04-11 15:08:56 +04:00
}
static void mess_parent_dgm_cleanup_done ( struct tevent_req * req )
{
struct messaging_context * msg = tevent_req_callback_data (
req , struct messaging_context ) ;
NTSTATUS status ;
status = background_job_recv ( req ) ;
TALLOC_FREE ( req ) ;
2014-05-02 13:12:52 +04:00
DEBUG ( 1 , ( " messaging dgm cleanup job ended with %s \n " ,
nt_errstr ( status ) ) ) ;
2014-04-11 15:08:56 +04:00
req = background_job_send (
msg , msg - > event_ctx , msg , NULL , 0 ,
2014-05-02 13:12:52 +04:00
lp_parm_int ( - 1 , " messaging " , " messaging dgm cleanup interval " ,
60 * 15 ) ,
2014-04-11 15:08:56 +04:00
mess_parent_dgm_cleanup , msg ) ;
if ( req = = NULL ) {
DEBUG ( 1 , ( " background_job_send failed \n " ) ) ;
2015-03-26 12:21:20 +03:00
return ;
2014-04-11 15:08:56 +04:00
}
tevent_req_set_callback ( req , mess_parent_dgm_cleanup_done , msg ) ;
}
2014-07-17 15:01:00 +04:00
int messaging_cleanup ( struct messaging_context * msg_ctx , pid_t pid )
{
int ret ;
if ( pid = = 0 ) {
2014-09-10 18:13:18 +04:00
ret = messaging_dgm_wipe ( ) ;
2014-07-17 15:01:00 +04:00
} else {
2014-09-10 18:13:18 +04:00
ret = messaging_dgm_cleanup ( pid ) ;
2014-07-17 15:01:00 +04:00
}
return ret ;
}
2014-05-29 18:44:32 +04:00
struct tevent_context * messaging_tevent_context (
struct messaging_context * msg_ctx )
{
return msg_ctx - > event_ctx ;
}
2014-10-17 16:09:03 +04:00
struct server_id_db * messaging_names_db ( struct messaging_context * msg_ctx )
{
return msg_ctx - > names_db ;
}
2002-03-09 12:48:35 +03:00
/** @} **/