2009-01-22 20:39:29 +03:00
/*
* Unix SMB / CIFS implementation .
* RPC client transport over a socket
* Copyright ( C ) Volker Lendecke 2009
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_RPC_CLI
struct rpc_transport_sock_state {
int fd ;
2010-01-06 07:13:35 +03:00
int timeout ;
2009-01-22 20:39:29 +03:00
} ;
2010-03-25 17:00:38 +03:00
static void rpc_sock_disconnect ( struct rpc_transport_sock_state * s )
2009-01-22 20:39:29 +03:00
{
if ( s - > fd ! = - 1 ) {
close ( s - > fd ) ;
s - > fd = - 1 ;
}
2010-03-25 17:00:38 +03:00
}
static int rpc_transport_sock_state_destructor ( struct rpc_transport_sock_state * s )
{
rpc_sock_disconnect ( s ) ;
2009-01-22 20:39:29 +03:00
return 0 ;
}
2010-03-25 17:00:38 +03:00
static bool rpc_sock_is_connected ( void * priv )
{
struct rpc_transport_sock_state * sock_transp = talloc_get_type_abort (
priv , struct rpc_transport_sock_state ) ;
if ( sock_transp - > fd = = - 1 ) {
return false ;
}
return true ;
}
2010-03-25 17:51:51 +03:00
static unsigned int rpc_sock_set_timeout ( void * priv , unsigned int timeout )
{
struct rpc_transport_sock_state * sock_transp = talloc_get_type_abort (
priv , struct rpc_transport_sock_state ) ;
int orig_timeout ;
bool ok ;
ok = rpc_sock_is_connected ( sock_transp ) ;
if ( ! ok ) {
return 0 ;
}
orig_timeout = sock_transp - > timeout ;
sock_transp - > timeout = timeout ;
return orig_timeout ;
}
2009-02-25 14:35:48 +03:00
struct rpc_sock_read_state {
2009-05-18 21:13:36 +04:00
struct rpc_transport_sock_state * transp ;
2009-02-25 14:35:48 +03:00
ssize_t received ;
} ;
static void rpc_sock_read_done ( struct tevent_req * subreq ) ;
2009-03-24 01:03:37 +03:00
static struct tevent_req * rpc_sock_read_send ( TALLOC_CTX * mem_ctx ,
struct event_context * ev ,
uint8_t * data , size_t size ,
void * priv )
2009-01-22 20:39:29 +03:00
{
struct rpc_transport_sock_state * sock_transp = talloc_get_type_abort (
priv , struct rpc_transport_sock_state ) ;
2009-03-24 01:03:37 +03:00
struct tevent_req * req , * subreq ;
2009-02-25 14:35:48 +03:00
struct rpc_sock_read_state * state ;
2010-01-06 07:13:35 +03:00
struct timeval endtime ;
2009-02-25 14:35:48 +03:00
2009-03-24 01:03:37 +03:00
req = tevent_req_create ( mem_ctx , & state , struct rpc_sock_read_state ) ;
if ( req = = NULL ) {
2009-02-25 14:35:48 +03:00
return NULL ;
}
2010-03-25 17:00:38 +03:00
if ( ! rpc_sock_is_connected ( sock_transp ) ) {
2009-05-18 21:13:36 +04:00
tevent_req_nterror ( req , NT_STATUS_CONNECTION_INVALID ) ;
return tevent_req_post ( req , ev ) ;
}
state - > transp = sock_transp ;
2010-01-06 07:13:35 +03:00
endtime = timeval_current_ofs ( 0 , sock_transp - > timeout * 1000 ) ;
2009-02-25 14:35:48 +03:00
subreq = async_recv_send ( state , ev , sock_transp - > fd , data , size , 0 ) ;
if ( subreq = = NULL ) {
goto fail ;
}
2010-01-06 07:13:35 +03:00
if ( ! tevent_req_set_endtime ( subreq , ev , endtime ) ) {
goto fail ;
}
2009-03-24 01:03:37 +03:00
tevent_req_set_callback ( subreq , rpc_sock_read_done , req ) ;
return req ;
2009-02-25 14:35:48 +03:00
fail :
2009-03-24 01:03:37 +03:00
TALLOC_FREE ( req ) ;
2009-02-25 14:35:48 +03:00
return NULL ;
2009-01-22 20:39:29 +03:00
}
2009-02-25 14:35:48 +03:00
static void rpc_sock_read_done ( struct tevent_req * subreq )
2009-01-22 20:39:29 +03:00
{
2009-03-24 01:03:37 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct rpc_sock_read_state * state = tevent_req_data (
req , struct rpc_sock_read_state ) ;
2009-02-25 14:35:48 +03:00
int err ;
2009-01-22 20:39:29 +03:00
2010-02-20 01:18:51 +03:00
/* We must free subreq in this function as there is
a timer event attached to it . */
2009-02-25 14:35:48 +03:00
state - > received = async_recv_recv ( subreq , & err ) ;
2010-02-20 01:18:51 +03:00
2009-02-25 14:35:48 +03:00
if ( state - > received = = - 1 ) {
2010-02-20 01:18:51 +03:00
TALLOC_FREE ( subreq ) ;
2010-03-25 17:00:38 +03:00
rpc_sock_disconnect ( state - > transp ) ;
2009-03-24 01:03:37 +03:00
tevent_req_nterror ( req , map_nt_error_from_unix ( err ) ) ;
2009-02-25 14:35:48 +03:00
return ;
2009-01-22 20:39:29 +03:00
}
2010-02-20 01:18:51 +03:00
TALLOC_FREE ( subreq ) ;
2009-03-24 01:03:37 +03:00
tevent_req_done ( req ) ;
2009-02-25 14:35:48 +03:00
}
2009-03-24 01:03:37 +03:00
static NTSTATUS rpc_sock_read_recv ( struct tevent_req * req , ssize_t * preceived )
2009-02-25 14:35:48 +03:00
{
2009-03-24 01:03:37 +03:00
struct rpc_sock_read_state * state = tevent_req_data (
req , struct rpc_sock_read_state ) ;
2009-02-25 14:35:48 +03:00
NTSTATUS status ;
2009-03-24 01:03:37 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
2009-02-25 14:35:48 +03:00
return status ;
2009-01-22 20:39:29 +03:00
}
2009-02-25 14:35:48 +03:00
* preceived = state - > received ;
2009-01-22 20:39:29 +03:00
return NT_STATUS_OK ;
}
2009-02-25 14:44:26 +03:00
struct rpc_sock_write_state {
2009-05-18 21:13:36 +04:00
struct rpc_transport_sock_state * transp ;
2009-02-25 14:44:26 +03:00
ssize_t sent ;
} ;
static void rpc_sock_write_done ( struct tevent_req * subreq ) ;
2009-03-24 01:20:03 +03:00
static struct tevent_req * rpc_sock_write_send ( TALLOC_CTX * mem_ctx ,
struct event_context * ev ,
const uint8_t * data , size_t size ,
void * priv )
2009-01-22 20:39:29 +03:00
{
struct rpc_transport_sock_state * sock_transp = talloc_get_type_abort (
priv , struct rpc_transport_sock_state ) ;
2009-03-24 01:20:03 +03:00
struct tevent_req * req , * subreq ;
2009-02-25 14:44:26 +03:00
struct rpc_sock_write_state * state ;
2010-01-06 07:13:35 +03:00
struct timeval endtime ;
2009-02-25 14:44:26 +03:00
2009-03-24 01:20:03 +03:00
req = tevent_req_create ( mem_ctx , & state , struct rpc_sock_write_state ) ;
if ( req = = NULL ) {
2009-02-25 14:44:26 +03:00
return NULL ;
}
2010-03-25 17:00:38 +03:00
if ( ! rpc_sock_is_connected ( sock_transp ) ) {
2009-05-18 21:13:36 +04:00
tevent_req_nterror ( req , NT_STATUS_CONNECTION_INVALID ) ;
return tevent_req_post ( req , ev ) ;
}
state - > transp = sock_transp ;
2010-01-06 07:13:35 +03:00
endtime = timeval_current_ofs ( 0 , sock_transp - > timeout * 1000 ) ;
2009-02-25 14:44:26 +03:00
subreq = async_send_send ( state , ev , sock_transp - > fd , data , size , 0 ) ;
if ( subreq = = NULL ) {
goto fail ;
}
2010-01-06 07:13:35 +03:00
if ( ! tevent_req_set_endtime ( subreq , ev , endtime ) ) {
goto fail ;
}
2009-03-24 01:20:03 +03:00
tevent_req_set_callback ( subreq , rpc_sock_write_done , req ) ;
return req ;
2009-02-25 14:44:26 +03:00
fail :
2009-03-24 01:20:03 +03:00
TALLOC_FREE ( req ) ;
2009-02-25 14:44:26 +03:00
return NULL ;
}
static void rpc_sock_write_done ( struct tevent_req * subreq )
{
2009-03-24 01:20:03 +03:00
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct rpc_sock_write_state * state = tevent_req_data (
req , struct rpc_sock_write_state ) ;
2009-02-25 14:44:26 +03:00
int err ;
2010-02-20 01:18:51 +03:00
/* We must free subreq in this function as there is
a timer event attached to it . */
2009-02-25 14:44:26 +03:00
state - > sent = async_send_recv ( subreq , & err ) ;
2010-02-20 01:18:51 +03:00
2009-02-25 14:44:26 +03:00
if ( state - > sent = = - 1 ) {
2010-02-20 01:18:51 +03:00
TALLOC_FREE ( subreq ) ;
2010-03-25 17:00:38 +03:00
rpc_sock_disconnect ( state - > transp ) ;
2009-03-24 01:20:03 +03:00
tevent_req_nterror ( req , map_nt_error_from_unix ( err ) ) ;
2009-02-25 14:44:26 +03:00
return ;
}
2010-02-20 01:18:51 +03:00
TALLOC_FREE ( subreq ) ;
2009-03-24 01:20:03 +03:00
tevent_req_done ( req ) ;
2009-01-22 20:39:29 +03:00
}
2009-03-24 01:20:03 +03:00
static NTSTATUS rpc_sock_write_recv ( struct tevent_req * req , ssize_t * psent )
2009-01-22 20:39:29 +03:00
{
2009-03-24 01:20:03 +03:00
struct rpc_sock_write_state * state = tevent_req_data (
req , struct rpc_sock_write_state ) ;
2009-02-25 14:44:26 +03:00
NTSTATUS status ;
2009-01-22 20:39:29 +03:00
2009-03-24 01:20:03 +03:00
if ( tevent_req_is_nterror ( req , & status ) ) {
2009-02-25 14:44:26 +03:00
return status ;
2009-01-22 20:39:29 +03:00
}
2009-02-25 14:44:26 +03:00
* psent = state - > sent ;
2009-01-22 20:39:29 +03:00
return NT_STATUS_OK ;
}
NTSTATUS rpc_transport_sock_init ( TALLOC_CTX * mem_ctx , int fd ,
struct rpc_cli_transport * * presult )
{
struct rpc_cli_transport * result ;
struct rpc_transport_sock_state * state ;
result = talloc ( mem_ctx , struct rpc_cli_transport ) ;
if ( result = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
state = talloc ( result , struct rpc_transport_sock_state ) ;
if ( state = = NULL ) {
TALLOC_FREE ( result ) ;
return NT_STATUS_NO_MEMORY ;
}
result - > priv = state ;
state - > fd = fd ;
2010-01-06 07:13:35 +03:00
state - > timeout = 10000 ; /* 10 seconds. */
2009-01-22 20:39:29 +03:00
talloc_set_destructor ( state , rpc_transport_sock_state_destructor ) ;
result - > trans_send = NULL ;
result - > trans_recv = NULL ;
result - > write_send = rpc_sock_write_send ;
result - > write_recv = rpc_sock_write_recv ;
result - > read_send = rpc_sock_read_send ;
result - > read_recv = rpc_sock_read_recv ;
2010-03-25 17:00:38 +03:00
result - > is_connected = rpc_sock_is_connected ;
2010-03-25 17:51:51 +03:00
result - > set_timeout = rpc_sock_set_timeout ;
2009-01-22 20:39:29 +03:00
* presult = result ;
return NT_STATUS_OK ;
}