2008-08-08 20:30:57 +04:00
/*
Unix SMB / CIFS implementation .
async socket syscalls
Copyright ( C ) Volker Lendecke 2008
2009-05-29 16:14:50 +04:00
* * NOTE ! The following LGPL license applies to the async_sock
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
2008-08-08 20:30:57 +04:00
2009-05-29 16:14:50 +04:00
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 ,
2008-08-08 20:30:57 +04:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2009-05-29 16:14:50 +04:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Library General Public License for more details .
2008-08-08 20:30:57 +04:00
2009-05-29 16:14:50 +04:00
You should have received a copy of the GNU Lesser General Public License
2008-08-08 20:30:57 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2009-06-08 10:15:57 +04:00
# include "replace.h"
# include "system/network.h"
# include "system/filesys.h"
# include <talloc.h>
# include <tevent.h>
2009-01-24 12:00:13 +03:00
# include "lib/async_req/async_sock.h"
2015-02-14 18:48:54 +03:00
# include "lib/util/iov_buf.h"
2021-01-11 17:58:58 +03:00
# include "lib/util/util_net.h"
2009-06-08 10:15:57 +04:00
/* Note: lib/util/ is currently GPL */
2009-02-22 21:49:18 +03:00
# include "lib/util/tevent_unix.h"
2011-09-21 01:26:36 +04:00
# include "lib/util/samba_util.h"
2009-01-24 12:00:13 +03:00
2009-01-04 02:26:49 +03:00
struct async_connect_state {
int fd ;
2015-05-21 23:28:14 +03:00
struct tevent_fd * fde ;
2009-01-04 02:26:49 +03:00
int result ;
long old_sockflags ;
2009-05-24 15:14:12 +04:00
socklen_t address_len ;
struct sockaddr_storage address ;
2013-05-16 18:11:54 +04:00
void ( * before_connect ) ( void * private_data ) ;
void ( * after_connect ) ( void * private_data ) ;
void * private_data ;
2009-01-04 02:26:49 +03:00
} ;
2008-08-08 20:30:57 +04:00
2015-05-21 23:28:14 +03:00
static void async_connect_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state ) ;
2009-01-24 12:00:13 +03:00
static void async_connect_connected ( struct tevent_context * ev ,
struct tevent_fd * fde , uint16_t flags ,
2009-01-04 02:26:49 +03:00
void * priv ) ;
2008-08-08 20:30:57 +04:00
/**
* @ brief async version of connect ( 2 )
* @ param [ in ] mem_ctx The memory context to hang the result off
* @ param [ in ] ev The event context to work from
* @ param [ in ] fd The socket to recv from
* @ param [ in ] address Where to connect ?
* @ param [ in ] address_len Length of * address
* @ retval The async request
*
* This function sets the socket into non - blocking state to be able to call
* connect in an async state . This will be reset when the request is finished .
*/
2013-05-16 18:11:54 +04:00
struct tevent_req * async_connect_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev , int fd ,
const struct sockaddr * address , socklen_t address_len ,
void ( * before_connect ) ( void * private_data ) ,
void ( * after_connect ) ( void * private_data ) ,
void * private_data )
2008-08-08 20:30:57 +04:00
{
2015-06-05 14:58:19 +03:00
struct tevent_req * req ;
2009-01-04 02:26:49 +03:00
struct async_connect_state * state ;
2015-06-23 11:18:31 +03:00
int ret ;
2008-08-08 20:30:57 +04:00
2015-06-05 14:58:19 +03:00
req = tevent_req_create ( mem_ctx , & state , struct async_connect_state ) ;
if ( req = = NULL ) {
2008-08-08 20:30:57 +04:00
return NULL ;
}
/**
* We have to set the socket to nonblocking for async connect ( 2 ) . Keep
* the old sockflags around .
*/
2009-01-04 02:26:49 +03:00
state - > fd = fd ;
2013-05-16 18:11:54 +04:00
state - > before_connect = before_connect ;
state - > after_connect = after_connect ;
state - > private_data = private_data ;
2008-08-08 20:30:57 +04:00
2009-06-06 02:46:38 +04:00
state - > old_sockflags = fcntl ( fd , F_GETFL , 0 ) ;
if ( state - > old_sockflags = = - 1 ) {
2015-05-21 23:28:14 +03:00
tevent_req_error ( req , errno ) ;
return tevent_req_post ( req , ev ) ;
2009-06-06 02:46:38 +04:00
}
2015-05-21 23:28:14 +03:00
tevent_req_set_cleanup_fn ( req , async_connect_cleanup ) ;
2009-05-24 15:14:12 +04:00
state - > address_len = address_len ;
if ( address_len > sizeof ( state - > address ) ) {
2015-05-21 23:28:14 +03:00
tevent_req_error ( req , EINVAL ) ;
return tevent_req_post ( req , ev ) ;
2009-05-24 15:14:12 +04:00
}
memcpy ( & state - > address , address , address_len ) ;
2015-06-23 11:18:31 +03:00
ret = set_blocking ( fd , false ) ;
if ( ret = = - 1 ) {
tevent_req_error ( req , errno ) ;
return tevent_req_post ( req , ev ) ;
}
2008-08-08 20:30:57 +04:00
2013-05-16 18:11:54 +04:00
if ( state - > before_connect ! = NULL ) {
state - > before_connect ( state - > private_data ) ;
}
2009-01-04 02:26:49 +03:00
state - > result = connect ( fd , address , address_len ) ;
2013-05-16 18:11:54 +04:00
if ( state - > after_connect ! = NULL ) {
state - > after_connect ( state - > private_data ) ;
}
2009-01-04 02:26:49 +03:00
if ( state - > result = = 0 ) {
2015-06-05 14:58:19 +03:00
tevent_req_done ( req ) ;
2015-05-21 23:28:14 +03:00
return tevent_req_post ( req , ev ) ;
2008-08-08 20:30:57 +04:00
}
async_req: fix non-blocking connect()
According to Stevens UNIX Network Programming and various other sources,
the correct handling for non-blocking connect() is:
- when the initial connect() return -1/EINPROGRESS polling the socket
for *writeability*
- in the poll handler call getsocktopt() with SO_ERROR to get the
finished connect() return value
Simply calling connect() a second time without error checking is
probably wrong and not portable. For a successfull connect() Linux
returns 0, but Solaris will return EISCONN:
24254: 0.0336 0.0002 connect(4, 0xFEFFECAC, 16, SOV_DEFAULT) Err#150 EINPROGRESS
24254: AF_INET name = 10.10.10.143 port = 1024
24254: 0.0349 0.0001 port_associate(3, 4, 0x00000004, 0x0000001D,0x080648A8) = 0
24254: 0.0495 0.0146 port_getn(3, 0xFEFFEB50, 1, 1, 0xFEFFEB60) = 1 [0]
24254: 0.0497 0.0002 connect(4, 0x080646E4, 16, SOV_DEFAULT) Err#133 EISCONN
24254: AF_INET name = 10.10.10.143 port = 1024
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11564
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
2015-10-18 23:21:10 +03:00
/*
2016-08-03 16:00:45 +03:00
* The only errno indicating that an initial connect is still
* in flight is EINPROGRESS .
*
* This allows callers like open_socket_out_send ( ) to reuse
* fds and call us with an fd for which the connect is still
* in flight . The proper thing to do for callers would be
* closing the fd and starting from scratch with a fresh
* socket .
2008-08-08 20:30:57 +04:00
*/
2020-02-26 16:16:05 +03:00
if ( errno ! = EINPROGRESS ) {
2015-05-21 23:28:14 +03:00
tevent_req_error ( req , errno ) ;
return tevent_req_post ( req , ev ) ;
2009-01-04 02:26:49 +03:00
}
2008-08-08 20:30:57 +04:00
2019-10-02 17:56:30 +03:00
/*
* Note for historic reasons TEVENT_FD_WRITE is not enough
* to get notified for POLLERR or EPOLLHUP even if they
* come together with POLLOUT . That means we need to
* use TEVENT_FD_READ in addition until we have
* TEVENT_FD_ERROR .
*/
state - > fde = tevent_add_fd ( ev , state , fd , TEVENT_FD_READ | TEVENT_FD_WRITE ,
2015-05-21 23:28:14 +03:00
async_connect_connected , req ) ;
if ( state - > fde = = NULL ) {
tevent_req_error ( req , ENOMEM ) ;
return tevent_req_post ( req , ev ) ;
2008-08-08 20:30:57 +04:00
}
2015-06-05 14:58:19 +03:00
return req ;
2015-05-21 23:28:14 +03:00
}
static void async_connect_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
{
struct async_connect_state * state =
tevent_req_data ( req , struct async_connect_state ) ;
2008-08-08 20:30:57 +04:00
2015-05-21 23:28:14 +03:00
TALLOC_FREE ( state - > fde ) ;
if ( state - > fd ! = - 1 ) {
2015-06-16 09:20:56 +03:00
int ret ;
ret = fcntl ( state - > fd , F_SETFL , state - > old_sockflags ) ;
if ( ret = = - 1 ) {
abort ( ) ;
}
2015-05-21 23:28:14 +03:00
state - > fd = - 1 ;
}
2009-01-04 02:26:49 +03:00
}
2008-08-08 20:30:57 +04:00
2009-01-04 02:26:49 +03:00
/**
* fde event handler for connect ( 2 )
* @ param [ in ] ev The event context that sent us here
* @ param [ in ] fde The file descriptor event associated with the connect
* @ param [ in ] flags Indicate read / writeability of the socket
* @ param [ in ] priv private data , " struct async_req * " in this case
*/
2008-08-08 20:30:57 +04:00
2009-01-24 12:00:13 +03:00
static void async_connect_connected ( struct tevent_context * ev ,
struct tevent_fd * fde , uint16_t flags ,
2009-01-04 02:26:49 +03:00
void * priv )
{
2009-02-22 21:49:18 +03:00
struct tevent_req * req = talloc_get_type_abort (
priv , struct tevent_req ) ;
2009-02-28 23:44:30 +03:00
struct async_connect_state * state =
tevent_req_data ( req , struct async_connect_state ) ;
2011-08-22 16:16:26 +04:00
int ret ;
async_req: fix non-blocking connect()
According to Stevens UNIX Network Programming and various other sources,
the correct handling for non-blocking connect() is:
- when the initial connect() return -1/EINPROGRESS polling the socket
for *writeability*
- in the poll handler call getsocktopt() with SO_ERROR to get the
finished connect() return value
Simply calling connect() a second time without error checking is
probably wrong and not portable. For a successfull connect() Linux
returns 0, but Solaris will return EISCONN:
24254: 0.0336 0.0002 connect(4, 0xFEFFECAC, 16, SOV_DEFAULT) Err#150 EINPROGRESS
24254: AF_INET name = 10.10.10.143 port = 1024
24254: 0.0349 0.0001 port_associate(3, 4, 0x00000004, 0x0000001D,0x080648A8) = 0
24254: 0.0495 0.0146 port_getn(3, 0xFEFFEB50, 1, 1, 0xFEFFEB60) = 1 [0]
24254: 0.0497 0.0002 connect(4, 0x080646E4, 16, SOV_DEFAULT) Err#133 EISCONN
24254: AF_INET name = 10.10.10.143 port = 1024
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11564
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
2015-10-18 23:21:10 +03:00
int socket_error = 0 ;
socklen_t slen = sizeof ( socket_error ) ;
ret = getsockopt ( state - > fd , SOL_SOCKET , SO_ERROR ,
& socket_error , & slen ) ;
if ( ret ! = 0 ) {
/*
* According to Stevens this is the Solaris behaviour
* in case the connection encountered an error :
* getsockopt ( ) fails , error is in errno
*/
tevent_req_error ( req , errno ) ;
2009-01-04 02:26:49 +03:00
return ;
}
async_req: fix non-blocking connect()
According to Stevens UNIX Network Programming and various other sources,
the correct handling for non-blocking connect() is:
- when the initial connect() return -1/EINPROGRESS polling the socket
for *writeability*
- in the poll handler call getsocktopt() with SO_ERROR to get the
finished connect() return value
Simply calling connect() a second time without error checking is
probably wrong and not portable. For a successfull connect() Linux
returns 0, but Solaris will return EISCONN:
24254: 0.0336 0.0002 connect(4, 0xFEFFECAC, 16, SOV_DEFAULT) Err#150 EINPROGRESS
24254: AF_INET name = 10.10.10.143 port = 1024
24254: 0.0349 0.0001 port_associate(3, 4, 0x00000004, 0x0000001D,0x080648A8) = 0
24254: 0.0495 0.0146 port_getn(3, 0xFEFFEB50, 1, 1, 0xFEFFEB60) = 1 [0]
24254: 0.0497 0.0002 connect(4, 0x080646E4, 16, SOV_DEFAULT) Err#133 EISCONN
24254: AF_INET name = 10.10.10.143 port = 1024
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11564
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
2015-10-18 23:21:10 +03:00
if ( socket_error ! = 0 ) {
/*
* Berkeley derived implementations ( including ) Linux
* return the pending error via socket_error .
*/
tevent_req_error ( req , socket_error ) ;
2011-08-22 16:16:26 +04:00
return ;
}
async_req: fix non-blocking connect()
According to Stevens UNIX Network Programming and various other sources,
the correct handling for non-blocking connect() is:
- when the initial connect() return -1/EINPROGRESS polling the socket
for *writeability*
- in the poll handler call getsocktopt() with SO_ERROR to get the
finished connect() return value
Simply calling connect() a second time without error checking is
probably wrong and not portable. For a successfull connect() Linux
returns 0, but Solaris will return EISCONN:
24254: 0.0336 0.0002 connect(4, 0xFEFFECAC, 16, SOV_DEFAULT) Err#150 EINPROGRESS
24254: AF_INET name = 10.10.10.143 port = 1024
24254: 0.0349 0.0001 port_associate(3, 4, 0x00000004, 0x0000001D,0x080648A8) = 0
24254: 0.0495 0.0146 port_getn(3, 0xFEFFEB50, 1, 1, 0xFEFFEB60) = 1 [0]
24254: 0.0497 0.0002 connect(4, 0x080646E4, 16, SOV_DEFAULT) Err#133 EISCONN
24254: AF_INET name = 10.10.10.143 port = 1024
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11564
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
2015-10-18 23:21:10 +03:00
tevent_req_done ( req ) ;
2011-08-22 16:16:26 +04:00
return ;
2008-08-08 20:30:57 +04:00
}
2009-02-22 21:49:18 +03:00
int async_connect_recv ( struct tevent_req * req , int * perrno )
2009-01-04 02:26:49 +03:00
{
2015-05-21 23:28:14 +03:00
int err = tevent_req_simple_recv_unix ( req ) ;
2009-01-04 02:26:49 +03:00
2015-05-21 23:28:14 +03:00
if ( err ! = 0 ) {
2009-02-04 11:07:36 +03:00
* perrno = err ;
return - 1 ;
2009-01-04 02:26:49 +03:00
}
2009-02-22 21:49:18 +03:00
2015-05-21 23:28:14 +03:00
return 0 ;
2009-01-04 02:26:49 +03:00
}
2009-02-22 22:16:32 +03:00
struct writev_state {
struct tevent_context * ev ;
2016-09-15 12:41:56 +03:00
struct tevent_queue_entry * queue_entry ;
2009-02-22 22:16:32 +03:00
int fd ;
2015-05-21 23:28:14 +03:00
struct tevent_fd * fde ;
2009-02-22 22:16:32 +03:00
struct iovec * iov ;
int count ;
size_t total_size ;
2009-05-23 18:10:54 +04:00
uint16_t flags ;
2011-06-03 21:22:44 +04:00
bool err_on_readability ;
2009-02-22 22:16:32 +03:00
} ;
2015-05-21 23:28:14 +03:00
static void writev_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state ) ;
2016-09-15 12:41:56 +03:00
static bool writev_cancel ( struct tevent_req * req ) ;
2009-03-01 21:43:07 +03:00
static void writev_trigger ( struct tevent_req * req , void * private_data ) ;
2009-02-22 22:16:32 +03:00
static void writev_handler ( struct tevent_context * ev , struct tevent_fd * fde ,
uint16_t flags , void * private_data ) ;
struct tevent_req * writev_send ( TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
2009-03-01 21:43:07 +03:00
struct tevent_queue * queue , int fd ,
2009-05-23 18:10:54 +04:00
bool err_on_readability ,
2009-03-01 21:43:07 +03:00
struct iovec * iov , int count )
2009-02-22 22:16:32 +03:00
{
2009-05-10 12:49:18 +04:00
struct tevent_req * req ;
2009-02-22 22:16:32 +03:00
struct writev_state * state ;
2009-05-10 12:49:18 +04:00
req = tevent_req_create ( mem_ctx , & state , struct writev_state ) ;
if ( req = = NULL ) {
2009-02-22 22:16:32 +03:00
return NULL ;
}
state - > ev = ev ;
state - > fd = fd ;
state - > total_size = 0 ;
state - > count = count ;
state - > iov = ( struct iovec * ) talloc_memdup (
state , iov , sizeof ( struct iovec ) * count ) ;
2015-05-21 23:28:14 +03:00
if ( tevent_req_nomem ( state - > iov , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-02-22 22:16:32 +03:00
}
2011-06-03 21:22:44 +04:00
state - > flags = TEVENT_FD_WRITE | TEVENT_FD_READ ;
state - > err_on_readability = err_on_readability ;
2009-02-22 22:16:32 +03:00
2015-05-21 23:28:14 +03:00
tevent_req_set_cleanup_fn ( req , writev_cleanup ) ;
2016-09-15 12:41:56 +03:00
tevent_req_set_cancel_fn ( req , writev_cancel ) ;
2015-05-21 23:28:14 +03:00
2009-05-10 12:49:18 +04:00
if ( queue = = NULL ) {
2015-05-21 23:28:14 +03:00
state - > fde = tevent_add_fd ( state - > ev , state , state - > fd ,
2009-05-23 18:10:54 +04:00
state - > flags , writev_handler , req ) ;
2015-05-21 23:28:14 +03:00
if ( tevent_req_nomem ( state - > fde , req ) ) {
2009-05-10 12:49:18 +04:00
return tevent_req_post ( req , ev ) ;
}
return req ;
}
2020-04-07 14:46:32 +03:00
/*
* writev_trigger tries a nonblocking write . If that succeeds ,
* we can ' t directly notify the callback to call
* writev_recv . The callback would TALLOC_FREE ( req ) after
* calling writev_recv even before writev_trigger can inspect
* it for success .
*/
tevent_req_defer_callback ( req , ev ) ;
2020-03-12 18:20:25 +03:00
state - > queue_entry = tevent_queue_add_optimize_empty (
queue , ev , req , writev_trigger , NULL ) ;
2016-09-15 12:41:56 +03:00
if ( tevent_req_nomem ( state - > queue_entry , req ) ) {
2015-05-21 23:28:14 +03:00
return tevent_req_post ( req , ev ) ;
2009-02-22 22:16:32 +03:00
}
2020-03-19 19:00:59 +03:00
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , ev ) ;
}
2009-05-10 12:49:18 +04:00
return req ;
2015-05-21 23:28:14 +03:00
}
static void writev_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
{
struct writev_state * state = tevent_req_data ( req , struct writev_state ) ;
2016-09-15 12:41:56 +03:00
TALLOC_FREE ( state - > queue_entry ) ;
2015-05-21 23:28:14 +03:00
TALLOC_FREE ( state - > fde ) ;
2009-02-22 22:16:32 +03:00
}
2016-09-15 12:41:56 +03:00
static bool writev_cancel ( struct tevent_req * req )
{
struct writev_state * state = tevent_req_data ( req , struct writev_state ) ;
if ( state - > total_size > 0 ) {
/*
* We ' ve already started to write : - (
*/
return false ;
}
2020-03-12 13:42:41 +03:00
TALLOC_FREE ( state - > queue_entry ) ;
TALLOC_FREE ( state - > fde ) ;
tevent_req_defer_callback ( req , state - > ev ) ;
2016-09-15 12:41:56 +03:00
tevent_req_error ( req , ECANCELED ) ;
return true ;
}
2020-03-19 19:00:59 +03:00
static void writev_do ( struct tevent_req * req , struct writev_state * state )
{
ssize_t written ;
bool ok ;
written = writev ( state - > fd , state - > iov , state - > count ) ;
if ( ( written = = - 1 ) & &
( ( errno = = EINTR ) | |
( errno = = EAGAIN ) | |
( errno = = EWOULDBLOCK ) ) ) {
/* retry after going through the tevent loop */
return ;
}
if ( written = = - 1 ) {
tevent_req_error ( req , errno ) ;
return ;
}
if ( written = = 0 ) {
tevent_req_error ( req , EPIPE ) ;
return ;
}
state - > total_size + = written ;
ok = iov_advance ( & state - > iov , & state - > count , written ) ;
if ( ! ok ) {
tevent_req_error ( req , EIO ) ;
return ;
}
if ( state - > count = = 0 ) {
tevent_req_done ( req ) ;
return ;
}
}
2009-03-01 21:43:07 +03:00
static void writev_trigger ( struct tevent_req * req , void * private_data )
{
struct writev_state * state = tevent_req_data ( req , struct writev_state ) ;
2016-09-15 12:41:56 +03:00
state - > queue_entry = NULL ;
2020-03-19 19:00:59 +03:00
writev_do ( req , state ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return ;
}
2015-05-21 23:28:14 +03:00
state - > fde = tevent_add_fd ( state - > ev , state , state - > fd , state - > flags ,
2009-03-01 21:43:07 +03:00
writev_handler , req ) ;
2015-05-21 23:28:14 +03:00
if ( tevent_req_nomem ( state - > fde , req ) ) {
return ;
2009-03-01 21:43:07 +03:00
}
}
2009-02-22 22:16:32 +03:00
static void writev_handler ( struct tevent_context * ev , struct tevent_fd * fde ,
uint16_t flags , void * private_data )
{
struct tevent_req * req = talloc_get_type_abort (
private_data , struct tevent_req ) ;
2009-02-28 23:44:30 +03:00
struct writev_state * state =
tevent_req_data ( req , struct writev_state ) ;
2009-02-22 22:16:32 +03:00
2009-06-04 14:02:38 +04:00
if ( ( state - > flags & TEVENT_FD_READ ) & & ( flags & TEVENT_FD_READ ) ) {
2011-06-03 21:22:44 +04:00
int ret , value ;
if ( state - > err_on_readability ) {
/* Readable and the caller wants an error on read. */
tevent_req_error ( req , EPIPE ) ;
return ;
}
/* Might be an error. Check if there are bytes to read */
ret = ioctl ( state - > fd , FIONREAD , & value ) ;
/* FIXME - should we also check
for ret = = 0 and value = = 0 here ? */
if ( ret = = - 1 ) {
/* There's an error. */
tevent_req_error ( req , EPIPE ) ;
return ;
}
/* A request for TEVENT_FD_READ will succeed from now and
forevermore until the bytes are read so if there was
an error we ' ll wait until we do read , then get it in
the read callback function . Until then , remove TEVENT_FD_READ
from the flags we ' re waiting for . */
state - > flags & = ~ TEVENT_FD_READ ;
TEVENT_FD_NOT_READABLE ( fde ) ;
/* If not writable, we're done. */
if ( ! ( flags & TEVENT_FD_WRITE ) ) {
return ;
}
2009-05-23 18:10:54 +04:00
}
2020-03-19 19:00:59 +03:00
writev_do ( req , state ) ;
2009-02-22 22:16:32 +03:00
}
ssize_t writev_recv ( struct tevent_req * req , int * perrno )
{
2009-02-28 23:44:30 +03:00
struct writev_state * state =
tevent_req_data ( req , struct writev_state ) ;
2015-05-21 23:28:14 +03:00
ssize_t ret ;
2009-02-22 22:16:32 +03:00
if ( tevent_req_is_unix_error ( req , perrno ) ) {
2015-05-21 23:28:14 +03:00
tevent_req_received ( req ) ;
2009-02-22 22:16:32 +03:00
return - 1 ;
}
2015-05-21 23:28:14 +03:00
ret = state - > total_size ;
tevent_req_received ( req ) ;
return ret ;
2009-02-22 22:16:32 +03:00
}
2009-02-23 01:13:34 +03:00
struct read_packet_state {
int fd ;
2015-05-21 23:28:14 +03:00
struct tevent_fd * fde ;
2009-02-23 01:13:34 +03:00
uint8_t * buf ;
size_t nread ;
ssize_t ( * more ) ( uint8_t * buf , size_t buflen , void * private_data ) ;
void * private_data ;
} ;
2015-05-21 23:28:14 +03:00
static void read_packet_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state ) ;
2009-02-23 01:13:34 +03:00
static void read_packet_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags , void * private_data ) ;
struct tevent_req * read_packet_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
int fd , size_t initial ,
ssize_t ( * more ) ( uint8_t * buf ,
size_t buflen ,
void * private_data ) ,
void * private_data )
{
2015-05-21 23:28:14 +03:00
struct tevent_req * req ;
2009-02-23 01:13:34 +03:00
struct read_packet_state * state ;
2015-05-21 23:28:14 +03:00
req = tevent_req_create ( mem_ctx , & state , struct read_packet_state ) ;
if ( req = = NULL ) {
2009-02-23 01:13:34 +03:00
return NULL ;
}
state - > fd = fd ;
state - > nread = 0 ;
state - > more = more ;
state - > private_data = private_data ;
2015-05-21 23:28:14 +03:00
tevent_req_set_cleanup_fn ( req , read_packet_cleanup ) ;
2009-02-23 01:13:34 +03:00
state - > buf = talloc_array ( state , uint8_t , initial ) ;
2015-05-21 23:28:14 +03:00
if ( tevent_req_nomem ( state - > buf , req ) ) {
return tevent_req_post ( req , ev ) ;
2009-02-23 01:13:34 +03:00
}
2015-05-21 23:28:14 +03:00
state - > fde = tevent_add_fd ( ev , state , fd ,
TEVENT_FD_READ , read_packet_handler ,
req ) ;
if ( tevent_req_nomem ( state - > fde , req ) ) {
2015-05-21 23:28:14 +03:00
return tevent_req_post ( req , ev ) ;
2009-02-23 01:13:34 +03:00
}
2015-05-21 23:28:14 +03:00
return req ;
2009-02-23 01:13:34 +03:00
}
2015-05-21 23:28:14 +03:00
static void read_packet_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
{
struct read_packet_state * state =
tevent_req_data ( req , struct read_packet_state ) ;
TALLOC_FREE ( state - > fde ) ;
}
2009-02-23 01:13:34 +03:00
static void read_packet_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags , void * private_data )
{
struct tevent_req * req = talloc_get_type_abort (
private_data , struct tevent_req ) ;
2009-02-28 23:44:30 +03:00
struct read_packet_state * state =
tevent_req_data ( req , struct read_packet_state ) ;
2009-02-23 01:13:34 +03:00
size_t total = talloc_get_size ( state - > buf ) ;
ssize_t nread , more ;
uint8_t * tmp ;
2009-04-05 15:26:42 +04:00
nread = recv ( state - > fd , state - > buf + state - > nread , total - state - > nread ,
0 ) ;
2012-03-23 18:56:43 +04:00
if ( ( nread = = - 1 ) & & ( errno = = ENOTSOCK ) ) {
nread = read ( state - > fd , state - > buf + state - > nread ,
total - state - > nread ) ;
}
2009-05-30 11:49:17 +04:00
if ( ( nread = = - 1 ) & & ( errno = = EINTR ) ) {
/* retry */
return ;
}
2009-02-23 01:13:34 +03:00
if ( nread = = - 1 ) {
tevent_req_error ( req , errno ) ;
return ;
}
if ( nread = = 0 ) {
tevent_req_error ( req , EPIPE ) ;
return ;
}
state - > nread + = nread ;
if ( state - > nread < total ) {
/* Come back later */
return ;
}
/*
* We got what was initially requested . See if " more " asks for - - more .
*/
if ( state - > more = = NULL ) {
/* Nobody to ask, this is a async read_data */
tevent_req_done ( req ) ;
return ;
}
more = state - > more ( state - > buf , total , state - > private_data ) ;
if ( more = = - 1 ) {
/* We got an invalid packet, tell the caller */
tevent_req_error ( req , EIO ) ;
return ;
}
if ( more = = 0 ) {
/* We're done, full packet received */
tevent_req_done ( req ) ;
return ;
}
2013-10-16 16:17:49 +04:00
if ( total + more < total ) {
tevent_req_error ( req , EMSGSIZE ) ;
return ;
}
2009-04-16 16:53:36 +04:00
tmp = talloc_realloc ( state , state - > buf , uint8_t , total + more ) ;
2009-02-23 01:13:34 +03:00
if ( tevent_req_nomem ( tmp , req ) ) {
return ;
}
state - > buf = tmp ;
}
ssize_t read_packet_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
uint8_t * * pbuf , int * perrno )
{
2009-02-28 23:44:30 +03:00
struct read_packet_state * state =
tevent_req_data ( req , struct read_packet_state ) ;
2009-02-23 01:13:34 +03:00
if ( tevent_req_is_unix_error ( req , perrno ) ) {
2015-05-21 23:28:14 +03:00
tevent_req_received ( req ) ;
2009-02-23 01:13:34 +03:00
return - 1 ;
}
* pbuf = talloc_move ( mem_ctx , & state - > buf ) ;
2015-05-21 23:28:14 +03:00
tevent_req_received ( req ) ;
2009-02-23 01:13:34 +03:00
return talloc_get_size ( * pbuf ) ;
}
2011-07-26 17:06:44 +04:00
struct wait_for_read_state {
struct tevent_fd * fde ;
2015-06-25 09:46:24 +03:00
int fd ;
bool check_errors ;
2011-07-26 17:06:44 +04:00
} ;
2015-05-21 23:28:14 +03:00
static void wait_for_read_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state ) ;
2011-07-26 17:06:44 +04:00
static void wait_for_read_done ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags ,
void * private_data ) ;
struct tevent_req * wait_for_read_send ( TALLOC_CTX * mem_ctx ,
2015-06-25 09:46:24 +03:00
struct tevent_context * ev , int fd ,
bool check_errors )
2011-07-26 17:06:44 +04:00
{
struct tevent_req * req ;
struct wait_for_read_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct wait_for_read_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2015-05-21 23:28:14 +03:00
tevent_req_set_cleanup_fn ( req , wait_for_read_cleanup ) ;
2011-07-26 17:06:44 +04:00
state - > fde = tevent_add_fd ( ev , state , fd , TEVENT_FD_READ ,
2015-05-21 23:28:14 +03:00
wait_for_read_done , req ) ;
2011-07-26 17:06:44 +04:00
if ( tevent_req_nomem ( state - > fde , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2015-06-25 09:46:24 +03:00
state - > fd = fd ;
state - > check_errors = check_errors ;
2011-07-26 17:06:44 +04:00
return req ;
}
2015-05-21 23:28:14 +03:00
static void wait_for_read_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
{
struct wait_for_read_state * state =
tevent_req_data ( req , struct wait_for_read_state ) ;
TALLOC_FREE ( state - > fde ) ;
}
2011-07-26 17:06:44 +04:00
static void wait_for_read_done ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags ,
void * private_data )
{
2015-05-21 23:28:14 +03:00
struct tevent_req * req = talloc_get_type_abort (
private_data , struct tevent_req ) ;
2015-06-25 09:46:24 +03:00
struct wait_for_read_state * state =
tevent_req_data ( req , struct wait_for_read_state ) ;
2021-03-09 14:54:49 +03:00
int ret , available ;
2011-07-26 17:06:44 +04:00
2015-06-25 09:46:24 +03:00
if ( ( flags & TEVENT_FD_READ ) = = 0 ) {
return ;
}
if ( ! state - > check_errors ) {
2015-05-21 23:28:14 +03:00
tevent_req_done ( req ) ;
2015-06-25 09:46:24 +03:00
return ;
2011-07-26 17:06:44 +04:00
}
2015-06-25 09:46:24 +03:00
2021-03-09 14:54:49 +03:00
ret = ioctl ( state - > fd , FIONREAD , & available ) ;
2015-06-25 09:46:24 +03:00
2021-03-09 14:54:49 +03:00
if ( ( ret = = - 1 ) & & ( errno = = EINTR ) ) {
2015-06-25 09:46:24 +03:00
/* come back later */
return ;
}
2021-03-09 14:54:49 +03:00
if ( ret = = - 1 ) {
tevent_req_error ( req , errno ) ;
2015-06-25 09:46:24 +03:00
return ;
}
2021-03-09 14:54:49 +03:00
if ( available = = 0 ) {
tevent_req_error ( req , EPIPE ) ;
2015-06-25 09:46:24 +03:00
return ;
}
tevent_req_done ( req ) ;
2011-07-26 17:06:44 +04:00
}
bool wait_for_read_recv ( struct tevent_req * req , int * perr )
{
2015-05-21 23:28:14 +03:00
int err = tevent_req_simple_recv_unix ( req ) ;
2011-07-26 17:06:44 +04:00
2015-05-21 23:28:14 +03:00
if ( err ! = 0 ) {
2011-07-26 17:06:44 +04:00
* perr = err ;
return false ;
}
2015-05-21 23:28:14 +03:00
2011-07-26 17:06:44 +04:00
return true ;
}
2014-11-30 18:10:32 +03:00
struct accept_state {
struct tevent_fd * fde ;
int listen_sock ;
2021-01-11 17:58:58 +03:00
struct samba_sockaddr addr ;
2014-11-30 18:10:32 +03:00
int sock ;
} ;
static void accept_handler ( struct tevent_context * ev , struct tevent_fd * fde ,
uint16_t flags , void * private_data ) ;
struct tevent_req * accept_send ( TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
int listen_sock )
{
struct tevent_req * req ;
struct accept_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct accept_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > listen_sock = listen_sock ;
state - > fde = tevent_add_fd ( ev , state , listen_sock , TEVENT_FD_READ ,
accept_handler , req ) ;
if ( tevent_req_nomem ( state - > fde , req ) ) {
return tevent_req_post ( req , ev ) ;
}
return req ;
}
static void accept_handler ( struct tevent_context * ev , struct tevent_fd * fde ,
uint16_t flags , void * private_data )
{
struct tevent_req * req = talloc_get_type_abort (
private_data , struct tevent_req ) ;
struct accept_state * state = tevent_req_data ( req , struct accept_state ) ;
int ret ;
TALLOC_FREE ( state - > fde ) ;
if ( ( flags & TEVENT_FD_READ ) = = 0 ) {
tevent_req_error ( req , EIO ) ;
return ;
}
2021-01-11 17:58:58 +03:00
state - > addr . sa_socklen = sizeof ( state - > addr . u ) ;
ret = accept ( state - > listen_sock ,
& state - > addr . u . sa ,
& state - > addr . sa_socklen ) ;
2014-11-30 18:10:32 +03:00
if ( ( ret = = - 1 ) & & ( errno = = EINTR ) ) {
/* retry */
return ;
}
if ( ret = = - 1 ) {
tevent_req_error ( req , errno ) ;
return ;
}
2017-12-10 23:31:33 +03:00
smb_set_close_on_exec ( ret ) ;
2014-11-30 18:10:32 +03:00
state - > sock = ret ;
tevent_req_done ( req ) ;
}
2021-01-11 17:58:58 +03:00
int accept_recv ( struct tevent_req * req ,
2021-01-17 13:04:47 +03:00
int * listen_sock ,
2021-01-11 17:58:58 +03:00
struct samba_sockaddr * paddr ,
int * perr )
2014-11-30 18:10:32 +03:00
{
struct accept_state * state = tevent_req_data ( req , struct accept_state ) ;
2021-01-17 13:04:47 +03:00
int sock = state - > sock ;
2014-11-30 18:10:32 +03:00
int err ;
if ( tevent_req_is_unix_error ( req , & err ) ) {
if ( perr ! = NULL ) {
* perr = err ;
}
2021-01-17 13:04:47 +03:00
tevent_req_received ( req ) ;
2014-11-30 18:10:32 +03:00
return - 1 ;
}
2021-01-17 13:04:47 +03:00
if ( listen_sock ! = NULL ) {
* listen_sock = state - > listen_sock ;
}
2014-11-30 18:10:32 +03:00
if ( paddr ! = NULL ) {
2021-01-11 17:58:58 +03:00
* paddr = state - > addr ;
2014-11-30 18:10:32 +03:00
}
2021-01-17 13:04:47 +03:00
tevent_req_received ( req ) ;
return sock ;
2014-11-30 18:10:32 +03:00
}