2009-02-18 11:10:54 +03:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Stefan Metzmacher 2009
2009-12-15 14:56:44 +03:00
* * NOTE ! The following LGPL license applies to the tsocket
2009-02-18 11:10:54 +03:00
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
version 3 of the License , or ( at your option ) any later version .
This library 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "replace.h"
2009-04-03 20:08:10 +04:00
# include "system/filesys.h"
2009-02-18 11:10:54 +03:00
# include "tsocket.h"
# include "tsocket_internal.h"
2009-04-03 19:54:08 +04:00
int tsocket_simple_int_recv ( struct tevent_req * req , int * perrno )
{
enum tevent_req_state state ;
uint64_t error ;
if ( ! tevent_req_is_error ( req , & state , & error ) ) {
return 0 ;
}
switch ( state ) {
case TEVENT_REQ_NO_MEMORY :
* perrno = ENOMEM ;
return - 1 ;
case TEVENT_REQ_TIMED_OUT :
* perrno = ETIMEDOUT ;
return - 1 ;
case TEVENT_REQ_USER_ERROR :
* perrno = ( int ) error ;
return - 1 ;
default :
2010-05-23 01:44:01 +04:00
break ;
2009-04-03 19:54:08 +04:00
}
* perrno = EIO ;
return - 1 ;
}
2009-02-18 11:10:54 +03:00
struct tsocket_address * _tsocket_address_create ( TALLOC_CTX * mem_ctx ,
const struct tsocket_address_ops * ops ,
void * pstate ,
size_t psize ,
const char * type ,
const char * location )
{
void * * ppstate = ( void * * ) pstate ;
struct tsocket_address * addr ;
addr = talloc_zero ( mem_ctx , struct tsocket_address ) ;
if ( ! addr ) {
return NULL ;
}
addr - > ops = ops ;
addr - > location = location ;
addr - > private_data = talloc_size ( addr , psize ) ;
if ( ! addr - > private_data ) {
talloc_free ( addr ) ;
return NULL ;
}
talloc_set_name_const ( addr - > private_data , type ) ;
* ppstate = addr - > private_data ;
return addr ;
}
char * tsocket_address_string ( const struct tsocket_address * addr ,
TALLOC_CTX * mem_ctx )
{
if ( ! addr ) {
return talloc_strdup ( mem_ctx , " NULL " ) ;
}
return addr - > ops - > string ( addr , mem_ctx ) ;
}
struct tsocket_address * _tsocket_address_copy ( const struct tsocket_address * addr ,
TALLOC_CTX * mem_ctx ,
const char * location )
{
return addr - > ops - > copy ( addr , mem_ctx , location ) ;
}
2009-03-26 16:27:45 +03:00
struct tdgram_context {
const char * location ;
const struct tdgram_context_ops * ops ;
void * private_data ;
2009-04-14 12:44:25 +04:00
struct tevent_req * recvfrom_req ;
struct tevent_req * sendto_req ;
2009-03-26 16:27:45 +03:00
} ;
2009-04-14 12:44:25 +04:00
static int tdgram_context_destructor ( struct tdgram_context * dgram )
{
if ( dgram - > recvfrom_req ) {
tevent_req_received ( dgram - > recvfrom_req ) ;
}
if ( dgram - > sendto_req ) {
tevent_req_received ( dgram - > sendto_req ) ;
}
return 0 ;
}
2009-03-26 16:27:45 +03:00
struct tdgram_context * _tdgram_context_create ( TALLOC_CTX * mem_ctx ,
const struct tdgram_context_ops * ops ,
void * pstate ,
size_t psize ,
const char * type ,
const char * location )
{
struct tdgram_context * dgram ;
void * * ppstate = ( void * * ) pstate ;
void * state ;
dgram = talloc ( mem_ctx , struct tdgram_context ) ;
if ( dgram = = NULL ) {
return NULL ;
}
2009-04-14 12:44:25 +04:00
dgram - > location = location ;
dgram - > ops = ops ;
dgram - > recvfrom_req = NULL ;
dgram - > sendto_req = NULL ;
2009-03-26 16:27:45 +03:00
state = talloc_size ( dgram , psize ) ;
if ( state = = NULL ) {
talloc_free ( dgram ) ;
return NULL ;
}
talloc_set_name_const ( state , type ) ;
dgram - > private_data = state ;
2009-04-14 12:44:25 +04:00
talloc_set_destructor ( dgram , tdgram_context_destructor ) ;
2009-03-26 16:27:45 +03:00
* ppstate = state ;
return dgram ;
}
void * _tdgram_context_data ( struct tdgram_context * dgram )
{
return dgram - > private_data ;
}
struct tdgram_recvfrom_state {
const struct tdgram_context_ops * ops ;
2009-04-14 12:44:25 +04:00
struct tdgram_context * dgram ;
2009-03-26 16:27:45 +03:00
uint8_t * buf ;
size_t len ;
struct tsocket_address * src ;
} ;
2009-04-14 12:44:25 +04:00
static int tdgram_recvfrom_destructor ( struct tdgram_recvfrom_state * state )
{
if ( state - > dgram ) {
state - > dgram - > recvfrom_req = NULL ;
}
return 0 ;
}
2009-03-26 16:27:45 +03:00
static void tdgram_recvfrom_done ( struct tevent_req * subreq ) ;
struct tevent_req * tdgram_recvfrom_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tdgram_context * dgram )
{
struct tevent_req * req ;
struct tdgram_recvfrom_state * state ;
struct tevent_req * subreq ;
req = tevent_req_create ( mem_ctx , & state ,
struct tdgram_recvfrom_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ops = dgram - > ops ;
2009-04-14 12:44:25 +04:00
state - > dgram = dgram ;
state - > buf = NULL ;
state - > len = 0 ;
state - > src = NULL ;
if ( dgram - > recvfrom_req ) {
tevent_req_error ( req , EBUSY ) ;
goto post ;
}
dgram - > recvfrom_req = req ;
talloc_set_destructor ( state , tdgram_recvfrom_destructor ) ;
2009-03-26 16:27:45 +03:00
subreq = state - > ops - > recvfrom_send ( state , ev , dgram ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
goto post ;
}
tevent_req_set_callback ( subreq , tdgram_recvfrom_done , req ) ;
return req ;
post :
tevent_req_post ( req , ev ) ;
return req ;
}
static void tdgram_recvfrom_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct tdgram_recvfrom_state * state = tevent_req_data ( req ,
struct tdgram_recvfrom_state ) ;
ssize_t ret ;
int sys_errno ;
ret = state - > ops - > recvfrom_recv ( subreq , & sys_errno , state ,
& state - > buf , & state - > src ) ;
if ( ret = = - 1 ) {
tevent_req_error ( req , sys_errno ) ;
return ;
}
state - > len = ret ;
tevent_req_done ( req ) ;
}
ssize_t tdgram_recvfrom_recv ( struct tevent_req * req ,
int * perrno ,
TALLOC_CTX * mem_ctx ,
uint8_t * * buf ,
struct tsocket_address * * src )
{
struct tdgram_recvfrom_state * state = tevent_req_data ( req ,
struct tdgram_recvfrom_state ) ;
ssize_t ret ;
ret = tsocket_simple_int_recv ( req , perrno ) ;
if ( ret = = 0 ) {
* buf = talloc_move ( mem_ctx , & state - > buf ) ;
ret = state - > len ;
if ( src ) {
* src = talloc_move ( mem_ctx , & state - > src ) ;
}
}
tevent_req_received ( req ) ;
return ret ;
}
struct tdgram_sendto_state {
const struct tdgram_context_ops * ops ;
2009-04-14 12:44:25 +04:00
struct tdgram_context * dgram ;
2009-03-26 16:27:45 +03:00
ssize_t ret ;
} ;
2009-04-14 12:44:25 +04:00
static int tdgram_sendto_destructor ( struct tdgram_sendto_state * state )
{
if ( state - > dgram ) {
state - > dgram - > sendto_req = NULL ;
}
return 0 ;
}
2009-03-26 16:27:45 +03:00
static void tdgram_sendto_done ( struct tevent_req * subreq ) ;
struct tevent_req * tdgram_sendto_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tdgram_context * dgram ,
const uint8_t * buf , size_t len ,
const struct tsocket_address * dst )
{
struct tevent_req * req ;
struct tdgram_sendto_state * state ;
struct tevent_req * subreq ;
req = tevent_req_create ( mem_ctx , & state ,
struct tdgram_sendto_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ops = dgram - > ops ;
2009-04-14 12:44:25 +04:00
state - > dgram = dgram ;
2009-03-26 16:27:45 +03:00
state - > ret = - 1 ;
2009-04-10 22:35:12 +04:00
if ( len = = 0 ) {
tevent_req_error ( req , EINVAL ) ;
goto post ;
}
2009-04-14 12:44:25 +04:00
if ( dgram - > sendto_req ) {
tevent_req_error ( req , EBUSY ) ;
goto post ;
}
dgram - > sendto_req = req ;
talloc_set_destructor ( state , tdgram_sendto_destructor ) ;
2009-03-26 16:27:45 +03:00
subreq = state - > ops - > sendto_send ( state , ev , dgram ,
buf , len , dst ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
goto post ;
}
tevent_req_set_callback ( subreq , tdgram_sendto_done , req ) ;
return req ;
post :
tevent_req_post ( req , ev ) ;
return req ;
}
static void tdgram_sendto_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct tdgram_sendto_state * state = tevent_req_data ( req ,
struct tdgram_sendto_state ) ;
ssize_t ret ;
int sys_errno ;
ret = state - > ops - > sendto_recv ( subreq , & sys_errno ) ;
if ( ret = = - 1 ) {
tevent_req_error ( req , sys_errno ) ;
return ;
}
state - > ret = ret ;
tevent_req_done ( req ) ;
}
ssize_t tdgram_sendto_recv ( struct tevent_req * req ,
int * perrno )
{
struct tdgram_sendto_state * state = tevent_req_data ( req ,
struct tdgram_sendto_state ) ;
ssize_t ret ;
ret = tsocket_simple_int_recv ( req , perrno ) ;
if ( ret = = 0 ) {
ret = state - > ret ;
}
tevent_req_received ( req ) ;
return ret ;
}
struct tdgram_disconnect_state {
const struct tdgram_context_ops * ops ;
} ;
static void tdgram_disconnect_done ( struct tevent_req * subreq ) ;
struct tevent_req * tdgram_disconnect_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tdgram_context * dgram )
{
struct tevent_req * req ;
struct tdgram_disconnect_state * state ;
struct tevent_req * subreq ;
req = tevent_req_create ( mem_ctx , & state ,
struct tdgram_disconnect_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ops = dgram - > ops ;
2009-04-14 12:44:25 +04:00
if ( dgram - > recvfrom_req | | dgram - > sendto_req ) {
tevent_req_error ( req , EBUSY ) ;
goto post ;
}
2009-03-26 16:27:45 +03:00
subreq = state - > ops - > disconnect_send ( state , ev , dgram ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
goto post ;
}
tevent_req_set_callback ( subreq , tdgram_disconnect_done , req ) ;
return req ;
post :
tevent_req_post ( req , ev ) ;
return req ;
}
static void tdgram_disconnect_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct tdgram_disconnect_state * state = tevent_req_data ( req ,
struct tdgram_disconnect_state ) ;
int ret ;
int sys_errno ;
ret = state - > ops - > disconnect_recv ( subreq , & sys_errno ) ;
if ( ret = = - 1 ) {
tevent_req_error ( req , sys_errno ) ;
return ;
}
tevent_req_done ( req ) ;
}
int tdgram_disconnect_recv ( struct tevent_req * req ,
int * perrno )
{
int ret ;
ret = tsocket_simple_int_recv ( req , perrno ) ;
tevent_req_received ( req ) ;
return ret ;
}
2009-04-03 20:08:10 +04:00
struct tstream_context {
const char * location ;
const struct tstream_context_ops * ops ;
void * private_data ;
struct tevent_req * readv_req ;
struct tevent_req * writev_req ;
} ;
static int tstream_context_destructor ( struct tstream_context * stream )
{
if ( stream - > readv_req ) {
tevent_req_received ( stream - > readv_req ) ;
}
if ( stream - > writev_req ) {
tevent_req_received ( stream - > writev_req ) ;
}
return 0 ;
}
struct tstream_context * _tstream_context_create ( TALLOC_CTX * mem_ctx ,
const struct tstream_context_ops * ops ,
void * pstate ,
size_t psize ,
const char * type ,
const char * location )
{
struct tstream_context * stream ;
void * * ppstate = ( void * * ) pstate ;
void * state ;
stream = talloc ( mem_ctx , struct tstream_context ) ;
if ( stream = = NULL ) {
return NULL ;
}
stream - > location = location ;
stream - > ops = ops ;
stream - > readv_req = NULL ;
stream - > writev_req = NULL ;
state = talloc_size ( stream , psize ) ;
if ( state = = NULL ) {
talloc_free ( stream ) ;
return NULL ;
}
talloc_set_name_const ( state , type ) ;
stream - > private_data = state ;
talloc_set_destructor ( stream , tstream_context_destructor ) ;
* ppstate = state ;
return stream ;
}
void * _tstream_context_data ( struct tstream_context * stream )
{
return stream - > private_data ;
}
ssize_t tstream_pending_bytes ( struct tstream_context * stream )
{
return stream - > ops - > pending_bytes ( stream ) ;
}
struct tstream_readv_state {
const struct tstream_context_ops * ops ;
struct tstream_context * stream ;
int ret ;
} ;
static int tstream_readv_destructor ( struct tstream_readv_state * state )
{
if ( state - > stream ) {
state - > stream - > readv_req = NULL ;
}
return 0 ;
}
static void tstream_readv_done ( struct tevent_req * subreq ) ;
struct tevent_req * tstream_readv_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tstream_context * stream ,
struct iovec * vector ,
size_t count )
{
struct tevent_req * req ;
struct tstream_readv_state * state ;
struct tevent_req * subreq ;
int to_read = 0 ;
size_t i ;
req = tevent_req_create ( mem_ctx , & state ,
struct tstream_readv_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ops = stream - > ops ;
state - > stream = stream ;
state - > ret = - 1 ;
/* first check if the input is ok */
2009-06-09 08:54:15 +04:00
# ifdef IOV_MAX
2009-04-03 20:08:10 +04:00
if ( count > IOV_MAX ) {
tevent_req_error ( req , EMSGSIZE ) ;
goto post ;
}
2009-06-09 08:54:15 +04:00
# endif
2009-04-03 20:08:10 +04:00
for ( i = 0 ; i < count ; i + + ) {
int tmp = to_read ;
tmp + = vector [ i ] . iov_len ;
if ( tmp < to_read ) {
tevent_req_error ( req , EMSGSIZE ) ;
goto post ;
}
to_read = tmp ;
}
if ( to_read = = 0 ) {
tevent_req_error ( req , EINVAL ) ;
goto post ;
}
if ( stream - > readv_req ) {
tevent_req_error ( req , EBUSY ) ;
goto post ;
}
stream - > readv_req = req ;
talloc_set_destructor ( state , tstream_readv_destructor ) ;
subreq = state - > ops - > readv_send ( state , ev , stream , vector , count ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
goto post ;
}
tevent_req_set_callback ( subreq , tstream_readv_done , req ) ;
return req ;
post :
tevent_req_post ( req , ev ) ;
return req ;
}
static void tstream_readv_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct tstream_readv_state * state = tevent_req_data ( req ,
struct tstream_readv_state ) ;
ssize_t ret ;
int sys_errno ;
ret = state - > ops - > readv_recv ( subreq , & sys_errno ) ;
2009-06-27 22:04:37 +04:00
TALLOC_FREE ( subreq ) ;
2009-04-03 20:08:10 +04:00
if ( ret = = - 1 ) {
tevent_req_error ( req , sys_errno ) ;
return ;
}
state - > ret = ret ;
tevent_req_done ( req ) ;
}
int tstream_readv_recv ( struct tevent_req * req ,
int * perrno )
{
struct tstream_readv_state * state = tevent_req_data ( req ,
struct tstream_readv_state ) ;
int ret ;
ret = tsocket_simple_int_recv ( req , perrno ) ;
if ( ret = = 0 ) {
ret = state - > ret ;
}
tevent_req_received ( req ) ;
return ret ;
}
struct tstream_writev_state {
const struct tstream_context_ops * ops ;
struct tstream_context * stream ;
int ret ;
} ;
static int tstream_writev_destructor ( struct tstream_writev_state * state )
{
if ( state - > stream ) {
state - > stream - > writev_req = NULL ;
}
return 0 ;
}
static void tstream_writev_done ( struct tevent_req * subreq ) ;
struct tevent_req * tstream_writev_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tstream_context * stream ,
const struct iovec * vector ,
size_t count )
{
struct tevent_req * req ;
struct tstream_writev_state * state ;
struct tevent_req * subreq ;
int to_write = 0 ;
size_t i ;
req = tevent_req_create ( mem_ctx , & state ,
struct tstream_writev_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ops = stream - > ops ;
state - > stream = stream ;
state - > ret = - 1 ;
/* first check if the input is ok */
2009-06-09 08:54:15 +04:00
# ifdef IOV_MAX
2009-04-03 20:08:10 +04:00
if ( count > IOV_MAX ) {
tevent_req_error ( req , EMSGSIZE ) ;
goto post ;
}
2009-06-09 08:54:15 +04:00
# endif
2009-04-03 20:08:10 +04:00
for ( i = 0 ; i < count ; i + + ) {
int tmp = to_write ;
tmp + = vector [ i ] . iov_len ;
if ( tmp < to_write ) {
tevent_req_error ( req , EMSGSIZE ) ;
goto post ;
}
to_write = tmp ;
}
if ( to_write = = 0 ) {
tevent_req_error ( req , EINVAL ) ;
goto post ;
}
if ( stream - > writev_req ) {
tevent_req_error ( req , EBUSY ) ;
goto post ;
}
stream - > writev_req = req ;
talloc_set_destructor ( state , tstream_writev_destructor ) ;
subreq = state - > ops - > writev_send ( state , ev , stream , vector , count ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
goto post ;
}
tevent_req_set_callback ( subreq , tstream_writev_done , req ) ;
return req ;
post :
tevent_req_post ( req , ev ) ;
return req ;
}
static void tstream_writev_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct tstream_writev_state * state = tevent_req_data ( req ,
struct tstream_writev_state ) ;
ssize_t ret ;
int sys_errno ;
ret = state - > ops - > writev_recv ( subreq , & sys_errno ) ;
if ( ret = = - 1 ) {
tevent_req_error ( req , sys_errno ) ;
return ;
}
state - > ret = ret ;
tevent_req_done ( req ) ;
}
int tstream_writev_recv ( struct tevent_req * req ,
int * perrno )
{
struct tstream_writev_state * state = tevent_req_data ( req ,
struct tstream_writev_state ) ;
int ret ;
ret = tsocket_simple_int_recv ( req , perrno ) ;
if ( ret = = 0 ) {
ret = state - > ret ;
}
tevent_req_received ( req ) ;
return ret ;
}
struct tstream_disconnect_state {
const struct tstream_context_ops * ops ;
} ;
static void tstream_disconnect_done ( struct tevent_req * subreq ) ;
struct tevent_req * tstream_disconnect_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct tstream_context * stream )
{
struct tevent_req * req ;
struct tstream_disconnect_state * state ;
struct tevent_req * subreq ;
req = tevent_req_create ( mem_ctx , & state ,
struct tstream_disconnect_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ops = stream - > ops ;
if ( stream - > readv_req | | stream - > writev_req ) {
tevent_req_error ( req , EBUSY ) ;
goto post ;
}
subreq = state - > ops - > disconnect_send ( state , ev , stream ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
goto post ;
}
tevent_req_set_callback ( subreq , tstream_disconnect_done , req ) ;
return req ;
post :
tevent_req_post ( req , ev ) ;
return req ;
}
static void tstream_disconnect_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct tstream_disconnect_state * state = tevent_req_data ( req ,
struct tstream_disconnect_state ) ;
int ret ;
int sys_errno ;
ret = state - > ops - > disconnect_recv ( subreq , & sys_errno ) ;
if ( ret = = - 1 ) {
tevent_req_error ( req , sys_errno ) ;
return ;
}
tevent_req_done ( req ) ;
}
int tstream_disconnect_recv ( struct tevent_req * req ,
int * perrno )
{
int ret ;
ret = tsocket_simple_int_recv ( req , perrno ) ;
tevent_req_received ( req ) ;
return ret ;
}