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"
2007-11-16 22:12:00 +03:00
# include "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"
2008-09-16 17:16:31 +04:00
# include "../tdb/include/tdb.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"
2004-10-17 14:04:49 +04:00
/* change the message version with any incompatible changes in the protocol */
# define MESSAGING_VERSION 1
2004-10-27 02:45:33 +04:00
struct messaging_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 ;
2005-06-03 08:21:25 +04:00
struct messaging_rec * pending ;
2007-05-26 12:47:27 +04:00
struct messaging_rec * retry_queue ;
2007-12-14 01:23:25 +03:00
struct smb_iconv_convenience * iconv_convenience ;
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 */
struct messaging_rec {
2005-06-03 08:21:25 +04:00
struct messaging_rec * next , * prev ;
2004-10-27 02:45:33 +04:00
struct messaging_context * msg ;
2004-10-17 14:04:49 +04:00
const char * path ;
2005-06-03 10:04:34 +04:00
struct messaging_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
2005-06-05 10:53:07 +04:00
static void irpc_handler ( struct messaging_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 .
*/
2009-02-01 01:57:02 +03:00
static void ping_message ( struct messaging_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
{
2007-01-10 13:52:09 +03:00
DEBUG ( 1 , ( " INFO: Received PING message from server %u.%u [%.*s] \n " ,
( uint_t ) src . node , ( uint_t ) src . id , ( int ) data - > length ,
2005-07-17 13:20:52 +04:00
data - > data ? ( const char * ) data - > data : " " ) ) ;
2004-10-27 02:45:33 +04:00
messaging_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 )
{
2009-02-01 02:03:47 +03:00
struct messaging_context * ctx = talloc_get_type ( msg - > private_data , struct messaging_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
*/
2007-01-10 13:52:09 +03:00
static char * messaging_path ( struct messaging_context * msg , struct server_id server_id )
2004-10-17 14:04:49 +04:00
{
2008-02-04 15:04:35 +03:00
return talloc_asprintf ( msg , " %s/msg.%s " , msg - > base_path ,
cluster_id_string ( msg , server_id ) ) ;
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
*/
2004-10-27 02:45:33 +04:00
static void messaging_dispatch ( struct messaging_context * msg , struct messaging_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
*/
2007-02-08 05:59:58 +03:00
static void cluster_message_handler ( struct messaging_context * msg , DATA_BLOB packet )
2007-02-08 03:58:17 +03:00
{
struct messaging_rec * rec ;
rec = talloc ( msg , struct messaging_rec ) ;
if ( rec = = NULL ) {
smb_panic ( " Unable to allocate messaging_rec " ) ;
}
rec - > msg = msg ;
rec - > path = msg - > path ;
rec - > header = ( struct messaging_header * ) packet . data ;
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 ;
}
messaging_dispatch ( msg , rec ) ;
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
*/
2005-06-03 08:21:25 +04:00
static NTSTATUS try_send ( struct messaging_rec * rec )
{
struct messaging_context * msg = rec - > msg ;
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
{
2009-02-01 01:57:02 +03:00
struct messaging_context * msg = talloc_get_type ( private_data ,
2007-05-26 12:47:27 +04:00
struct messaging_context ) ;
msg - > retry_te = NULL ;
/* put the messages back on the main queue */
while ( msg - > retry_queue ) {
struct messaging_rec * rec = msg - > retry_queue ;
DLIST_REMOVE ( msg - > retry_queue , rec ) ;
DLIST_ADD_END ( msg - > pending , rec , struct messaging_rec * ) ;
}
EVENT_FD_WRITEABLE ( msg - > event . fde ) ;
}
2005-06-03 08:21:25 +04:00
/*
handle a socket write event
*/
static void messaging_send_handler ( struct messaging_context * msg )
{
while ( msg - > pending ) {
struct messaging_rec * rec = msg - > pending ;
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 ,
struct messaging_rec * ) ;
if ( msg - > retry_te = = NULL ) {
msg - > retry_te =
event_add_timed ( msg - > event . ev , msg ,
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 ) ) {
2008-02-04 09:51:38 +03:00
DEBUG ( 1 , ( " messaging: Lost message from %s to %s of type %u - %s \n " ,
cluster_id_string ( debug_ctx ( ) , rec - > header - > from ) ,
cluster_id_string ( debug_ctx ( ) , rec - > header - > to ) ,
rec - > header - > msg_type ,
2005-06-03 08:21:25 +04:00
nt_errstr ( status ) ) ) ;
}
DLIST_REMOVE ( msg - > pending , rec ) ;
talloc_free ( rec ) ;
}
if ( msg - > pending = = NULL ) {
EVENT_FD_NOT_WRITEABLE ( msg - > event . fde ) ;
}
}
/*
handle a new incoming packet
*/
static void messaging_recv_handler ( struct messaging_context * msg )
2004-10-17 14:04:49 +04:00
{
2005-05-01 22:49:07 +04:00
struct messaging_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
}
2005-01-27 10:08:20 +03:00
rec = talloc ( msg , struct messaging_rec ) ;
2004-10-17 14:04:49 +04:00
if ( rec = = NULL ) {
smb_panic ( " Unable to allocate messaging_rec " ) ;
}
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 ;
2005-06-03 10:04:34 +04:00
rec - > header = ( struct messaging_header * ) packet . data ;
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 ;
}
messaging_dispatch ( msg , rec ) ;
talloc_free ( rec ) ;
2004-10-17 14:04:49 +04:00
}
2005-06-03 08:21:25 +04:00
/*
handle a socket event
*/
2008-12-29 22:24:57 +03:00
static void messaging_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
{
2009-02-01 01:57:02 +03:00
struct messaging_context * msg = talloc_get_type ( private_data ,
2005-06-03 08:21:25 +04:00
struct messaging_context ) ;
if ( flags & EVENT_FD_WRITE ) {
messaging_send_handler ( msg ) ;
}
if ( flags & EVENT_FD_READ ) {
messaging_recv_handler ( msg ) ;
}
}
2004-10-17 14:04:49 +04:00
/*
Register a dispatch function for a particular message type .
*/
2009-02-01 01:57:02 +03:00
NTSTATUS messaging_register ( struct messaging_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
*/
2009-02-01 01:57:02 +03:00
NTSTATUS messaging_register_tmp ( struct messaging_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 .
*/
2009-02-01 01:57:02 +03:00
void messaging_deregister ( struct messaging_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
*/
2007-01-10 13:52:09 +03:00
NTSTATUS messaging_send ( struct messaging_context * msg , struct server_id server ,
2005-06-03 08:21:25 +04:00
uint32_t msg_type , DATA_BLOB * data )
2004-10-17 14:04:49 +04:00
{
struct messaging_rec * rec ;
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
2005-01-27 10:08:20 +03:00
rec = talloc ( msg , struct messaging_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 ;
rec - > header = ( struct messaging_header * ) rec - > packet . data ;
2008-03-15 14:21:06 +03:00
/* zero padding */
ZERO_STRUCTP ( rec - > header ) ;
2005-06-03 10:04:34 +04:00
rec - > header - > version = MESSAGING_VERSION ;
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 ;
}
2005-06-05 11:37:27 +04:00
rec - > path = messaging_path ( msg , server ) ;
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 ) {
EVENT_FD_WRITEABLE ( msg - > event . fde ) ;
}
2005-06-05 11:30:44 +04:00
DLIST_ADD_END ( msg - > pending , rec , struct messaging_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
*/
2007-01-10 13:52:09 +03:00
NTSTATUS messaging_send_ptr ( struct messaging_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 * ) ;
return messaging_send ( msg , server , msg_type , & blob ) ;
}
2004-10-17 14:04:49 +04:00
/*
destroy the messaging context
*/
2006-05-24 11:34:11 +04:00
static int messaging_destructor ( struct messaging_context * msg )
2004-10-17 14:04:49 +04:00
{
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
*/
2007-01-10 13:52:09 +03:00
struct messaging_context * messaging_init ( TALLOC_CTX * mem_ctx ,
2007-10-01 22:52:55 +04:00
const char * dir ,
2007-01-10 13:52:09 +03:00
struct server_id server_id ,
2007-12-14 01:23:25 +03:00
struct smb_iconv_convenience * iconv_convenience ,
2008-12-29 22:24:57 +03:00
struct tevent_context * ev )
2004-10-17 14:04:49 +04:00
{
2004-10-27 02:45:33 +04:00
struct messaging_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 ;
}
2006-04-12 10:08:24 +04:00
msg = talloc_zero ( mem_ctx , struct messaging_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 ) ;
2006-04-12 10:08:24 +04:00
msg - > path = messaging_path ( msg , server_id ) ;
msg - > server_id = server_id ;
2007-12-14 01:23:25 +03:00
msg - > iconv_convenience = iconv_convenience ;
2006-04-12 10:08:24 +04:00
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 ;
2005-02-03 05:35:52 +03:00
msg - > event . fde = event_add_fd ( ev , msg , socket_get_fd ( msg - > sock ) ,
2005-06-03 08:21:25 +04:00
EVENT_FD_READ , messaging_handler , msg ) ;
2004-10-17 14:04:49 +04:00
talloc_set_destructor ( msg , messaging_destructor ) ;
messaging_register ( msg , NULL , MSG_PING , ping_message ) ;
2005-06-05 10:53:07 +04:00
messaging_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
*/
struct messaging_context * messaging_client_init ( TALLOC_CTX * mem_ctx ,
2007-10-01 22:52:55 +04:00
const char * dir ,
2007-12-14 01:23:25 +03:00
struct smb_iconv_convenience * iconv_convenience ,
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 ) ;
id . id = random ( ) % 0x10000000 ;
2007-12-14 01:23:25 +03:00
return messaging_init ( mem_ctx , dir , id , iconv_convenience , ev ) ;
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
*/
NTSTATUS irpc_register ( struct messaging_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
*/
2005-09-25 17:01:26 +04:00
static void irpc_handler_reply ( struct messaging_context * msg_ctx , struct irpc_message * m )
2005-06-05 10:53:07 +04:00
{
struct irpc_request * irpc ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2005-06-05 10:53:07 +04:00
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 ;
/* parse the reply data */
2007-11-09 21:24:51 +03:00
ndr_err = irpc - > table - > calls [ irpc - > callnum ] . ndr_pull ( m - > ndr , NDR_OUT , irpc - > r ) ;
if ( NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2005-09-25 17:01:26 +04:00
irpc - > status = m - > header . status ;
talloc_steal ( irpc - > mem_ctx , m ) ;
2005-08-01 21:33:43 +04:00
} else {
2007-11-09 21:24:51 +03:00
irpc - > status = ndr_map_error2ntstatus ( ndr_err ) ;
2005-09-25 17:01:26 +04:00
talloc_steal ( irpc , m ) ;
2005-06-05 10:53:07 +04:00
}
2007-08-27 22:43:18 +04:00
irpc - > done = true ;
2005-06-05 10:53:07 +04:00
if ( irpc - > async . fn ) {
irpc - > async . fn ( irpc ) ;
}
}
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 */
2007-12-14 01:23:25 +03:00
push = ndr_push_init_ctx ( m - > ndr , m - > msg_ctx - > iconv_convenience ) ;
2005-09-25 17:01:26 +04:00
if ( push = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto failed ;
}
m - > header . flags | = IRPC_FLAG_REPLY ;
/* 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 ) ;
status = messaging_send ( m - > msg_ctx , m - > from , MSG_IRPC , & packet ) ;
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
*/
static void irpc_handler_request ( struct messaging_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 ;
/* 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 ;
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
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
*/
2009-02-01 01:57:02 +03:00
static void irpc_handler ( struct messaging_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
2007-12-14 01:23:25 +03:00
m - > ndr = ndr_pull_init_blob ( packet , m , msg_ctx - > iconv_convenience ) ;
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 ;
}
if ( irpc - > reject_free ) {
return - 1 ;
}
2005-06-05 10:53:07 +04:00
return 0 ;
}
/*
timeout a irpc request
*/
2008-12-29 22:24:57 +03:00
static void irpc_timeout ( struct tevent_context * ev , struct tevent_timer * te ,
2009-02-01 01:57:02 +03:00
struct timeval t , void * private_data )
2005-06-05 10:53:07 +04:00
{
2009-02-01 01:57:02 +03:00
struct irpc_request * irpc = talloc_get_type ( private_data , struct irpc_request ) ;
2005-06-05 10:53:07 +04:00
irpc - > status = NT_STATUS_IO_TIMEOUT ;
2007-08-27 22:43:18 +04:00
irpc - > done = true ;
2005-06-05 10:53:07 +04:00
if ( irpc - > async . fn ) {
irpc - > async . fn ( irpc ) ;
}
}
/*
make a irpc call - async send
*/
struct irpc_request * irpc_call_send ( struct messaging_context * msg_ctx ,
2007-01-10 13:52:09 +03:00
struct server_id server_id ,
2007-08-20 00:46:45 +04:00
const struct ndr_interface_table * table ,
2005-08-01 21:33:43 +04:00
int callnum , void * r , TALLOC_CTX * ctx )
2005-06-05 10:53:07 +04:00
{
struct irpc_header header ;
struct ndr_push * ndr ;
NTSTATUS status ;
DATA_BLOB packet ;
struct irpc_request * irpc ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2005-06-05 10:53:07 +04:00
irpc = talloc ( msg_ctx , struct irpc_request ) ;
if ( irpc = = NULL ) goto failed ;
irpc - > msg_ctx = msg_ctx ;
irpc - > table = table ;
irpc - > callnum = callnum ;
irpc - > callid = idr_get_new ( msg_ctx - > idr , irpc , UINT16_MAX ) ;
if ( irpc - > callid = = - 1 ) goto failed ;
irpc - > r = r ;
2007-08-27 22:43:18 +04:00
irpc - > done = false ;
2005-06-05 10:53:07 +04:00
irpc - > async . fn = NULL ;
2005-08-01 21:33:43 +04:00
irpc - > mem_ctx = ctx ;
2007-08-27 22:43:18 +04:00
irpc - > reject_free = false ;
2005-06-05 10:53:07 +04:00
talloc_set_destructor ( irpc , irpc_destructor ) ;
/* setup the header */
2006-03-26 04:59:17 +04:00
header . uuid = table - > syntax_id . uuid ;
2005-06-05 10:53:07 +04:00
2006-03-26 04:59:17 +04:00
header . if_version = table - > syntax_id . if_version ;
2005-06-05 10:53:07 +04:00
header . callid = irpc - > callid ;
header . callnum = callnum ;
header . flags = 0 ;
header . status = NT_STATUS_OK ;
/* construct the irpc packet */
2007-12-14 01:23:25 +03:00
ndr = ndr_push_init_ctx ( irpc , msg_ctx - > iconv_convenience ) ;
2005-06-05 10:53:07 +04:00
if ( ndr = = NULL ) goto failed ;
2007-11-09 21:24:51 +03:00
ndr_err = ndr_push_irpc_header ( ndr , NDR_SCALARS | NDR_BUFFERS , & header ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) goto failed ;
2005-06-05 10:53:07 +04:00
2007-11-09 21:24:51 +03:00
ndr_err = table - > calls [ callnum ] . ndr_push ( ndr , NDR_IN , r ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) goto failed ;
2005-06-05 10:53:07 +04:00
/* and send it */
packet = ndr_push_blob ( ndr ) ;
status = messaging_send ( msg_ctx , server_id , MSG_IRPC , & packet ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
event_add_timed ( msg_ctx - > event . ev , irpc ,
timeval_current_ofs ( IRPC_CALL_TIMEOUT , 0 ) ,
irpc_timeout , irpc ) ;
talloc_free ( ndr ) ;
return irpc ;
failed :
talloc_free ( irpc ) ;
return NULL ;
}
/*
wait for a irpc reply
*/
NTSTATUS irpc_call_recv ( struct irpc_request * irpc )
{
2005-12-02 10:30:34 +03:00
NTSTATUS status ;
2005-06-05 10:53:07 +04:00
NT_STATUS_HAVE_NO_MEMORY ( irpc ) ;
2005-12-02 10:30:34 +03:00
2007-05-01 13:55:36 +04:00
irpc - > reject_free = true ;
2005-06-05 10:53:07 +04:00
while ( ! irpc - > done ) {
if ( event_loop_once ( irpc - > msg_ctx - > event . ev ) ! = 0 ) {
return NT_STATUS_CONNECTION_DISCONNECTED ;
2005-12-02 10:30:34 +03:00
}
2005-06-05 10:53:07 +04:00
}
2007-05-01 13:55:36 +04:00
irpc - > reject_free = false ;
2005-12-02 10:30:34 +03:00
status = irpc - > status ;
talloc_free ( irpc ) ;
return status ;
2005-06-05 10:53:07 +04:00
}
/*
perform a synchronous irpc request
*/
NTSTATUS irpc_call ( struct messaging_context * msg_ctx ,
2007-01-10 13:52:09 +03:00
struct server_id server_id ,
2007-08-20 00:46:45 +04:00
const struct ndr_interface_table * table ,
2005-08-01 21:33:43 +04:00
int callnum , void * r ,
TALLOC_CTX * mem_ctx )
2005-06-05 10:53:07 +04:00
{
struct irpc_request * irpc = irpc_call_send ( msg_ctx , server_id ,
2005-08-01 21:33:43 +04:00
table , callnum , r , mem_ctx ) ;
2005-12-02 10:30:34 +03:00
return irpc_call_recv ( irpc ) ;
2005-06-05 10:53:07 +04:00
}
2005-07-10 05:08:10 +04:00
2005-07-10 08:54:21 +04:00
/*
open the naming database
*/
static struct tdb_wrap * irpc_namedb_open ( struct messaging_context * msg_ctx )
{
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
*/
NTSTATUS irpc_add_name ( struct messaging_context * msg_ctx , const char * name )
{
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
*/
2007-05-07 19:19:53 +04:00
struct server_id * irpc_servers_byname ( struct messaging_context * msg_ctx ,
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
*/
void irpc_remove_name ( struct messaging_context * msg_ctx , const char * name )
{
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
struct server_id messaging_get_server_id ( struct messaging_context * msg_ctx )
{
return msg_ctx - > server_id ;
}