2024-03-21 19:27:41 +08:00
# include <string.h>
2024-08-28 19:00:32 +08:00
# include <stdbool.h>
2024-09-13 15:34:26 +08:00
# include <sys/queue.h>
2024-03-21 19:27:41 +08:00
2024-09-19 16:23:12 +08:00
# include "log_internal.h"
2024-03-27 17:11:38 +08:00
# include "interval_tree.h"
2024-06-25 10:32:51 +08:00
# include "tcp_reassembly.h"
2024-08-21 15:54:35 +08:00
# include "stellar/stellar.h"
2024-06-25 10:32:51 +08:00
2024-10-23 10:10:20 +08:00
# define TCP_REASSEMBLY_LOG_DEBUG(format, ...) STELLAR_LOG_DEBUG(__thread_local_logger, "TCP reassembly", format, ##__VA_ARGS__)
# define TCP_REASSEMBLY_LOG_ERROR(format, ...) STELLAR_LOG_ERROR(__thread_local_logger, "TCP reassembly", format, ##__VA_ARGS__)
2024-03-21 19:27:41 +08:00
2024-10-31 18:53:01 +08:00
struct tcp_segment_internal
2024-03-21 19:27:41 +08:00
{
2024-04-02 16:21:39 +08:00
uint64_t ts ;
2024-03-27 17:11:38 +08:00
uint64_t id ;
2024-04-02 16:21:39 +08:00
struct interval_tree_node node ;
2024-10-31 18:53:01 +08:00
TAILQ_ENTRY ( tcp_segment_internal ) lru ;
2024-04-02 16:21:39 +08:00
struct tcp_segment seg ;
2024-11-25 10:53:21 +08:00
void * user_data ;
2024-04-02 16:21:39 +08:00
void * data ; // flexible array member
2024-03-21 19:27:41 +08:00
} ;
2024-10-31 18:53:01 +08:00
TAILQ_HEAD ( tcp_segment_internal_list , tcp_segment_internal ) ;
2024-09-13 15:34:26 +08:00
2024-03-25 17:30:48 +08:00
struct tcp_reassembly
{
2024-04-02 16:21:39 +08:00
uint64_t max_timeout ;
uint64_t max_seg_num ;
uint64_t cur_seg_num ;
uint64_t sum_seg_num ;
2024-09-13 15:34:26 +08:00
struct rb_root_cached rb_root ;
2024-10-31 18:53:01 +08:00
struct tcp_segment_internal_list lru_list ;
2024-04-02 16:21:39 +08:00
uint32_t recv_next ;
2024-03-25 17:30:48 +08:00
} ;
2024-04-02 16:21:39 +08:00
struct tcp_segment * tcp_segment_new ( uint32_t seq , const void * data , uint32_t len )
2024-03-29 16:32:16 +08:00
{
2024-10-31 18:53:01 +08:00
struct tcp_segment_internal * p = ( struct tcp_segment_internal * ) malloc ( sizeof ( struct tcp_segment_internal ) + len ) ;
2024-08-14 10:53:22 +08:00
if ( ! p )
{
TCP_REASSEMBLY_LOG_ERROR ( " calloc failed " ) ;
return NULL ;
}
p - > ts = 0 ;
p - > id = 0 ;
2024-04-02 16:21:39 +08:00
p - > node . start = seq ;
p - > node . last = ( uint64_t ) seq + ( uint64_t ) len - 1 ;
2024-10-31 18:53:01 +08:00
p - > data = ( char * ) p + sizeof ( struct tcp_segment_internal ) ;
2024-04-02 16:21:39 +08:00
memcpy ( p - > data , data , len ) ;
2024-03-21 19:27:41 +08:00
2024-04-02 16:21:39 +08:00
p - > seg . len = len ;
p - > seg . data = p - > data ;
2024-03-21 19:27:41 +08:00
2024-04-02 16:21:39 +08:00
return & p - > seg ;
2024-03-21 19:27:41 +08:00
}
2024-04-02 16:21:39 +08:00
void tcp_segment_free ( struct tcp_segment * seg )
2024-03-21 19:27:41 +08:00
{
2024-04-02 16:21:39 +08:00
if ( seg )
2024-03-21 19:27:41 +08:00
{
2024-10-31 18:53:01 +08:00
struct tcp_segment_internal * p = container_of ( seg , struct tcp_segment_internal , seg ) ;
2024-04-02 16:21:39 +08:00
free ( p ) ;
2024-03-21 19:27:41 +08:00
}
}
2024-11-25 10:53:21 +08:00
void tcp_segment_set_user_data ( struct tcp_segment * seg , void * user_data )
{
struct tcp_segment_internal * p = container_of ( seg , struct tcp_segment_internal , seg ) ;
p - > user_data = user_data ;
}
void * tcp_segment_get_user_data ( const struct tcp_segment * seg )
{
struct tcp_segment_internal * p = container_of ( seg , struct tcp_segment_internal , seg ) ;
return p - > user_data ;
}
2024-04-02 16:21:39 +08:00
struct tcp_reassembly * tcp_reassembly_new ( uint64_t max_timeout , uint64_t max_seg_num )
2024-03-21 19:27:41 +08:00
{
2024-09-13 15:34:26 +08:00
struct tcp_reassembly * tcp_reass = ( struct tcp_reassembly * ) malloc ( sizeof ( struct tcp_reassembly ) ) ;
if ( ! tcp_reass )
2024-03-21 19:27:41 +08:00
{
2024-04-02 16:21:39 +08:00
TCP_REASSEMBLY_LOG_ERROR ( " calloc failed " ) ;
return NULL ;
2024-03-21 19:27:41 +08:00
}
2024-03-25 17:30:48 +08:00
2024-09-13 15:34:26 +08:00
tcp_reass - > max_timeout = max_timeout ;
tcp_reass - > max_seg_num = max_seg_num ;
tcp_reass - > cur_seg_num = 0 ;
tcp_reass - > sum_seg_num = 0 ;
tcp_reass - > rb_root = RB_ROOT_CACHED ;
tcp_reass - > recv_next = 0 ;
TAILQ_INIT ( & tcp_reass - > lru_list ) ;
2024-04-02 16:21:39 +08:00
2024-09-13 15:34:26 +08:00
return tcp_reass ;
2024-03-21 19:27:41 +08:00
}
2024-09-13 15:34:26 +08:00
void tcp_reassembly_free ( struct tcp_reassembly * tcp_reass )
2024-03-21 19:27:41 +08:00
{
2024-09-13 15:34:26 +08:00
if ( tcp_reass )
2024-03-21 19:27:41 +08:00
{
2024-10-31 18:53:01 +08:00
struct tcp_segment_internal * p = NULL ;
2024-09-13 15:34:26 +08:00
while ( ( p = TAILQ_FIRST ( & tcp_reass - > lru_list ) ) )
2024-03-21 19:27:41 +08:00
{
2024-09-13 15:34:26 +08:00
tcp_reass - > cur_seg_num - - ;
TAILQ_REMOVE ( & tcp_reass - > lru_list , p , lru ) ;
interval_tree_remove ( & p - > node , & tcp_reass - > rb_root ) ;
2024-04-02 16:21:39 +08:00
free ( p ) ;
2024-03-21 19:27:41 +08:00
}
2024-09-13 15:34:26 +08:00
free ( tcp_reass ) ;
2024-03-21 19:27:41 +08:00
}
}
2024-05-06 15:54:16 +08:00
/*
* return : 1 : push tcp segment success ( segment overlap )
* return : 0 : push tcp segment success
* return : - 1 : push tcp segment failed ( no space )
* return : - 2 : push tcp segment failed ( segment repeat )
*/
2024-09-13 15:34:26 +08:00
int tcp_reassembly_push ( struct tcp_reassembly * tcp_reass , struct tcp_segment * seg , uint64_t now )
2024-03-21 19:27:41 +08:00
{
2024-09-13 15:34:26 +08:00
if ( tcp_reass = = NULL )
2024-04-17 17:53:42 +08:00
{
return - 1 ;
}
2024-09-13 15:34:26 +08:00
if ( tcp_reass - > cur_seg_num > = tcp_reass - > max_seg_num )
2024-03-21 19:27:41 +08:00
{
2024-09-13 15:34:26 +08:00
TCP_REASSEMBLY_LOG_ERROR ( " tcp_reass %p is full " , tcp_reass ) ;
2024-04-02 16:21:39 +08:00
return - 1 ;
2024-03-21 19:27:41 +08:00
}
2024-04-02 16:21:39 +08:00
int ret = 0 ;
2024-10-31 18:53:01 +08:00
struct tcp_segment_internal * p = container_of ( seg , struct tcp_segment_internal , seg ) ;
2024-09-13 15:34:26 +08:00
struct interval_tree_node * node = interval_tree_iter_first ( & tcp_reass - > rb_root , p - > node . start , p - > node . last ) ;
2024-05-06 15:54:16 +08:00
if ( node )
2024-03-21 19:27:41 +08:00
{
2024-05-06 15:54:16 +08:00
do
{
2024-10-31 18:53:01 +08:00
struct tcp_segment_internal * t = container_of ( node , struct tcp_segment_internal , node ) ;
2024-05-06 15:54:16 +08:00
if ( t - > node . start = = p - > node . start & & t - > node . last = = p - > node . last )
{
2024-09-13 15:34:26 +08:00
TCP_REASSEMBLY_LOG_DEBUG ( " tcp_reass %p push segment %p [%lu, %lu] failed, segment repeat " , tcp_reass , seg , p - > node . start , p - > node . last ) ;
2024-05-06 15:54:16 +08:00
return - 2 ;
}
} while ( ( node = interval_tree_iter_next ( node , p - > node . start , p - > node . last ) ) ) ;
2024-09-13 15:34:26 +08:00
TCP_REASSEMBLY_LOG_DEBUG ( " tcp_reass %p push segment %p [%lu, %lu], but segment overlap " , tcp_reass , seg , p - > node . start , p - > node . last ) ;
2024-04-02 16:21:39 +08:00
ret = 1 ;
2024-03-21 19:27:41 +08:00
}
2024-05-06 15:54:16 +08:00
else
{
2024-09-13 15:34:26 +08:00
TCP_REASSEMBLY_LOG_DEBUG ( " tcp_reass %p push segment %p [%lu, %lu] " , tcp_reass , seg , p - > node . start , p - > node . last ) ;
2024-05-06 15:54:16 +08:00
}
2024-03-21 19:27:41 +08:00
2024-04-02 16:21:39 +08:00
p - > ts = now ;
2024-09-13 15:34:26 +08:00
p - > id = tcp_reass - > sum_seg_num + + ;
TAILQ_INSERT_TAIL ( & tcp_reass - > lru_list , p , lru ) ;
interval_tree_insert ( & p - > node , & tcp_reass - > rb_root ) ;
2024-03-21 19:27:41 +08:00
2024-09-13 15:34:26 +08:00
tcp_reass - > cur_seg_num + + ;
2024-03-27 17:11:38 +08:00
2024-04-02 16:21:39 +08:00
return ret ;
2024-03-21 19:27:41 +08:00
}
2024-09-13 15:34:26 +08:00
struct tcp_segment * tcp_reassembly_pop ( struct tcp_reassembly * tcp_reass )
2024-03-21 19:27:41 +08:00
{
2024-09-13 15:34:26 +08:00
if ( tcp_reass = = NULL )
2024-04-17 17:53:42 +08:00
{
return NULL ;
}
2024-03-21 19:27:41 +08:00
2024-09-13 15:34:26 +08:00
struct interval_tree_node * node = interval_tree_iter_first ( & tcp_reass - > rb_root , tcp_reass - > recv_next , tcp_reass - > recv_next ) ;
2024-04-02 16:21:39 +08:00
if ( node = = NULL )
2024-03-21 19:27:41 +08:00
{
return NULL ;
}
2024-05-06 15:54:16 +08:00
uint64_t overlap = 0 ;
2024-04-02 16:21:39 +08:00
uint64_t min_id = UINT64_MAX ;
2024-10-31 18:53:01 +08:00
struct tcp_segment_internal * oldest = NULL ;
2024-04-02 16:21:39 +08:00
while ( node )
2024-03-21 19:27:41 +08:00
{
2024-10-31 18:53:01 +08:00
struct tcp_segment_internal * p = container_of ( node , struct tcp_segment_internal , node ) ;
2024-04-02 16:21:39 +08:00
if ( p - > id < min_id )
2024-03-25 17:30:48 +08:00
{
2024-04-02 16:21:39 +08:00
min_id = p - > id ;
oldest = p ;
2024-03-25 17:30:48 +08:00
}
2024-09-13 15:34:26 +08:00
node = interval_tree_iter_next ( node , tcp_reass - > recv_next , tcp_reass - > recv_next ) ;
2024-03-25 17:30:48 +08:00
}
2024-09-13 15:34:26 +08:00
TAILQ_REMOVE ( & tcp_reass - > lru_list , oldest , lru ) ;
interval_tree_remove ( & oldest - > node , & tcp_reass - > rb_root ) ;
2024-04-02 16:21:39 +08:00
2024-09-13 15:34:26 +08:00
tcp_reass - > cur_seg_num - - ;
2024-04-02 16:21:39 +08:00
2024-09-13 15:34:26 +08:00
if ( oldest - > node . start < tcp_reass - > recv_next )
2024-03-25 17:30:48 +08:00
{
2024-04-02 16:21:39 +08:00
// trim overlap
2024-09-13 15:34:26 +08:00
overlap = tcp_reass - > recv_next - oldest - > node . start ;
2024-04-02 16:21:39 +08:00
oldest - > seg . len - = overlap ;
oldest - > seg . data = ( char * ) oldest - > data + overlap ;
2024-03-25 17:30:48 +08:00
}
2024-09-13 15:34:26 +08:00
TCP_REASSEMBLY_LOG_DEBUG ( " tcp_reass %p pop segment %p [%lu, %lu], trim overlap %lu " , tcp_reass , & oldest - > seg , oldest - > node . start , oldest - > node . last , overlap ) ;
2024-05-06 15:54:16 +08:00
2024-04-02 16:21:39 +08:00
// update recv_next
2024-09-13 15:34:26 +08:00
tcp_reass - > recv_next = uint32_add ( tcp_reass - > recv_next , oldest - > seg . len ) ;
2024-03-21 19:27:41 +08:00
2024-04-02 16:21:39 +08:00
return & oldest - > seg ;
2024-03-21 19:27:41 +08:00
}
2024-09-13 15:34:26 +08:00
struct tcp_segment * tcp_reassembly_expire ( struct tcp_reassembly * tcp_reass , uint64_t now )
2024-03-21 19:27:41 +08:00
{
2024-09-13 15:34:26 +08:00
if ( tcp_reass = = NULL )
2024-03-21 19:27:41 +08:00
{
2024-04-02 16:21:39 +08:00
return NULL ;
2024-03-21 19:27:41 +08:00
}
2024-10-31 18:53:01 +08:00
struct tcp_segment_internal * p = TAILQ_FIRST ( & tcp_reass - > lru_list ) ;
2024-09-13 15:34:26 +08:00
if ( p & & now - p - > ts > = tcp_reass - > max_timeout )
2024-03-25 17:30:48 +08:00
{
2024-09-13 15:34:26 +08:00
tcp_reass - > cur_seg_num - - ;
TAILQ_REMOVE ( & tcp_reass - > lru_list , p , lru ) ;
interval_tree_remove ( & p - > node , & tcp_reass - > rb_root ) ;
TCP_REASSEMBLY_LOG_DEBUG ( " tcp_reass %p expire segment %p [%lu, %lu] " , tcp_reass , & p - > seg , p - > node . start , p - > node . last ) ;
2024-04-02 16:21:39 +08:00
return & p - > seg ;
2024-03-25 17:30:48 +08:00
}
2024-04-02 16:21:39 +08:00
else
2024-03-21 19:27:41 +08:00
{
2024-04-02 16:21:39 +08:00
return NULL ;
2024-03-21 19:27:41 +08:00
}
}
2024-09-13 15:34:26 +08:00
void tcp_reassembly_inc_recv_next ( struct tcp_reassembly * tcp_reass , uint32_t offset )
2024-03-21 19:27:41 +08:00
{
2024-09-13 15:34:26 +08:00
if ( tcp_reass = = NULL )
2024-04-17 17:53:42 +08:00
{
return ;
}
2024-09-13 15:34:26 +08:00
tcp_reass - > recv_next = uint32_add ( tcp_reass - > recv_next , offset ) ;
2024-09-14 18:38:37 +08:00
TCP_REASSEMBLY_LOG_DEBUG ( " tcp_reass %p inc recv_next %u to %u " , tcp_reass , offset , tcp_reass - > recv_next ) ;
2024-03-25 17:30:48 +08:00
}
2024-09-13 15:34:26 +08:00
void tcp_reassembly_set_recv_next ( struct tcp_reassembly * tcp_reass , uint32_t seq )
2024-03-25 17:30:48 +08:00
{
2024-09-13 15:34:26 +08:00
if ( tcp_reass = = NULL )
2024-04-17 17:53:42 +08:00
{
return ;
}
2024-09-13 15:34:26 +08:00
tcp_reass - > recv_next = seq ;
TCP_REASSEMBLY_LOG_DEBUG ( " tcp_reass %p set recv_next %u " , tcp_reass , seq ) ;
2024-03-25 17:30:48 +08:00
}
2024-04-02 16:21:39 +08:00
2024-09-13 15:34:26 +08:00
uint32_t tcp_reassembly_get_recv_next ( struct tcp_reassembly * tcp_reass )
2024-04-02 16:21:39 +08:00
{
2024-09-13 15:34:26 +08:00
if ( tcp_reass = = NULL )
2024-04-17 17:53:42 +08:00
{
return 0 ;
}
2024-09-13 15:34:26 +08:00
return tcp_reass - > recv_next ;
2024-04-02 16:21:39 +08:00
}