@ -20,7 +20,8 @@ static void error_cb(socket_t sock, void* arg);
static void resume_read_cb ( struct ll_queue * q , void * arg ) ;
static void fin_deferred_cb ( struct ll_queue * q , void * arg ) ;
static void write_queue_fetch_cb ( struct ll_queue * q , void * arg ) ;
static void flush_write_buf ( struct tcp_conn * tc ) ;
static int flush_write_buf ( struct tcp_conn * tc ) ;
static void tcp_conn_handle_error ( struct tcp_conn * tc , int err ) ;
static const uint8_t tcp_fin_sentinel ;
struct tcp_conn * tcp_conn_create (
@ -128,6 +129,45 @@ void tcp_conn_destroy(struct tcp_conn* tc) {
u_free ( tc ) ;
}
static void tcp_conn_handle_error ( struct tcp_conn * tc , int err )
{
tc - > error = 1 ;
queue_waiter_cancel ( tc - > read_queue , & tc - > read_waiter ) ;
queue_set_empty_callback ( tc - > read_queue , NULL , NULL ) ;
queue_set_callback ( tc - > read_queue , NULL , NULL ) ;
if ( tc - > sock ! = SOCKET_INVALID ) {
while ( 1 ) {
struct ll_entry * e = queue_entry_new_from_pool ( tc - > entry_pool ) ;
if ( ! e ) break ;
uint8_t * buf = memory_pool_alloc ( tc - > data_pool ) ;
if ( ! buf ) { queue_entry_free ( e ) ; break ; }
ssize_t n = recv ( tc - > sock , buf , tc - > entry_data_size , 0 ) ;
if ( n > 0 ) { e - > dgram = buf ; e - > len = ( uint16_t ) n ; queue_data_put ( tc - > read_queue , e ) ; }
else { memory_pool_free ( tc - > data_pool , buf ) ; queue_entry_free ( e ) ; break ; }
}
}
if ( tc - > socket_id ) {
uasync_remove_socket_t ( tc - > ua , tc - > sock ) ;
tc - > socket_id = NULL ;
}
if ( tc - > sock ! = SOCKET_INVALID ) {
socket_close_wrapper ( tc - > sock ) ;
tc - > sock = SOCKET_INVALID ;
}
queue_set_callback ( tc - > write_queue , NULL , NULL ) ;
if ( tc - > on_error ) {
void ( * on_err ) ( struct tcp_conn * , int , void * ) = tc - > on_error ;
void * arg = tc - > arg ;
tc - > on_error = NULL ;
on_err ( tc , err , arg ) ;
}
}
// ====================================================================
// Чтение из сокета
// ====================================================================
@ -174,9 +214,8 @@ static void read_cb(socket_t sock, void* arg) {
memory_pool_free ( tc - > data_pool , buf ) ;
queue_entry_free ( e ) ;
if ( errno = = EAGAIN | | errno = = EWOULDBLOCK | | errno = = EINTR ) return ;
tc - > error = 1 ;
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " tcp_io: recv error fd=%d errno=%d " , ( int ) tc - > sock , errno ) ;
if ( tc - > on_error ) tc - > on _error( tc , errno , tc - > arg ) ;
tcp_conn_handle _error( tc , errno ) ;
}
}
@ -198,7 +237,7 @@ static void fin_deferred_cb(struct ll_queue* q, void* arg) {
// Запись в сокет
// ====================================================================
static void flush_write_buf ( struct tcp_conn * tc ) {
static int flush_write_buf ( struct tcp_conn * tc ) {
while ( tc - > write_buf & & tc - > write_offset < tc - > write_len ) {
ssize_t n = send ( tc - > sock , tc - > write_buf + tc - > write_offset , tc - > write_len - tc - > write_offset , MSG_NOSIGNAL ) ;
if ( n > 0 ) {
@ -209,16 +248,16 @@ static void flush_write_buf(struct tcp_conn* tc) {
tc - > write_len = 0 ;
tc - > write_offset = 0 ;
DEBUG_TRACE ( DEBUG_CATEGORY_SOCKET , " tcp_io: flush_wbuf done fd=%d " , ( int ) tc - > sock ) ;
return ;
return 0 ;
}
continue ;
}
if ( n < 0 & & ( errno = = EAGAIN | | errno = = EWOULDBLOCK | | errno = = EINTR ) ) return ;
tc - > error = 1 ;
if ( n < 0 & & ( errno = = EAGAIN | | errno = = EWOULDBLOCK | | errno = = EINTR ) ) return 0 ;
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " tcp_io: send error fd=%d errno=%d " , ( int ) tc - > sock , errno ) ;
if ( tc - > on_error ) tc - > on _error( tc , errno , tc - > arg ) ;
return ;
tcp_conn_handle _error( tc , errno ) ;
return 1 ;
}
return 0 ;
}
static void write_queue_fetch_cb ( struct ll_queue * q , void * arg ) {
@ -227,7 +266,7 @@ static void write_queue_fetch_cb(struct ll_queue* q, void* arg) {
if ( tc - > error | | tc - > closed ) { DEBUG_TRACE ( DEBUG_CATEGORY_SOCKET , " tcp_io: wq_fetch skip fd=%d error=%d closed=%d " , ( int ) tc - > sock , tc - > error , tc - > closed ) ; return ; }
if ( tc - > write_buf ) {
flush_write_buf ( tc ) ;
if ( flush_write_buf ( tc ) ) return ;
if ( tc - > write_buf ) return ; // остался остаток, ждём write_cb
}
@ -278,9 +317,9 @@ static void write_queue_fetch_cb(struct ll_queue* q, void* arg) {
tc - > write_buf = memory_pool_alloc ( tc - > data_pool ) ;
if ( ! tc - > write_buf ) {
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " tcp_io: write_buf alloc failed fd=%d " , ( int ) tc - > sock ) ;
tc - > error = 1 ;
memory_pool_free ( tc - > data_pool , e - > dgram ) ;
queue_entry_free ( e ) ;
tcp_conn_handle_error ( tc , ENOMEM ) ;
return ;
}
memcpy ( tc - > write_buf , e - > dgram + n , rem ) ;
@ -295,9 +334,9 @@ static void write_queue_fetch_cb(struct ll_queue* q, void* arg) {
tc - > write_buf = memory_pool_alloc ( tc - > data_pool ) ;
if ( ! tc - > write_buf ) {
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " tcp_io: write_buf alloc failed fd=%d " , ( int ) tc - > sock ) ;
tc - > error = 1 ;
memory_pool_free ( tc - > data_pool , e - > dgram ) ;
queue_entry_free ( e ) ;
tcp_conn_handle_error ( tc , ENOMEM ) ;
return ;
}
memcpy ( tc - > write_buf , e - > dgram , e - > len ) ;
@ -309,11 +348,10 @@ static void write_queue_fetch_cb(struct ll_queue* q, void* arg) {
tc - > write_monitor = 1 ;
DEBUG_TRACE ( DEBUG_CATEGORY_SOCKET , " tcp_io: wq_fetch POLLOUT ON fd=%d (EAGAIN, wbuf=%zu bytes) " , ( int ) tc - > sock , tc - > write_len ) ;
} else {
tc - > error = 1 ;
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " tcp_io: send error fd=%d errno=%d " , ( int ) tc - > sock , errno ) ;
if ( tc - > on_error ) tc - > on_error ( tc , errno , tc - > arg ) ;
memory_pool_free ( tc - > data_pool , e - > dgram ) ;
queue_entry_free ( e ) ;
tcp_conn_handle_error ( tc , errno ) ;
}
}
@ -329,15 +367,13 @@ static void write_cb(socket_t sock, void* arg) {
tc - > connected = 1 ;
DEBUG_INFO ( DEBUG_CATEGORY_SOCKET , " tcp_io: connect ok fd=%d " , ( int ) tc - > sock ) ;
} else {
tc - > error = 1 ;
DEBUG_TRACE ( DEBUG_CATEGORY_SOCKET , " tcp_io: write_cb connect fail fd=%d err=%d wmon=%d (POLLOUT still active) " , ( int ) tc - > sock , err , tc - > write_monitor ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " tcp_io: connect fail fd=%d err=%d " , ( int ) tc - > sock , err ) ;
if ( tc - > on_error ) tc - > on _error( tc , err ? err : - 1 , tc - > arg ) ;
tcp_conn_handle_error ( tc , err ? err : - 1 ) ;
return ;
}
}
flush_write_buf ( tc ) ;
if ( flush_write_buf ( tc ) ) return ;
if ( ! tc - > write_buf ) {
DEBUG_TRACE ( DEBUG_CATEGORY_SOCKET , " tcp_io: write_cb flushed fd=%d wmon=%d (resume WQ cb) " , ( int ) tc - > sock , tc - > write_monitor ) ;
queue_resume_callback ( tc - > write_queue ) ;
@ -352,10 +388,8 @@ static void error_cb(socket_t sock, void* arg) {
( void ) sock ;
struct tcp_conn * tc = ( struct tcp_conn * ) arg ;
if ( ! tc | | tc - > sock = = SOCKET_INVALID ) return ;
tc - > error = 1 ;
DEBUG_TRACE ( DEBUG_CATEGORY_SOCKET , " tcp_io: error_cb fd=%d connected=%d fin_remote=%d wmon=%d " , ( int ) tc - > sock , tc - > connected , tc - > fin_remote , tc - > write_monitor ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " tcp_io: async error fd=%d " , ( int ) tc - > sock ) ;
if ( tc - > on_error ) tc - > on _error( tc , - 1 , tc - > arg ) ;
tcp_conn_handle_error ( tc , - 1 ) ;
}
// ====================================================================