2004-10-17 14:04:49 +04:00
/*
Unix SMB / CIFS implementation .
Samba internal messaging functions
Copyright ( C ) Andrew Tridgell 2004
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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2004-10-17 14:04:49 +04:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-10-17 14:04:49 +04:00
*/
# include "includes.h"
2005-02-03 14:56:03 +03:00
# include "lib/events/events.h"
2005-02-10 08:09:35 +03:00
# include "system/filesys.h"
2006-01-03 18:40:05 +03:00
# include "messaging/messaging.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/dlinklist.h"
2005-02-10 09:59:29 +03:00
# include "lib/socket/socket.h"
2005-06-05 10:53:07 +04:00
# include "librpc/gen_ndr/ndr_irpc.h"
# include "lib/messaging/irpc.h"
2011-05-04 04:28:15 +04:00
# include "lib/util/tdb_wrap.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/unix_privs.h"
2006-03-18 18:42:57 +03:00
# include "librpc/rpc/dcerpc.h"
2011-06-20 13:10:25 +04:00
# include "../lib/tdb_compat/tdb_compat.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/util_tdb.h"
2007-01-10 13:52:09 +03:00
# include "cluster/cluster.h"
2010-08-30 15:44:01 +04:00
# include "../lib/util/tevent_ntstatus.h"
2004-10-17 14:04:49 +04:00
/* change the message version with any incompatible changes in the protocol */
2011-05-03 04:40:33 +04:00
# define IMESSAGING_VERSION 1
2004-10-17 14:04:49 +04:00
2010-09-03 18:05:38 +04:00
/*
a pending irpc call
*/
struct irpc_request {
2011-05-03 04:40:33 +04:00
struct imessaging_context * msg_ctx ;
2010-09-03 18:05:38 +04:00
int callid ;
struct {
void ( * handler ) ( struct irpc_request * irpc , struct irpc_message * m ) ;
void * private_data ;
} incoming ;
} ;
2011-05-03 04:40:33 +04:00
struct imessaging_context {
2007-01-10 13:52:09 +03:00
struct server_id server_id ;
2004-10-17 14:04:49 +04:00
struct socket_context * sock ;
2005-06-05 11:37:27 +04:00
const char * base_path ;
2005-05-01 22:49:07 +04:00
const char * path ;
2006-04-12 10:08:24 +04:00
struct dispatch_fn * * dispatch ;
uint32_t num_types ;
struct idr_context * dispatch_tree ;
2011-05-03 04:40:33 +04:00
struct imessaging_rec * pending ;
struct imessaging_rec * retry_queue ;
2005-06-05 10:53:07 +04:00
struct irpc_list * irpc ;
struct idr_context * idr ;
2005-07-10 08:54:21 +04:00
const char * * names ;
2005-07-19 13:28:13 +04:00
struct timeval start_time ;
2008-12-29 22:24:57 +03:00
struct tevent_timer * retry_te ;
2004-10-17 14:04:49 +04:00
struct {
2008-12-29 22:24:57 +03:00
struct tevent_context * ev ;
struct tevent_fd * fde ;
2004-10-17 14:04:49 +04:00
} event ;
} ;
2006-04-12 10:08:24 +04:00
/* we have a linked list of dispatch handlers for each msg_type that
this messaging server can deal with */
2004-10-17 14:04:49 +04:00
struct dispatch_fn {
struct dispatch_fn * next , * prev ;
uint32_t msg_type ;
2009-02-01 01:57:02 +03:00
void * private_data ;
2006-04-12 10:08:24 +04:00
msg_callback_t fn ;
2004-10-17 14:04:49 +04:00
} ;
/* an individual message */
2011-05-03 04:40:33 +04:00
struct imessaging_rec {
struct imessaging_rec * next , * prev ;
struct imessaging_context * msg ;
2004-10-17 14:04:49 +04:00
const char * path ;
2011-05-03 04:40:33 +04:00
struct imessaging_header {
2004-10-17 14:04:49 +04:00
uint32_t version ;
uint32_t msg_type ;
2007-01-10 13:52:09 +03:00
struct server_id from ;
struct server_id to ;
2004-10-17 14:04:49 +04:00
uint32_t length ;
2005-06-03 10:04:34 +04:00
} * header ;
2004-10-17 14:04:49 +04:00
2005-06-03 10:04:34 +04:00
DATA_BLOB packet ;
2007-05-26 12:47:27 +04:00
uint32_t retries ;
2004-10-17 14:04:49 +04:00
} ;
2005-06-03 08:21:25 +04:00
2011-05-03 04:40:33 +04:00
static void irpc_handler ( struct imessaging_context * , void * ,
2007-01-10 13:52:09 +03:00
uint32_t , struct server_id , DATA_BLOB * ) ;
2005-06-05 10:53:07 +04:00
2004-10-17 14:04:49 +04:00
/*
A useful function for testing the message system .
*/
2011-05-03 04:40:33 +04:00
static void ping_message ( struct imessaging_context * msg , void * private_data ,
2007-01-10 13:52:09 +03:00
uint32_t msg_type , struct server_id src , DATA_BLOB * data )
2004-10-17 14:04:49 +04:00
{
2011-06-08 08:05:55 +04:00
char * task_id = server_id_str ( NULL , & src ) ;
2011-05-02 04:05:46 +04:00
DEBUG ( 1 , ( " INFO: Received PING message from server %s [%.*s] \n " ,
task_id , ( int ) data - > length ,
2005-07-17 13:20:52 +04:00
data - > data ? ( const char * ) data - > data : " " ) ) ;
2011-05-02 04:05:46 +04:00
talloc_free ( task_id ) ;
2011-05-03 04:40:33 +04:00
imessaging_send ( msg , src , MSG_PONG , data ) ;
2004-10-17 14:04:49 +04:00
}
2005-07-19 13:28:13 +04:00
/*
return uptime of messaging server via irpc
*/
static NTSTATUS irpc_uptime ( struct irpc_message * msg ,
struct irpc_uptime * r )
{
2011-05-03 04:40:33 +04:00
struct imessaging_context * ctx = talloc_get_type ( msg - > private_data , struct imessaging_context ) ;
2005-07-19 13:28:13 +04:00
* r - > out . start_time = timeval_to_nttime ( & ctx - > start_time ) ;
return NT_STATUS_OK ;
}
2004-10-17 14:04:49 +04:00
/*
return the path to a messaging socket
*/
2011-05-03 04:40:33 +04:00
static char * imessaging_path ( struct imessaging_context * msg , struct server_id server_id )
2004-10-17 14:04:49 +04:00
{
2010-01-09 01:04:18 +03:00
TALLOC_CTX * tmp_ctx = talloc_new ( msg ) ;
2011-06-08 08:05:55 +04:00
const char * id = server_id_str ( tmp_ctx , & server_id ) ;
2010-01-09 01:04:18 +03:00
char * s ;
if ( id = = NULL ) {
return NULL ;
}
s = talloc_asprintf ( msg , " %s/msg.%s " , msg - > base_path , id ) ;
talloc_steal ( s , tmp_ctx ) ;
return s ;
2004-10-17 14:04:49 +04:00
}
/*
dispatch a fully received message
2006-01-09 01:58:59 +03:00
note that this deliberately can match more than one message handler
per message . That allows a single messasging context to register
( for example ) a debug handler for more than one piece of code
2004-10-17 14:04:49 +04:00
*/
2011-05-03 04:40:33 +04:00
static void imessaging_dispatch ( struct imessaging_context * msg , struct imessaging_rec * rec )
2004-10-17 14:04:49 +04:00
{
2004-10-18 15:47:13 +04:00
struct dispatch_fn * d , * next ;
2006-04-12 10:08:24 +04:00
/* temporary IDs use an idtree, the rest use a array of pointers */
if ( rec - > header - > msg_type > = MSG_TMP_BASE ) {
2007-09-09 23:34:30 +04:00
d = ( struct dispatch_fn * ) idr_find ( msg - > dispatch_tree ,
rec - > header - > msg_type ) ;
2006-04-12 10:08:24 +04:00
} else if ( rec - > header - > msg_type < msg - > num_types ) {
d = msg - > dispatch [ rec - > header - > msg_type ] ;
} else {
d = NULL ;
}
for ( ; d ; d = next ) {
DATA_BLOB data ;
2004-10-18 15:47:13 +04:00
next = d - > next ;
2006-04-12 10:08:24 +04:00
data . data = rec - > packet . data + sizeof ( * rec - > header ) ;
data . length = rec - > header - > length ;
2009-02-01 01:57:02 +03:00
d - > fn ( msg , d - > private_data , d - > msg_type , rec - > header - > from , & data ) ;
2004-10-17 14:04:49 +04:00
}
2005-06-03 10:04:34 +04:00
rec - > header - > length = 0 ;
2004-10-17 14:04:49 +04:00
}
2007-02-08 03:58:17 +03:00
/*
handler for messages that arrive from other nodes in the cluster
*/
2011-05-03 04:40:33 +04:00
static void cluster_message_handler ( struct imessaging_context * msg , DATA_BLOB packet )
2007-02-08 03:58:17 +03:00
{
2011-05-03 04:40:33 +04:00
struct imessaging_rec * rec ;
2007-02-08 03:58:17 +03:00
2011-05-03 04:40:33 +04:00
rec = talloc ( msg , struct imessaging_rec ) ;
2007-02-08 03:58:17 +03:00
if ( rec = = NULL ) {
2011-05-03 04:40:33 +04:00
smb_panic ( " Unable to allocate imessaging_rec " ) ;
2007-02-08 03:58:17 +03:00
}
rec - > msg = msg ;
rec - > path = msg - > path ;
2011-05-03 04:40:33 +04:00
rec - > header = ( struct imessaging_header * ) packet . data ;
2007-02-08 03:58:17 +03:00
rec - > packet = packet ;
2007-05-26 12:47:27 +04:00
rec - > retries = 0 ;
2007-02-08 03:58:17 +03:00
if ( packet . length ! = sizeof ( * rec - > header ) + rec - > header - > length ) {
DEBUG ( 0 , ( " messaging: bad message header size %d should be %d \n " ,
rec - > header - > length , ( int ) ( packet . length - sizeof ( * rec - > header ) ) ) ) ;
talloc_free ( rec ) ;
return ;
}
2011-05-03 04:40:33 +04:00
imessaging_dispatch ( msg , rec ) ;
2007-02-08 03:58:17 +03:00
talloc_free ( rec ) ;
}
2004-10-17 14:04:49 +04:00
/*
2005-06-03 08:21:25 +04:00
try to send the message
2004-10-17 14:04:49 +04:00
*/
2011-05-03 04:40:33 +04:00
static NTSTATUS try_send ( struct imessaging_rec * rec )
2005-06-03 08:21:25 +04:00
{
2011-05-03 04:40:33 +04:00
struct imessaging_context * msg = rec - > msg ;
2005-06-03 08:21:25 +04:00
size_t nsent ;
void * priv ;
NTSTATUS status ;
2006-01-10 01:12:53 +03:00
struct socket_address * path ;
/* rec->path is the path of the *other* socket, where we want
* this to end up */
path = socket_address_from_strings ( msg , msg - > sock - > backend_name ,
rec - > path , 0 ) ;
if ( ! path ) {
return NT_STATUS_NO_MEMORY ;
}
2005-06-03 08:21:25 +04:00
/* we send with privileges so messages work from any context */
priv = root_privileges ( ) ;
2006-04-30 09:58:31 +04:00
status = socket_sendto ( msg - > sock , & rec - > packet , & nsent , path ) ;
2006-01-10 01:12:53 +03:00
talloc_free ( path ) ;
2005-06-03 08:21:25 +04:00
talloc_free ( priv ) ;
return status ;
}
2007-05-26 12:47:27 +04:00
/*
retry backed off messages
*/
2008-12-29 22:24:57 +03:00
static void msg_retry_timer ( struct tevent_context * ev , struct tevent_timer * te ,
2009-02-01 01:57:02 +03:00
struct timeval t , void * private_data )
2007-05-26 12:47:27 +04:00
{
2011-05-03 04:40:33 +04:00
struct imessaging_context * msg = talloc_get_type ( private_data ,
struct imessaging_context ) ;
2007-05-26 12:47:27 +04:00
msg - > retry_te = NULL ;
/* put the messages back on the main queue */
while ( msg - > retry_queue ) {
2011-05-03 04:40:33 +04:00
struct imessaging_rec * rec = msg - > retry_queue ;
2007-05-26 12:47:27 +04:00
DLIST_REMOVE ( msg - > retry_queue , rec ) ;
2011-05-03 04:40:33 +04:00
DLIST_ADD_END ( msg - > pending , rec , struct imessaging_rec * ) ;
2007-05-26 12:47:27 +04:00
}
2010-05-25 23:28:35 +04:00
TEVENT_FD_WRITEABLE ( msg - > event . fde ) ;
2007-05-26 12:47:27 +04:00
}
2005-06-03 08:21:25 +04:00
/*
handle a socket write event
*/
2011-05-03 04:40:33 +04:00
static void imessaging_send_handler ( struct imessaging_context * msg )
2005-06-03 08:21:25 +04:00
{
while ( msg - > pending ) {
2011-05-03 04:40:33 +04:00
struct imessaging_rec * rec = msg - > pending ;
2005-06-03 08:21:25 +04:00
NTSTATUS status ;
status = try_send ( rec ) ;
if ( NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) {
2007-05-26 12:47:27 +04:00
rec - > retries + + ;
if ( rec - > retries > 3 ) {
/* we're getting continuous write errors -
backoff this record */
DLIST_REMOVE ( msg - > pending , rec ) ;
DLIST_ADD_END ( msg - > retry_queue , rec ,
2011-05-03 04:40:33 +04:00
struct imessaging_rec * ) ;
2007-05-26 12:47:27 +04:00
if ( msg - > retry_te = = NULL ) {
msg - > retry_te =
2010-05-25 23:25:26 +04:00
tevent_add_timer ( msg - > event . ev , msg ,
2007-05-26 12:47:27 +04:00
timeval_current_ofs ( 1 , 0 ) ,
msg_retry_timer , msg ) ;
}
}
2005-06-03 08:21:25 +04:00
break ;
}
2007-05-26 12:47:27 +04:00
rec - > retries = 0 ;
2005-06-03 08:21:25 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-01-09 01:05:29 +03:00
TALLOC_CTX * tmp_ctx = talloc_new ( msg ) ;
2008-02-04 09:51:38 +03:00
DEBUG ( 1 , ( " messaging: Lost message from %s to %s of type %u - %s \n " ,
2011-06-08 08:05:55 +04:00
server_id_str ( tmp_ctx , & rec - > header - > from ) ,
server_id_str ( tmp_ctx , & rec - > header - > to ) ,
2008-02-04 09:51:38 +03:00
rec - > header - > msg_type ,
2005-06-03 08:21:25 +04:00
nt_errstr ( status ) ) ) ;
2010-01-09 01:05:29 +03:00
talloc_free ( tmp_ctx ) ;
2005-06-03 08:21:25 +04:00
}
DLIST_REMOVE ( msg - > pending , rec ) ;
talloc_free ( rec ) ;
}
if ( msg - > pending = = NULL ) {
2010-05-25 23:28:35 +04:00
TEVENT_FD_NOT_WRITEABLE ( msg - > event . fde ) ;
2005-06-03 08:21:25 +04:00
}
}
/*
handle a new incoming packet
*/
2011-05-03 04:40:33 +04:00
static void imessaging_recv_handler ( struct imessaging_context * msg )
2004-10-17 14:04:49 +04:00
{
2011-05-03 04:40:33 +04:00
struct imessaging_rec * rec ;
2004-10-17 14:04:49 +04:00
NTSTATUS status ;
2005-06-03 10:04:34 +04:00
DATA_BLOB packet ;
2005-05-01 22:49:07 +04:00
size_t msize ;
2004-10-17 14:04:49 +04:00
2005-06-03 10:04:34 +04:00
/* see how many bytes are in the next packet */
2005-06-03 17:20:45 +04:00
status = socket_pending ( msg - > sock , & msize ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " socket_pending failed in messaging - %s \n " ,
nt_errstr ( status ) ) ) ;
2005-06-03 10:04:34 +04:00
return ;
}
2005-06-03 17:20:45 +04:00
packet = data_blob_talloc ( msg , NULL , msize ) ;
2005-06-03 10:04:34 +04:00
if ( packet . data = = NULL ) {
/* assume this is temporary and retry */
return ;
}
2006-04-30 09:58:31 +04:00
status = socket_recv ( msg - > sock , packet . data , msize , & msize ) ;
2005-05-01 22:49:07 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-06-03 10:04:34 +04:00
data_blob_free ( & packet ) ;
2005-05-01 22:49:07 +04:00
return ;
2004-10-17 14:04:49 +04:00
}
2005-06-03 10:04:34 +04:00
if ( msize < sizeof ( * rec - > header ) ) {
2005-07-17 13:20:52 +04:00
DEBUG ( 0 , ( " messaging: bad message of size %d \n " , ( int ) msize ) ) ;
2005-06-03 10:04:34 +04:00
data_blob_free ( & packet ) ;
2005-05-01 22:49:07 +04:00
return ;
2004-10-17 14:04:49 +04:00
}
2011-05-03 04:40:33 +04:00
rec = talloc ( msg , struct imessaging_rec ) ;
2004-10-17 14:04:49 +04:00
if ( rec = = NULL ) {
2011-05-03 04:40:33 +04:00
smb_panic ( " Unable to allocate imessaging_rec " ) ;
2004-10-17 14:04:49 +04:00
}
2005-06-03 10:04:34 +04:00
talloc_steal ( rec , packet . data ) ;
2005-02-03 05:35:52 +03:00
rec - > msg = msg ;
rec - > path = msg - > path ;
2011-05-03 04:40:33 +04:00
rec - > header = ( struct imessaging_header * ) packet . data ;
2005-06-03 10:04:34 +04:00
rec - > packet = packet ;
2007-05-26 12:47:27 +04:00
rec - > retries = 0 ;
2005-05-01 22:49:07 +04:00
2005-06-03 10:04:34 +04:00
if ( msize ! = sizeof ( * rec - > header ) + rec - > header - > length ) {
2005-05-01 22:49:07 +04:00
DEBUG ( 0 , ( " messaging: bad message header size %d should be %d \n " ,
2005-07-17 13:20:52 +04:00
rec - > header - > length , ( int ) ( msize - sizeof ( * rec - > header ) ) ) ) ;
2005-05-01 22:49:07 +04:00
talloc_free ( rec ) ;
return ;
}
2011-05-03 04:40:33 +04:00
imessaging_dispatch ( msg , rec ) ;
2005-05-01 22:49:07 +04:00
talloc_free ( rec ) ;
2004-10-17 14:04:49 +04:00
}
2005-06-03 08:21:25 +04:00
/*
handle a socket event
*/
2011-05-03 04:40:33 +04:00
static void imessaging_handler ( struct tevent_context * ev , struct tevent_fd * fde ,
2009-02-01 01:57:02 +03:00
uint16_t flags , void * private_data )
2005-06-03 08:21:25 +04:00
{
2011-05-03 04:40:33 +04:00
struct imessaging_context * msg = talloc_get_type ( private_data ,
struct imessaging_context ) ;
2010-05-25 23:28:35 +04:00
if ( flags & TEVENT_FD_WRITE ) {
2011-05-03 04:40:33 +04:00
imessaging_send_handler ( msg ) ;
2005-06-03 08:21:25 +04:00
}
2010-05-25 23:28:35 +04:00
if ( flags & TEVENT_FD_READ ) {
2011-05-03 04:40:33 +04:00
imessaging_recv_handler ( msg ) ;
2005-06-03 08:21:25 +04:00
}
}
2004-10-17 14:04:49 +04:00
/*
Register a dispatch function for a particular message type .
*/
2011-05-03 04:40:33 +04:00
NTSTATUS imessaging_register ( struct imessaging_context * msg , void * private_data ,
2006-04-12 10:08:24 +04:00
uint32_t msg_type , msg_callback_t fn )
2004-10-17 14:04:49 +04:00
{
struct dispatch_fn * d ;
2006-04-12 10:08:24 +04:00
/* possibly expand dispatch array */
if ( msg_type > = msg - > num_types ) {
struct dispatch_fn * * dp ;
int i ;
dp = talloc_realloc ( msg , msg - > dispatch , struct dispatch_fn * , msg_type + 1 ) ;
NT_STATUS_HAVE_NO_MEMORY ( dp ) ;
msg - > dispatch = dp ;
for ( i = msg - > num_types ; i < = msg_type ; i + + ) {
msg - > dispatch [ i ] = NULL ;
}
msg - > num_types = msg_type + 1 ;
}
2006-04-12 19:52:17 +04:00
d = talloc_zero ( msg - > dispatch , struct dispatch_fn ) ;
2006-04-12 10:08:24 +04:00
NT_STATUS_HAVE_NO_MEMORY ( d ) ;
2004-10-17 14:04:49 +04:00
d - > msg_type = msg_type ;
2009-02-01 01:57:02 +03:00
d - > private_data = private_data ;
2004-10-17 14:04:49 +04:00
d - > fn = fn ;
2006-04-12 10:08:24 +04:00
DLIST_ADD ( msg - > dispatch [ msg_type ] , d ) ;
return NT_STATUS_OK ;
}
/*
register a temporary message handler . The msg_type is allocated
above MSG_TMP_BASE
*/
2011-05-03 04:40:33 +04:00
NTSTATUS imessaging_register_tmp ( struct imessaging_context * msg , void * private_data ,
2006-04-12 10:08:24 +04:00
msg_callback_t fn , uint32_t * msg_type )
{
struct dispatch_fn * d ;
int id ;
d = talloc_zero ( msg - > dispatch , struct dispatch_fn ) ;
NT_STATUS_HAVE_NO_MEMORY ( d ) ;
2009-02-01 01:57:02 +03:00
d - > private_data = private_data ;
2006-04-12 10:08:24 +04:00
d - > fn = fn ;
id = idr_get_new_above ( msg - > dispatch_tree , d , MSG_TMP_BASE , UINT16_MAX ) ;
if ( id = = - 1 ) {
talloc_free ( d ) ;
return NT_STATUS_TOO_MANY_CONTEXT_IDS ;
}
d - > msg_type = ( uint32_t ) id ;
( * msg_type ) = d - > msg_type ;
return NT_STATUS_OK ;
2004-10-17 14:04:49 +04:00
}
/*
De - register the function for a particular message type .
*/
2011-05-03 04:40:33 +04:00
void imessaging_deregister ( struct imessaging_context * msg , uint32_t msg_type , void * private_data )
2004-10-17 14:04:49 +04:00
{
2006-04-12 19:52:17 +04:00
struct dispatch_fn * d , * next ;
2004-10-17 14:04:49 +04:00
2006-04-12 10:08:24 +04:00
if ( msg_type > = msg - > num_types ) {
2007-09-09 23:34:30 +04:00
d = ( struct dispatch_fn * ) idr_find ( msg - > dispatch_tree ,
msg_type ) ;
2006-04-12 19:52:17 +04:00
if ( ! d ) return ;
idr_remove ( msg - > dispatch_tree , msg_type ) ;
talloc_free ( d ) ;
2006-04-12 10:08:24 +04:00
return ;
}
2006-04-12 19:52:17 +04:00
for ( d = msg - > dispatch [ msg_type ] ; d ; d = next ) {
2004-10-17 14:04:49 +04:00
next = d - > next ;
2009-02-01 01:57:02 +03:00
if ( d - > private_data = = private_data ) {
2006-04-12 19:52:17 +04:00
DLIST_REMOVE ( msg - > dispatch [ msg_type ] , d ) ;
2004-10-17 14:04:49 +04:00
talloc_free ( d ) ;
}
2006-04-12 10:08:24 +04:00
}
2004-10-17 14:04:49 +04:00
}
/*
Send a message to a particular server
*/
2011-05-03 04:40:33 +04:00
NTSTATUS imessaging_send ( struct imessaging_context * msg , struct server_id server ,
2010-08-30 15:42:20 +04:00
uint32_t msg_type , const DATA_BLOB * data )
2004-10-17 14:04:49 +04:00
{
2011-05-03 04:40:33 +04:00
struct imessaging_rec * rec ;
2004-10-17 14:04:49 +04:00
NTSTATUS status ;
2005-06-03 10:04:34 +04:00
size_t dlength = data ? data - > length : 0 ;
2004-10-17 14:04:49 +04:00
2011-05-03 04:40:33 +04:00
rec = talloc ( msg , struct imessaging_rec ) ;
2004-10-17 14:04:49 +04:00
if ( rec = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2005-06-03 10:04:34 +04:00
rec - > packet = data_blob_talloc ( rec , NULL , sizeof ( * rec - > header ) + dlength ) ;
if ( rec - > packet . data = = NULL ) {
talloc_free ( rec ) ;
return NT_STATUS_NO_MEMORY ;
}
2007-05-26 12:47:27 +04:00
rec - > retries = 0 ;
2005-06-03 10:04:34 +04:00
rec - > msg = msg ;
2011-05-03 04:40:33 +04:00
rec - > header = ( struct imessaging_header * ) rec - > packet . data ;
2008-03-15 14:21:06 +03:00
/* zero padding */
ZERO_STRUCTP ( rec - > header ) ;
2011-05-03 04:40:33 +04:00
rec - > header - > version = IMESSAGING_VERSION ;
2005-06-03 10:04:34 +04:00
rec - > header - > msg_type = msg_type ;
rec - > header - > from = msg - > server_id ;
rec - > header - > to = server ;
rec - > header - > length = dlength ;
if ( dlength ! = 0 ) {
memcpy ( rec - > packet . data + sizeof ( * rec - > header ) ,
data - > data , dlength ) ;
2004-10-17 14:04:49 +04:00
}
2007-02-08 05:59:58 +03:00
if ( ! cluster_node_equal ( & msg - > server_id , & server ) ) {
/* the destination is on another node - dispatch via
the cluster layer */
2007-02-09 04:52:13 +03:00
status = cluster_message_send ( server , & rec - > packet ) ;
2007-02-08 05:59:58 +03:00
talloc_free ( rec ) ;
return status ;
}
2011-05-03 04:40:33 +04:00
rec - > path = imessaging_path ( msg , server ) ;
2005-06-05 11:37:27 +04:00
talloc_steal ( rec , rec - > path ) ;
2004-10-17 14:04:49 +04:00
2005-06-05 11:44:51 +04:00
if ( msg - > pending ! = NULL ) {
status = STATUS_MORE_ENTRIES ;
} else {
status = try_send ( rec ) ;
}
2004-10-18 02:28:26 +04:00
if ( NT_STATUS_EQUAL ( status , STATUS_MORE_ENTRIES ) ) {
2005-06-03 08:21:25 +04:00
if ( msg - > pending = = NULL ) {
2010-05-25 23:28:35 +04:00
TEVENT_FD_WRITEABLE ( msg - > event . fde ) ;
2005-06-03 08:21:25 +04:00
}
2011-05-03 04:40:33 +04:00
DLIST_ADD_END ( msg - > pending , rec , struct imessaging_rec * ) ;
2004-10-18 02:28:26 +04:00
return NT_STATUS_OK ;
}
2005-06-03 08:21:25 +04:00
talloc_free ( rec ) ;
2004-10-17 17:33:03 +04:00
2005-06-03 08:21:25 +04:00
return status ;
2004-10-17 14:04:49 +04:00
}
2004-11-03 13:09:48 +03:00
/*
Send a message to a particular server , with the message containing a single pointer
*/
2011-05-03 04:40:33 +04:00
NTSTATUS imessaging_send_ptr ( struct imessaging_context * msg , struct server_id server ,
2004-11-03 13:09:48 +03:00
uint32_t msg_type , void * ptr )
{
DATA_BLOB blob ;
2007-09-07 19:08:14 +04:00
blob . data = ( uint8_t * ) & ptr ;
2004-11-03 13:09:48 +03:00
blob . length = sizeof ( void * ) ;
2011-05-03 04:40:33 +04:00
return imessaging_send ( msg , server , msg_type , & blob ) ;
2004-11-03 13:09:48 +03:00
}
2004-10-17 14:04:49 +04:00
/*
2011-07-22 08:55:32 +04:00
remove our messaging socket and database entry
2004-10-17 14:04:49 +04:00
*/
2011-07-22 08:55:32 +04:00
int imessaging_cleanup ( struct imessaging_context * msg )
2004-10-17 14:04:49 +04:00
{
2011-08-26 10:05:46 +04:00
if ( ! msg ) {
return 0 ;
}
2011-07-22 08:55:32 +04:00
DEBUG ( 5 , ( " imessaging: cleaning up %s \n " , msg - > path ) ) ;
2004-10-25 07:30:39 +04:00
unlink ( msg - > path ) ;
2005-07-10 08:54:21 +04:00
while ( msg - > names & & msg - > names [ 0 ] ) {
irpc_remove_name ( msg , msg - > names [ 0 ] ) ;
}
2004-10-17 14:04:49 +04:00
return 0 ;
}
/*
create the listening socket and setup the dispatcher
2011-07-22 08:55:32 +04:00
use temporary = true when you want a destructor to remove the
associated messaging socket and database entry on talloc free . Don ' t
use this in processes that may fork and a child may talloc free this
memory
2004-10-17 14:04:49 +04:00
*/
2011-05-03 04:40:33 +04:00
struct imessaging_context * imessaging_init ( TALLOC_CTX * mem_ctx ,
2011-07-22 08:55:32 +04:00
const char * dir ,
struct server_id server_id ,
struct tevent_context * ev ,
bool auto_remove )
2004-10-17 14:04:49 +04:00
{
2011-05-03 04:40:33 +04:00
struct imessaging_context * msg ;
2004-10-17 14:04:49 +04:00
NTSTATUS status ;
2006-01-10 01:12:53 +03:00
struct socket_address * path ;
2004-10-17 14:04:49 +04:00
2008-04-22 01:58:23 +04:00
if ( ev = = NULL ) {
return NULL ;
}
2011-05-03 04:40:33 +04:00
msg = talloc_zero ( mem_ctx , struct imessaging_context ) ;
2004-10-17 14:04:49 +04:00
if ( msg = = NULL ) {
return NULL ;
}
2007-02-08 03:58:17 +03:00
/* setup a handler for messages from other cluster nodes, if appropriate */
status = cluster_message_init ( msg , server_id , cluster_message_handler ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( msg ) ;
return NULL ;
}
2004-10-17 14:04:49 +04:00
/* create the messaging directory if needed */
2006-01-10 01:12:53 +03:00
mkdir ( dir , 0700 ) ;
2004-10-17 14:04:49 +04:00
2007-10-01 22:52:55 +04:00
msg - > base_path = talloc_reference ( msg , dir ) ;
2011-05-03 04:40:33 +04:00
msg - > path = imessaging_path ( msg , server_id ) ;
2006-04-12 10:08:24 +04:00
msg - > server_id = server_id ;
msg - > idr = idr_init ( msg ) ;
msg - > dispatch_tree = idr_init ( msg ) ;
msg - > start_time = timeval_current ( ) ;
2004-10-17 14:04:49 +04:00
2005-05-01 22:49:07 +04:00
status = socket_create ( " unix " , SOCKET_TYPE_DGRAM , & msg - > sock , 0 ) ;
2004-10-17 14:04:49 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( msg ) ;
return NULL ;
}
/* by stealing here we ensure that the socket is cleaned up (and even
deleted ) on exit */
talloc_steal ( msg , msg - > sock ) ;
2006-01-10 01:12:53 +03:00
path = socket_address_from_strings ( msg , msg - > sock - > backend_name ,
msg - > path , 0 ) ;
if ( ! path ) {
talloc_free ( msg ) ;
return NULL ;
}
status = socket_listen ( msg - > sock , path , 50 , 0 ) ;
2004-10-17 14:04:49 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-07-01 12:14:21 +04:00
DEBUG ( 0 , ( " Unable to setup messaging listener for '%s':%s \n " , msg - > path , nt_errstr ( status ) ) ) ;
2004-10-17 14:04:49 +04:00
talloc_free ( msg ) ;
return NULL ;
}
2005-06-03 08:21:25 +04:00
/* it needs to be non blocking for sends */
2007-08-27 22:43:18 +04:00
set_blocking ( socket_get_fd ( msg - > sock ) , false ) ;
2005-06-03 08:21:25 +04:00
2009-08-07 11:14:13 +04:00
msg - > event . ev = ev ;
2010-05-25 23:25:26 +04:00
msg - > event . fde = tevent_add_fd ( ev , msg , socket_get_fd ( msg - > sock ) ,
2010-05-25 23:28:35 +04:00
TEVENT_FD_READ , imessaging_handler , msg ) ;
2010-03-05 02:42:41 +03:00
tevent_fd_set_auto_close ( msg - > event . fde ) ;
2004-10-17 14:04:49 +04:00
2011-07-22 08:55:32 +04:00
if ( auto_remove ) {
talloc_set_destructor ( msg , imessaging_cleanup ) ;
}
2004-10-17 14:04:49 +04:00
2011-05-03 04:40:33 +04:00
imessaging_register ( msg , NULL , MSG_PING , ping_message ) ;
imessaging_register ( msg , NULL , MSG_IRPC , irpc_handler ) ;
2005-07-19 13:28:13 +04:00
IRPC_REGISTER ( msg , irpc , IRPC_UPTIME , irpc_uptime , msg ) ;
2004-10-17 14:04:49 +04:00
return msg ;
}
2005-06-05 10:53:07 +04:00
2006-02-04 01:30:30 +03:00
/*
A hack , for the short term until we get ' client only ' messaging in place
*/
2011-05-03 04:40:33 +04:00
struct imessaging_context * imessaging_client_init ( TALLOC_CTX * mem_ctx ,
2007-10-01 22:52:55 +04:00
const char * dir ,
2008-12-29 22:24:57 +03:00
struct tevent_context * ev )
2006-02-04 01:30:30 +03:00
{
2007-01-10 13:52:09 +03:00
struct server_id id ;
ZERO_STRUCT ( id ) ;
2011-05-02 04:05:46 +04:00
id . pid = random ( ) % 0x10000000 ;
2011-07-22 08:55:32 +04:00
return imessaging_init ( mem_ctx , dir , id , ev , true ) ;
2006-02-04 01:30:30 +03:00
}
2005-06-05 10:53:07 +04:00
/*
a list of registered irpc server functions
*/
struct irpc_list {
struct irpc_list * next , * prev ;
struct GUID uuid ;
2007-08-20 00:46:45 +04:00
const struct ndr_interface_table * table ;
2005-06-05 10:53:07 +04:00
int callnum ;
irpc_function_t fn ;
2009-02-01 01:57:02 +03:00
void * private_data ;
2005-06-05 10:53:07 +04:00
} ;
/*
register a irpc server function
*/
2011-05-03 04:40:33 +04:00
NTSTATUS irpc_register ( struct imessaging_context * msg_ctx ,
2007-08-20 00:46:45 +04:00
const struct ndr_interface_table * table ,
2009-02-01 01:57:02 +03:00
int callnum , irpc_function_t fn , void * private_data )
2005-06-05 10:53:07 +04:00
{
struct irpc_list * irpc ;
2005-06-05 11:30:44 +04:00
/* override an existing handler, if any */
for ( irpc = msg_ctx - > irpc ; irpc ; irpc = irpc - > next ) {
if ( irpc - > table = = table & & irpc - > callnum = = callnum ) {
break ;
}
}
if ( irpc = = NULL ) {
irpc = talloc ( msg_ctx , struct irpc_list ) ;
NT_STATUS_HAVE_NO_MEMORY ( irpc ) ;
DLIST_ADD ( msg_ctx - > irpc , irpc ) ;
}
2005-06-05 10:53:07 +04:00
irpc - > table = table ;
2005-06-05 11:30:44 +04:00
irpc - > callnum = callnum ;
2005-06-05 10:53:07 +04:00
irpc - > fn = fn ;
2009-02-01 01:57:02 +03:00
irpc - > private_data = private_data ;
2006-03-26 04:59:17 +04:00
irpc - > uuid = irpc - > table - > syntax_id . uuid ;
2005-06-05 10:53:07 +04:00
return NT_STATUS_OK ;
}
/*
handle an incoming irpc reply message
*/
2011-05-03 04:40:33 +04:00
static void irpc_handler_reply ( struct imessaging_context * msg_ctx , struct irpc_message * m )
2005-06-05 10:53:07 +04:00
{
struct irpc_request * irpc ;
2007-09-09 23:34:30 +04:00
irpc = ( struct irpc_request * ) idr_find ( msg_ctx - > idr , m - > header . callid ) ;
2005-06-05 10:53:07 +04:00
if ( irpc = = NULL ) return ;
2010-09-03 18:05:38 +04:00
irpc - > incoming . handler ( irpc , m ) ;
2005-06-05 10:53:07 +04:00
}
2005-09-25 17:01:26 +04:00
/*
send a irpc reply
*/
2005-09-25 17:17:03 +04:00
NTSTATUS irpc_send_reply ( struct irpc_message * m , NTSTATUS status )
2005-09-25 17:01:26 +04:00
{
struct ndr_push * push ;
DATA_BLOB packet ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2005-09-25 17:01:26 +04:00
2005-09-25 17:17:03 +04:00
m - > header . status = status ;
2005-09-25 17:01:26 +04:00
/* setup the reply */
2010-05-09 19:20:01 +04:00
push = ndr_push_init_ctx ( m - > ndr ) ;
2005-09-25 17:01:26 +04:00
if ( push = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto failed ;
}
m - > header . flags | = IRPC_FLAG_REPLY ;
2010-09-27 03:42:26 +04:00
m - > header . creds . token = NULL ;
2005-09-25 17:01:26 +04:00
/* construct the packet */
2007-11-09 21:24:51 +03:00
ndr_err = ndr_push_irpc_header ( push , NDR_SCALARS | NDR_BUFFERS , & m - > header ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
goto failed ;
}
2005-09-25 17:01:26 +04:00
2007-11-09 21:24:51 +03:00
ndr_err = m - > irpc - > table - > calls [ m - > irpc - > callnum ] . ndr_push ( push , NDR_OUT , m - > data ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
goto failed ;
}
2005-09-25 17:01:26 +04:00
/* send the reply message */
packet = ndr_push_blob ( push ) ;
2011-05-03 04:40:33 +04:00
status = imessaging_send ( m - > msg_ctx , m - > from , MSG_IRPC , & packet ) ;
2005-09-25 17:01:26 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
failed :
talloc_free ( m ) ;
return status ;
}
2005-06-05 10:53:07 +04:00
/*
handle an incoming irpc request message
*/
2011-05-03 04:40:33 +04:00
static void irpc_handler_request ( struct imessaging_context * msg_ctx ,
2005-09-25 17:01:26 +04:00
struct irpc_message * m )
2005-06-05 10:53:07 +04:00
{
struct irpc_list * i ;
void * r ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2005-06-05 10:53:07 +04:00
for ( i = msg_ctx - > irpc ; i ; i = i - > next ) {
2005-09-25 17:01:26 +04:00
if ( GUID_equal ( & i - > uuid , & m - > header . uuid ) & &
2006-03-26 04:59:17 +04:00
i - > table - > syntax_id . if_version = = m - > header . if_version & &
2005-09-25 17:01:26 +04:00
i - > callnum = = m - > header . callnum ) {
2005-06-05 10:53:07 +04:00
break ;
}
}
if ( i = = NULL ) {
/* no registered handler for this message */
2005-09-25 17:01:26 +04:00
talloc_free ( m ) ;
2005-06-05 10:53:07 +04:00
return ;
}
/* allocate space for the structure */
2005-09-25 17:01:26 +04:00
r = talloc_zero_size ( m - > ndr , i - > table - > calls [ m - > header . callnum ] . struct_size ) ;
2005-06-05 10:53:07 +04:00
if ( r = = NULL ) goto failed ;
2010-09-23 06:04:58 +04:00
m - > ndr - > flags | = LIBNDR_FLAG_REF_ALLOC ;
2005-06-05 10:53:07 +04:00
/* parse the request data */
2007-11-09 21:24:51 +03:00
ndr_err = i - > table - > calls [ i - > callnum ] . ndr_pull ( m - > ndr , NDR_IN , r ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) goto failed ;
2005-06-05 10:53:07 +04:00
/* make the call */
2009-02-01 02:03:47 +03:00
m - > private_data = i - > private_data ;
2007-08-27 22:43:18 +04:00
m - > defer_reply = false ;
2010-09-12 04:02:02 +04:00
m - > no_reply = false ;
2005-09-25 17:01:26 +04:00
m - > msg_ctx = msg_ctx ;
m - > irpc = i ;
m - > data = r ;
2005-09-25 17:17:03 +04:00
m - > ev = msg_ctx - > event . ev ;
2005-06-05 10:53:07 +04:00
2005-09-25 17:01:26 +04:00
m - > header . status = i - > fn ( m , r ) ;
2005-06-05 10:53:07 +04:00
2010-09-12 04:02:02 +04:00
if ( m - > no_reply ) {
/* the server function won't ever be replying to this request */
talloc_free ( m ) ;
return ;
}
2005-09-25 17:01:26 +04:00
if ( m - > defer_reply ) {
/* the server function has asked to defer the reply to later */
talloc_steal ( msg_ctx , m ) ;
return ;
}
2005-06-05 10:53:07 +04:00
2005-09-25 17:17:03 +04:00
irpc_send_reply ( m , m - > header . status ) ;
2005-09-25 17:01:26 +04:00
return ;
2005-06-05 10:53:07 +04:00
failed :
2005-09-25 17:01:26 +04:00
talloc_free ( m ) ;
2005-06-05 10:53:07 +04:00
}
/*
handle an incoming irpc message
*/
2011-05-03 04:40:33 +04:00
static void irpc_handler ( struct imessaging_context * msg_ctx , void * private_data ,
2007-01-10 13:52:09 +03:00
uint32_t msg_type , struct server_id src , DATA_BLOB * packet )
2005-06-05 10:53:07 +04:00
{
2005-09-25 17:01:26 +04:00
struct irpc_message * m ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2005-06-05 10:53:07 +04:00
2005-09-25 17:01:26 +04:00
m = talloc ( msg_ctx , struct irpc_message ) ;
if ( m = = NULL ) goto failed ;
m - > from = src ;
2005-06-05 10:53:07 +04:00
2010-05-09 19:20:01 +04:00
m - > ndr = ndr_pull_init_blob ( packet , m ) ;
2005-09-25 17:01:26 +04:00
if ( m - > ndr = = NULL ) goto failed ;
2005-07-19 13:28:13 +04:00
2005-09-25 17:01:26 +04:00
m - > ndr - > flags | = LIBNDR_FLAG_REF_ALLOC ;
2007-11-09 21:24:51 +03:00
ndr_err = ndr_pull_irpc_header ( m - > ndr , NDR_BUFFERS | NDR_SCALARS , & m - > header ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) goto failed ;
2005-06-05 10:53:07 +04:00
2005-09-25 17:01:26 +04:00
if ( m - > header . flags & IRPC_FLAG_REPLY ) {
irpc_handler_reply ( msg_ctx , m ) ;
2005-06-05 10:53:07 +04:00
} else {
2005-09-25 17:01:26 +04:00
irpc_handler_request ( msg_ctx , m ) ;
2005-06-05 10:53:07 +04:00
}
2005-07-10 12:35:18 +04:00
return ;
2005-06-05 10:53:07 +04:00
failed :
2005-09-25 17:01:26 +04:00
talloc_free ( m ) ;
2005-06-05 10:53:07 +04:00
}
/*
destroy a irpc request
*/
2006-05-24 11:34:11 +04:00
static int irpc_destructor ( struct irpc_request * irpc )
2005-06-05 10:53:07 +04:00
{
2007-05-01 13:55:36 +04:00
if ( irpc - > callid ! = - 1 ) {
idr_remove ( irpc - > msg_ctx - > idr , irpc - > callid ) ;
irpc - > callid = - 1 ;
}
2005-06-05 10:53:07 +04:00
return 0 ;
}
2005-07-10 08:54:21 +04:00
/*
open the naming database
*/
2011-05-03 04:40:33 +04:00
static struct tdb_wrap * irpc_namedb_open ( struct imessaging_context * msg_ctx )
2005-07-10 08:54:21 +04:00
{
struct tdb_wrap * t ;
char * path = talloc_asprintf ( msg_ctx , " %s/names.tdb " , msg_ctx - > base_path ) ;
if ( path = = NULL ) {
return NULL ;
}
t = tdb_wrap_open ( msg_ctx , path , 0 , 0 , O_RDWR | O_CREAT , 0660 ) ;
talloc_free ( path ) ;
return t ;
}
2005-07-10 05:08:10 +04:00
/*
add a string name that this irpc server can be called on
*/
2011-05-03 04:40:33 +04:00
NTSTATUS irpc_add_name ( struct imessaging_context * msg_ctx , const char * name )
2005-07-10 05:08:10 +04:00
{
2005-07-10 08:54:21 +04:00
struct tdb_wrap * t ;
TDB_DATA rec ;
int count ;
NTSTATUS status = NT_STATUS_OK ;
t = irpc_namedb_open ( msg_ctx ) ;
NT_STATUS_HAVE_NO_MEMORY ( t ) ;
2005-07-10 10:17:39 +04:00
if ( tdb_lock_bystring ( t - > tdb , name ) ! = 0 ) {
talloc_free ( t ) ;
return NT_STATUS_LOCK_NOT_GRANTED ;
}
2005-07-10 08:54:21 +04:00
rec = tdb_fetch_bystring ( t - > tdb , name ) ;
2007-01-10 13:52:09 +03:00
count = rec . dsize / sizeof ( struct server_id ) ;
rec . dptr = ( unsigned char * ) realloc_p ( rec . dptr , struct server_id , count + 1 ) ;
rec . dsize + = sizeof ( struct server_id ) ;
2005-07-10 08:54:21 +04:00
if ( rec . dptr = = NULL ) {
2005-07-10 10:17:39 +04:00
tdb_unlock_bystring ( t - > tdb , name ) ;
2005-07-10 08:54:21 +04:00
talloc_free ( t ) ;
return NT_STATUS_NO_MEMORY ;
}
2007-01-10 13:52:09 +03:00
( ( struct server_id * ) rec . dptr ) [ count ] = msg_ctx - > server_id ;
2005-07-10 08:54:21 +04:00
if ( tdb_store_bystring ( t - > tdb , name , rec , 0 ) ! = 0 ) {
status = NT_STATUS_INTERNAL_ERROR ;
}
free ( rec . dptr ) ;
2005-07-10 10:17:39 +04:00
tdb_unlock_bystring ( t - > tdb , name ) ;
2005-07-10 08:54:21 +04:00
talloc_free ( t ) ;
msg_ctx - > names = str_list_add ( msg_ctx - > names , name ) ;
talloc_steal ( msg_ctx , msg_ctx - > names ) ;
return status ;
2005-07-10 05:08:10 +04:00
}
2005-07-10 08:54:21 +04:00
/*
return a list of server ids for a server name
*/
2011-05-03 04:40:33 +04:00
struct server_id * irpc_servers_byname ( struct imessaging_context * msg_ctx ,
2007-05-07 19:19:53 +04:00
TALLOC_CTX * mem_ctx ,
2007-01-10 13:52:09 +03:00
const char * name )
2005-07-10 08:54:21 +04:00
{
struct tdb_wrap * t ;
TDB_DATA rec ;
int count , i ;
2007-01-10 13:52:09 +03:00
struct server_id * ret ;
2005-07-10 08:54:21 +04:00
t = irpc_namedb_open ( msg_ctx ) ;
if ( t = = NULL ) {
return NULL ;
}
2005-07-10 05:08:10 +04:00
2005-07-10 10:17:39 +04:00
if ( tdb_lock_bystring ( t - > tdb , name ) ! = 0 ) {
talloc_free ( t ) ;
return NULL ;
}
2005-07-10 08:54:21 +04:00
rec = tdb_fetch_bystring ( t - > tdb , name ) ;
if ( rec . dptr = = NULL ) {
2005-07-10 10:17:39 +04:00
tdb_unlock_bystring ( t - > tdb , name ) ;
2005-07-10 08:54:21 +04:00
talloc_free ( t ) ;
return NULL ;
}
2007-01-10 13:52:09 +03:00
count = rec . dsize / sizeof ( struct server_id ) ;
2007-05-07 19:19:53 +04:00
ret = talloc_array ( mem_ctx , struct server_id , count + 1 ) ;
2005-07-10 08:54:21 +04:00
if ( ret = = NULL ) {
2005-07-10 10:17:39 +04:00
tdb_unlock_bystring ( t - > tdb , name ) ;
2005-07-10 08:54:21 +04:00
talloc_free ( t ) ;
return NULL ;
}
for ( i = 0 ; i < count ; i + + ) {
2007-01-10 13:52:09 +03:00
ret [ i ] = ( ( struct server_id * ) rec . dptr ) [ i ] ;
2005-07-10 08:54:21 +04:00
}
2008-02-04 09:51:38 +03:00
ret [ i ] = cluster_id ( 0 , 0 ) ;
2005-07-10 08:54:21 +04:00
free ( rec . dptr ) ;
2005-07-10 10:17:39 +04:00
tdb_unlock_bystring ( t - > tdb , name ) ;
2005-07-10 08:54:21 +04:00
talloc_free ( t ) ;
return ret ;
}
/*
remove a name from a messaging context
*/
2011-05-03 04:40:33 +04:00
void irpc_remove_name ( struct imessaging_context * msg_ctx , const char * name )
2005-07-10 08:54:21 +04:00
{
struct tdb_wrap * t ;
TDB_DATA rec ;
int count , i ;
2007-01-10 13:52:09 +03:00
struct server_id * ids ;
2005-07-10 08:54:21 +04:00
str_list_remove ( msg_ctx - > names , name ) ;
t = irpc_namedb_open ( msg_ctx ) ;
if ( t = = NULL ) {
return ;
}
2005-07-10 10:17:39 +04:00
if ( tdb_lock_bystring ( t - > tdb , name ) ! = 0 ) {
talloc_free ( t ) ;
return ;
}
2005-07-10 08:54:21 +04:00
rec = tdb_fetch_bystring ( t - > tdb , name ) ;
2008-05-19 17:53:09 +04:00
if ( rec . dptr = = NULL ) {
tdb_unlock_bystring ( t - > tdb , name ) ;
talloc_free ( t ) ;
return ;
}
2007-01-10 13:52:09 +03:00
count = rec . dsize / sizeof ( struct server_id ) ;
2005-07-10 08:54:21 +04:00
if ( count = = 0 ) {
2008-05-19 17:53:09 +04:00
free ( rec . dptr ) ;
2005-07-10 10:17:39 +04:00
tdb_unlock_bystring ( t - > tdb , name ) ;
2005-07-10 08:54:21 +04:00
talloc_free ( t ) ;
return ;
}
2007-01-10 13:52:09 +03:00
ids = ( struct server_id * ) rec . dptr ;
2005-07-10 08:54:21 +04:00
for ( i = 0 ; i < count ; i + + ) {
2007-01-10 13:52:09 +03:00
if ( cluster_id_equal ( & ids [ i ] , & msg_ctx - > server_id ) ) {
2005-07-10 08:54:21 +04:00
if ( i < count - 1 ) {
2007-01-10 13:52:09 +03:00
memmove ( ids + i , ids + i + 1 ,
sizeof ( struct server_id ) * ( count - ( i + 1 ) ) ) ;
2005-07-10 08:54:21 +04:00
}
2007-01-10 13:52:09 +03:00
rec . dsize - = sizeof ( struct server_id ) ;
2005-07-10 08:54:21 +04:00
break ;
}
}
tdb_store_bystring ( t - > tdb , name , rec , 0 ) ;
free ( rec . dptr ) ;
2005-07-10 10:17:39 +04:00
tdb_unlock_bystring ( t - > tdb , name ) ;
2005-07-10 08:54:21 +04:00
talloc_free ( t ) ;
}
2008-05-26 03:52:35 +04:00
2011-05-03 04:40:33 +04:00
struct server_id imessaging_get_server_id ( struct imessaging_context * msg_ctx )
2008-05-26 03:52:35 +04:00
{
return msg_ctx - > server_id ;
}
2010-08-30 15:44:01 +04:00
struct irpc_bh_state {
2011-05-03 04:40:33 +04:00
struct imessaging_context * msg_ctx ;
2010-08-30 15:44:01 +04:00
struct server_id server_id ;
const struct ndr_interface_table * table ;
2010-09-03 21:52:59 +04:00
uint32_t timeout ;
2010-09-27 03:42:26 +04:00
struct security_token * token ;
2010-08-30 15:44:01 +04:00
} ;
static bool irpc_bh_is_connected ( struct dcerpc_binding_handle * h )
{
struct irpc_bh_state * hs = dcerpc_binding_handle_data ( h ,
struct irpc_bh_state ) ;
if ( ! hs - > msg_ctx ) {
return false ;
}
return true ;
}
2010-09-03 21:52:59 +04:00
static uint32_t irpc_bh_set_timeout ( struct dcerpc_binding_handle * h ,
uint32_t timeout )
{
struct irpc_bh_state * hs = dcerpc_binding_handle_data ( h ,
struct irpc_bh_state ) ;
uint32_t old = hs - > timeout ;
hs - > timeout = timeout ;
return old ;
}
2010-08-30 15:44:01 +04:00
struct irpc_bh_raw_call_state {
struct irpc_request * irpc ;
uint32_t opnum ;
DATA_BLOB in_data ;
DATA_BLOB in_packet ;
DATA_BLOB out_data ;
} ;
static void irpc_bh_raw_call_incoming_handler ( struct irpc_request * irpc ,
struct irpc_message * m ) ;
static struct tevent_req * irpc_bh_raw_call_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct dcerpc_binding_handle * h ,
const struct GUID * object ,
uint32_t opnum ,
uint32_t in_flags ,
const uint8_t * in_data ,
size_t in_length )
{
struct irpc_bh_state * hs =
dcerpc_binding_handle_data ( h ,
struct irpc_bh_state ) ;
struct tevent_req * req ;
struct irpc_bh_raw_call_state * state ;
bool ok ;
struct irpc_header header ;
struct ndr_push * ndr ;
NTSTATUS status ;
enum ndr_err_code ndr_err ;
req = tevent_req_create ( mem_ctx , & state ,
struct irpc_bh_raw_call_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > opnum = opnum ;
state - > in_data . data = discard_const_p ( uint8_t , in_data ) ;
state - > in_data . length = in_length ;
ok = irpc_bh_is_connected ( h ) ;
if ( ! ok ) {
2011-09-14 19:57:37 +04:00
tevent_req_nterror ( req , NT_STATUS_CONNECTION_DISCONNECTED ) ;
2010-08-30 15:44:01 +04:00
return tevent_req_post ( req , ev ) ;
}
state - > irpc = talloc_zero ( state , struct irpc_request ) ;
if ( tevent_req_nomem ( state - > irpc , req ) ) {
return tevent_req_post ( req , ev ) ;
}
state - > irpc - > msg_ctx = hs - > msg_ctx ;
state - > irpc - > callid = idr_get_new ( hs - > msg_ctx - > idr ,
state - > irpc , UINT16_MAX ) ;
if ( state - > irpc - > callid = = - 1 ) {
tevent_req_nterror ( req , NT_STATUS_INSUFFICIENT_RESOURCES ) ;
return tevent_req_post ( req , ev ) ;
}
state - > irpc - > incoming . handler = irpc_bh_raw_call_incoming_handler ;
state - > irpc - > incoming . private_data = req ;
talloc_set_destructor ( state - > irpc , irpc_destructor ) ;
/* setup the header */
header . uuid = hs - > table - > syntax_id . uuid ;
header . if_version = hs - > table - > syntax_id . if_version ;
header . callid = state - > irpc - > callid ;
header . callnum = state - > opnum ;
header . flags = 0 ;
header . status = NT_STATUS_OK ;
2010-09-27 03:42:26 +04:00
header . creds . token = hs - > token ;
2010-08-30 15:44:01 +04:00
/* construct the irpc packet */
ndr = ndr_push_init_ctx ( state - > irpc ) ;
if ( tevent_req_nomem ( ndr , req ) ) {
return tevent_req_post ( req , ev ) ;
}
ndr_err = ndr_push_irpc_header ( ndr , NDR_SCALARS | NDR_BUFFERS , & header ) ;
status = ndr_map_error2ntstatus ( ndr_err ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
ndr_err = ndr_push_bytes ( ndr , in_data , in_length ) ;
status = ndr_map_error2ntstatus ( ndr_err ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
/* and send it */
state - > in_packet = ndr_push_blob ( ndr ) ;
2011-05-03 04:40:33 +04:00
status = imessaging_send ( hs - > msg_ctx , hs - > server_id ,
2010-08-30 15:44:01 +04:00
MSG_IRPC , & state - > in_packet ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
tevent_req_nterror ( req , status ) ;
return tevent_req_post ( req , ev ) ;
}
2010-09-15 17:53:48 +04:00
if ( hs - > timeout ! = IRPC_CALL_TIMEOUT_INF ) {
/* set timeout-callback in case caller wants that */
ok = tevent_req_set_endtime ( req , ev , timeval_current_ofs ( hs - > timeout , 0 ) ) ;
if ( ! ok ) {
return tevent_req_post ( req , ev ) ;
}
2010-09-03 21:52:59 +04:00
}
2010-08-30 15:44:01 +04:00
return req ;
}
static void irpc_bh_raw_call_incoming_handler ( struct irpc_request * irpc ,
struct irpc_message * m )
{
struct tevent_req * req =
talloc_get_type_abort ( irpc - > incoming . private_data ,
struct tevent_req ) ;
struct irpc_bh_raw_call_state * state =
tevent_req_data ( req ,
struct irpc_bh_raw_call_state ) ;
talloc_steal ( state , m ) ;
if ( ! NT_STATUS_IS_OK ( m - > header . status ) ) {
tevent_req_nterror ( req , m - > header . status ) ;
return ;
}
state - > out_data = data_blob_talloc ( state ,
m - > ndr - > data + m - > ndr - > offset ,
m - > ndr - > data_size - m - > ndr - > offset ) ;
if ( ( m - > ndr - > data_size - m - > ndr - > offset ) > 0 & & ! state - > out_data . data ) {
2011-06-19 23:10:01 +04:00
tevent_req_oom ( req ) ;
2010-08-30 15:44:01 +04:00
return ;
}
tevent_req_done ( req ) ;
}
static NTSTATUS irpc_bh_raw_call_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
uint8_t * * out_data ,
size_t * out_length ,
uint32_t * out_flags )
{
struct irpc_bh_raw_call_state * state =
tevent_req_data ( req ,
struct irpc_bh_raw_call_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
* out_data = talloc_move ( mem_ctx , & state - > out_data . data ) ;
* out_length = state - > out_data . length ;
* out_flags = 0 ;
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
struct irpc_bh_disconnect_state {
uint8_t _dummy ;
} ;
static struct tevent_req * irpc_bh_disconnect_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct dcerpc_binding_handle * h )
{
struct irpc_bh_state * hs = dcerpc_binding_handle_data ( h ,
struct irpc_bh_state ) ;
struct tevent_req * req ;
struct irpc_bh_disconnect_state * state ;
bool ok ;
req = tevent_req_create ( mem_ctx , & state ,
struct irpc_bh_disconnect_state ) ;
if ( req = = NULL ) {
return NULL ;
}
ok = irpc_bh_is_connected ( h ) ;
if ( ! ok ) {
2011-09-14 19:57:37 +04:00
tevent_req_nterror ( req , NT_STATUS_CONNECTION_DISCONNECTED ) ;
2010-08-30 15:44:01 +04:00
return tevent_req_post ( req , ev ) ;
}
hs - > msg_ctx = NULL ;
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
static NTSTATUS irpc_bh_disconnect_recv ( struct tevent_req * req )
{
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
static bool irpc_bh_ref_alloc ( struct dcerpc_binding_handle * h )
{
return true ;
}
static const struct dcerpc_binding_handle_ops irpc_bh_ops = {
. name = " wbint " ,
. is_connected = irpc_bh_is_connected ,
2010-09-03 21:52:59 +04:00
. set_timeout = irpc_bh_set_timeout ,
2010-08-30 15:44:01 +04:00
. raw_call_send = irpc_bh_raw_call_send ,
. raw_call_recv = irpc_bh_raw_call_recv ,
. disconnect_send = irpc_bh_disconnect_send ,
. disconnect_recv = irpc_bh_disconnect_recv ,
. ref_alloc = irpc_bh_ref_alloc ,
} ;
/* initialise a irpc binding handle */
struct dcerpc_binding_handle * irpc_binding_handle ( TALLOC_CTX * mem_ctx ,
2011-05-03 04:40:33 +04:00
struct imessaging_context * msg_ctx ,
2010-08-30 15:44:01 +04:00
struct server_id server_id ,
const struct ndr_interface_table * table )
{
struct dcerpc_binding_handle * h ;
struct irpc_bh_state * hs ;
h = dcerpc_binding_handle_create ( mem_ctx ,
& irpc_bh_ops ,
NULL ,
table ,
& hs ,
struct irpc_bh_state ,
__location__ ) ;
if ( h = = NULL ) {
return NULL ;
}
hs - > msg_ctx = msg_ctx ;
hs - > server_id = server_id ;
hs - > table = table ;
2010-09-03 21:52:59 +04:00
hs - > timeout = IRPC_CALL_TIMEOUT ;
2010-08-30 15:44:01 +04:00
dcerpc_binding_handle_set_sync_ev ( h , msg_ctx - > event . ev ) ;
return h ;
}
2010-08-30 15:44:41 +04:00
struct dcerpc_binding_handle * irpc_binding_handle_by_name ( TALLOC_CTX * mem_ctx ,
2011-05-03 04:40:33 +04:00
struct imessaging_context * msg_ctx ,
2010-08-30 15:44:41 +04:00
const char * dest_task ,
const struct ndr_interface_table * table )
{
struct dcerpc_binding_handle * h ;
struct server_id * sids ;
struct server_id sid ;
/* find the server task */
sids = irpc_servers_byname ( msg_ctx , mem_ctx , dest_task ) ;
if ( sids = = NULL ) {
errno = EADDRNOTAVAIL ;
return NULL ;
}
2011-05-02 04:05:46 +04:00
if ( sids [ 0 ] . pid = = 0 ) {
2010-08-30 15:44:41 +04:00
talloc_free ( sids ) ;
errno = EADDRNOTAVAIL ;
return NULL ;
}
sid = sids [ 0 ] ;
talloc_free ( sids ) ;
h = irpc_binding_handle ( mem_ctx , msg_ctx ,
sid , table ) ;
if ( h = = NULL ) {
return NULL ;
}
return h ;
}
2010-09-27 04:04:43 +04:00
void irpc_binding_handle_add_security_token ( struct dcerpc_binding_handle * h ,
struct security_token * token )
{
struct irpc_bh_state * hs =
dcerpc_binding_handle_data ( h ,
struct irpc_bh_state ) ;
hs - > token = token ;
}