2017-08-08 23:34:35 +08:00
# include "common.h"
# include "log.h"
2017-09-10 04:04:07 -05:00
# include "git_version.h"
2017-09-14 07:01:39 -05:00
# include "lib/rs.h"
2017-09-15 03:34:29 -05:00
# include "packet.h"
2017-09-23 02:00:44 -05:00
//#include "conn_manager.h"
# include "delay_manager.h"
2017-09-15 04:07:59 -05:00
# include "classic.h"
2017-09-15 22:45:13 -05:00
2017-08-08 23:34:35 +08:00
using namespace std ;
2017-08-08 17:10:38 +08:00
typedef unsigned long long u64_t ; //this works on most platform,avoid using the PRId64
typedef long long i64_t ;
typedef unsigned int u32_t ;
typedef int i32_t ;
2017-09-15 03:34:29 -05:00
2017-08-09 17:15:35 +08:00
int dup_num = 1 ;
int dup_delay_min = 20 ; //0.1ms
int dup_delay_max = 20 ;
int jitter_min = 0 ;
int jitter_max = 0 ;
2017-09-23 02:00:44 -05:00
//int random_number_fd=-1;
2017-09-15 03:34:29 -05:00
2017-08-09 17:15:35 +08:00
int mtu_warn = 1350 ;
2017-08-08 23:34:35 +08:00
u32_t remote_address_uint32 = 0 ;
char local_address [ 100 ] , remote_address [ 100 ] ;
int local_port = - 1 , remote_port = - 1 ;
2017-08-09 17:15:35 +08:00
u64_t last_report_time = 0 ;
int report_interval = 0 ;
2017-09-23 02:00:44 -05:00
//conn_manager_t conn_manager;
delay_manager_t delay_manager ;
2017-08-08 17:10:38 +08:00
2017-09-23 02:00:44 -05:00
const int disable_conv_clear = 0 ;
struct conv_manager_t // manage the udp connections
{
//typedef hash_map map;
unordered_map < u64_t , u32_t > u64_to_conv ; //conv and u64 are both supposed to be uniq
unordered_map < u32_t , u64_t > conv_to_u64 ;
2017-09-15 22:45:13 -05:00
2017-09-23 02:00:44 -05:00
unordered_map < u32_t , u64_t > conv_last_active_time ;
2017-08-08 23:34:35 +08:00
2017-09-23 02:00:44 -05:00
unordered_map < u32_t , u64_t > : : iterator clear_it ;
2017-08-08 17:10:38 +08:00
2017-09-23 02:00:44 -05:00
unordered_map < u32_t , u64_t > : : iterator it ;
unordered_map < u32_t , u64_t > : : iterator old_it ;
2017-08-09 17:15:35 +08:00
2017-09-23 02:00:44 -05:00
//void (*clear_function)(uint64_t u64) ;
2017-08-09 17:15:35 +08:00
2017-09-23 02:00:44 -05:00
long long last_clear_time ;
2017-09-15 22:45:13 -05:00
2017-09-23 02:00:44 -05:00
conv_manager_t ( )
{
clear_it = conv_last_active_time . begin ( ) ;
long long last_clear_time = 0 ;
//clear_function=0;
}
~ conv_manager_t ( )
{
clear ( ) ;
}
int get_size ( )
{
return conv_to_u64 . size ( ) ;
}
void reserve ( )
{
u64_to_conv . reserve ( 10007 ) ;
conv_to_u64 . reserve ( 10007 ) ;
conv_last_active_time . reserve ( 10007 ) ;
}
void clear ( )
{
///// if(disable_conv_clear) return ;
2017-08-09 09:27:47 +08:00
2017-09-23 02:00:44 -05:00
if ( program_mode = = server_mode )
{
for ( it = conv_to_u64 . begin ( ) ; it ! = conv_to_u64 . end ( ) ; it + + )
{
//int fd=int((it->second<<32u)>>32u);
////// server_clear_function( it->second);//////////////todo
}
}
u64_to_conv . clear ( ) ;
conv_to_u64 . clear ( ) ;
conv_last_active_time . clear ( ) ;
2017-08-08 23:34:35 +08:00
2017-09-23 02:00:44 -05:00
clear_it = conv_last_active_time . begin ( ) ;
2017-08-08 23:34:35 +08:00
2017-09-23 02:00:44 -05:00
}
u32_t get_new_conv ( )
{
u32_t conv = get_true_random_number_nz ( ) ;
while ( conv_to_u64 . find ( conv ) ! = conv_to_u64 . end ( ) )
{
conv = get_true_random_number_nz ( ) ;
}
return conv ;
}
int is_conv_used ( u32_t conv )
2017-08-09 17:15:35 +08:00
{
2017-09-23 02:00:44 -05:00
return conv_to_u64 . find ( conv ) ! = conv_to_u64 . end ( ) ;
}
int is_u64_used ( u64_t u64 )
{
return u64_to_conv . find ( u64 ) ! = u64_to_conv . end ( ) ;
}
u32_t find_conv_by_u64 ( u64_t u64 )
{
return u64_to_conv [ u64 ] ;
}
u64_t find_u64_by_conv ( u32_t conv )
{
return conv_to_u64 [ conv ] ;
}
int update_active_time ( u32_t conv )
{
return conv_last_active_time [ conv ] = get_current_time ( ) ;
}
int insert_conv ( u32_t conv , u64_t u64 )
{
u64_to_conv [ u64 ] = conv ;
conv_to_u64 [ conv ] = u64 ;
conv_last_active_time [ conv ] = get_current_time ( ) ;
2017-08-09 17:15:35 +08:00
return 0 ;
}
2017-09-23 02:00:44 -05:00
int erase_conv ( u32_t conv )
{
if ( disable_conv_clear ) return 0 ;
u64_t u64 = conv_to_u64 [ conv ] ;
if ( program_mode = = server_mode )
{
//server_clear_function(u64);
}
conv_to_u64 . erase ( conv ) ;
u64_to_conv . erase ( u64 ) ;
conv_last_active_time . erase ( conv ) ;
return 0 ;
}
int clear_inactive ( char * ip_port = 0 )
{
if ( get_current_time ( ) - last_clear_time > conv_clear_interval )
{
last_clear_time = get_current_time ( ) ;
return clear_inactive0 ( ip_port ) ;
2017-08-08 17:10:38 +08:00
}
2017-09-23 02:00:44 -05:00
return 0 ;
2017-08-08 17:10:38 +08:00
}
2017-09-23 02:00:44 -05:00
int clear_inactive0 ( char * ip_port )
{
if ( disable_conv_clear ) return 0 ;
2017-08-08 17:10:38 +08:00
2017-09-23 02:00:44 -05:00
//map<uint32_t,uint64_t>::iterator it;
int cnt = 0 ;
it = clear_it ;
int size = conv_last_active_time . size ( ) ;
int num_to_clean = size / conv_clear_ratio + conv_clear_min ; //clear 1/10 each time,to avoid latency glitch
num_to_clean = min ( num_to_clean , size ) ;
2017-08-08 17:10:38 +08:00
2017-09-23 02:00:44 -05:00
u64_t current_time = get_current_time ( ) ;
for ( ; ; )
2017-08-08 17:10:38 +08:00
{
2017-09-23 02:00:44 -05:00
if ( cnt > = num_to_clean ) break ;
if ( conv_last_active_time . begin ( ) = = conv_last_active_time . end ( ) ) break ;
2017-08-08 23:34:35 +08:00
2017-09-23 02:00:44 -05:00
if ( it = = conv_last_active_time . end ( ) )
2017-08-08 17:10:38 +08:00
{
2017-09-23 02:00:44 -05:00
it = conv_last_active_time . begin ( ) ;
}
2017-08-08 23:34:35 +08:00
2017-09-23 02:00:44 -05:00
if ( current_time - it - > second > conv_timeout )
{
//mylog(log_info,"inactive conv %u cleared \n",it->first);
old_it = it ;
it + + ;
u32_t conv = old_it - > first ;
erase_conv ( old_it - > first ) ;
if ( ip_port = = 0 )
2017-08-08 17:10:38 +08:00
{
2017-09-23 02:00:44 -05:00
mylog ( log_info , " conv %x cleared \n " , conv ) ;
2017-08-08 17:10:38 +08:00
}
else
{
2017-09-23 02:00:44 -05:00
mylog ( log_info , " [%s]conv %x cleared \n " , ip_port , conv ) ;
2017-08-08 17:10:38 +08:00
}
}
else
{
2017-09-23 02:00:44 -05:00
it + + ;
2017-08-08 17:10:38 +08:00
}
2017-09-23 02:00:44 -05:00
cnt + + ;
}
return 0 ;
}
} ; //g_conv_manager;
struct conn_info_t //stores info for a raw connection.for client ,there is only one connection,for server there can be thousand of connection since server can
//handle multiple clients
{
conv_manager_t conv_manager ;
} ;
struct conn_manager_t //manager for connections. for client,we dont need conn_manager since there is only one connection.for server we use one conn_manager for all connections
{
2017-08-08 17:10:38 +08:00
2017-09-23 02:00:44 -05:00
u32_t ready_num ;
unordered_map < int , conn_info_t * > udp_fd_mp ; //a bit dirty to used pointer,but can void unordered_map search
unordered_map < int , conn_info_t * > timer_fd_mp ; //we can use pointer here since unordered_map.rehash() uses shallow copy
unordered_map < id_t , conn_info_t * > const_id_mp ;
unordered_map < u64_t , conn_info_t * > mp ; //put it at end so that it de-consturcts first
unordered_map < u64_t , conn_info_t * > : : iterator clear_it ;
long long last_clear_time ;
conn_manager_t ( )
{
ready_num = 0 ;
mp . reserve ( 10007 ) ;
clear_it = mp . begin ( ) ;
timer_fd_mp . reserve ( 10007 ) ;
const_id_mp . reserve ( 10007 ) ;
udp_fd_mp . reserve ( 100007 ) ;
last_clear_time = 0 ;
//current_ready_ip=0;
// current_ready_port=0;
}
int exist ( u32_t ip , uint16_t port )
{
u64_t u64 = 0 ;
u64 = ip ;
u64 < < = 32u ;
u64 | = port ;
if ( mp . find ( u64 ) ! = mp . end ( ) )
{
return 1 ;
}
return 0 ;
}
/*
int insert ( uint32_t ip , uint16_t port )
{
uint64_t u64 = 0 ;
u64 = ip ;
u64 < < = 32u ;
u64 | = port ;
mp [ u64 ] ;
return 0 ;
} */
conn_info_t * & find_insert_p ( u32_t ip , uint16_t port ) //be aware,the adress may change after rehash
{
u64_t u64 = 0 ;
u64 = ip ;
u64 < < = 32u ;
u64 | = port ;
unordered_map < u64_t , conn_info_t * > : : iterator it = mp . find ( u64 ) ;
if ( it = = mp . end ( ) )
{
mp [ u64 ] = new conn_info_t ;
}
return mp [ u64 ] ;
}
conn_info_t & find_insert ( u32_t ip , uint16_t port ) //be aware,the adress may change after rehash
{
u64_t u64 = 0 ;
u64 = ip ;
u64 < < = 32u ;
u64 | = port ;
unordered_map < u64_t , conn_info_t * > : : iterator it = mp . find ( u64 ) ;
if ( it = = mp . end ( ) )
{
mp [ u64 ] = new conn_info_t ;
}
return * mp [ u64 ] ;
}
int erase ( unordered_map < u64_t , conn_info_t * > : : iterator erase_it )
{
if ( erase_it - > second - > state . server_current_state = = server_ready )
{
ready_num - - ;
assert ( i32_t ( ready_num ) ! = - 1 ) ;
assert ( erase_it - > second ! = 0 ) ;
assert ( erase_it - > second - > timer_fd ! = 0 ) ;
assert ( erase_it - > second - > oppsite_const_id ! = 0 ) ;
assert ( const_id_mp . find ( erase_it - > second - > oppsite_const_id ) ! = const_id_mp . end ( ) ) ;
assert ( timer_fd_mp . find ( erase_it - > second - > timer_fd ) ! = timer_fd_mp . end ( ) ) ;
const_id_mp . erase ( erase_it - > second - > oppsite_const_id ) ;
timer_fd_mp . erase ( erase_it - > second - > timer_fd ) ;
close ( erase_it - > second - > timer_fd ) ; // close will auto delte it from epoll
delete ( erase_it - > second ) ;
mp . erase ( erase_it - > first ) ;
2017-08-08 17:10:38 +08:00
}
2017-09-23 02:00:44 -05:00
else
2017-08-08 17:10:38 +08:00
{
2017-09-23 02:00:44 -05:00
assert ( erase_it - > second - > blob = = 0 ) ;
assert ( erase_it - > second - > timer_fd = = 0 ) ;
assert ( erase_it - > second - > oppsite_const_id = = 0 ) ;
delete ( erase_it - > second ) ;
mp . erase ( erase_it - > first ) ;
2017-08-08 17:10:38 +08:00
}
2017-09-23 02:00:44 -05:00
return 0 ;
}
int clear_inactive ( )
{
if ( get_current_time ( ) - last_clear_time > conn_clear_interval )
{
last_clear_time = get_current_time ( ) ;
return clear_inactive0 ( ) ;
2017-08-08 17:10:38 +08:00
}
2017-09-23 02:00:44 -05:00
return 0 ;
2017-08-08 17:10:38 +08:00
}
2017-09-23 02:00:44 -05:00
int clear_inactive0 ( )
{
unordered_map < u64_t , conn_info_t * > : : iterator it ;
unordered_map < u64_t , conn_info_t * > : : iterator old_it ;
if ( disable_conn_clear ) return 0 ;
//map<uint32_t,uint64_t>::iterator it;
int cnt = 0 ;
it = clear_it ;
int size = mp . size ( ) ;
int num_to_clean = size / conn_clear_ratio + conn_clear_min ; //clear 1/10 each time,to avoid latency glitch
mylog ( log_trace , " mp.size() %d \n " , size ) ;
num_to_clean = min ( num_to_clean , ( int ) mp . size ( ) ) ;
u64_t current_time = get_current_time ( ) ;
for ( ; ; )
{
if ( cnt > = num_to_clean ) break ;
if ( mp . begin ( ) = = mp . end ( ) ) break ;
if ( it = = mp . end ( ) )
{
it = mp . begin ( ) ;
}
if ( it - > second - > state . server_current_state = = server_ready & & current_time - it - > second - > last_hb_recv_time < = server_conn_timeout )
{
it + + ;
}
else if ( it - > second - > state . server_current_state ! = server_ready & & current_time - it - > second - > last_state_time < = server_handshake_timeout )
{
it + + ;
}
else if ( it - > second - > blob ! = 0 & & it - > second - > blob - > conv_manager . get_size ( ) > 0 )
{
assert ( it - > second - > state . server_current_state = = server_ready ) ;
it + + ;
}
else
{
mylog ( log_info , " [%s:%d]inactive conn cleared \n " , my_ntoa ( it - > second - > raw_info . recv_info . src_ip ) , it - > second - > raw_info . recv_info . src_port ) ;
old_it = it ;
it + + ;
erase ( old_it ) ;
}
cnt + + ;
}
return 0 ;
}
} conn_manager ;
int VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV ;
2017-08-08 23:34:35 +08:00
int event_loop ( )
{
struct sockaddr_in local_me , local_other ;
local_listen_fd = socket ( AF_INET , SOCK_DGRAM , IPPROTO_UDP ) ;
int yes = 1 ;
//setsockopt(local_listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
2017-08-09 17:15:35 +08:00
set_buf_size ( local_listen_fd , 4 * 1024 * 1024 ) ;
2017-08-08 23:34:35 +08:00
setnonblocking ( local_listen_fd ) ;
//char data[buf_len];
//char *data=data0;
socklen_t slen = sizeof ( sockaddr_in ) ;
memset ( & local_me , 0 , sizeof ( local_me ) ) ;
local_me . sin_family = AF_INET ;
local_me . sin_port = htons ( local_port ) ;
local_me . sin_addr . s_addr = inet_addr ( local_address ) ;
if ( bind ( local_listen_fd , ( struct sockaddr * ) & local_me , slen ) = = - 1 )
{
mylog ( log_fatal , " socket bind error " ) ;
2017-08-09 09:27:47 +08:00
myexit ( 1 ) ;
2017-08-08 23:34:35 +08:00
}
int epollfd = epoll_create1 ( 0 ) ;
const int max_events = 4096 ;
struct epoll_event ev , events [ max_events ] ;
if ( epollfd < 0 )
{
mylog ( log_fatal , " epoll created return %d \n " , epollfd ) ;
2017-08-09 09:27:47 +08:00
myexit ( - 1 ) ;
2017-08-08 23:34:35 +08:00
}
ev . events = EPOLLIN ;
ev . data . fd = local_listen_fd ;
int ret = epoll_ctl ( epollfd , EPOLL_CTL_ADD , local_listen_fd , & ev ) ;
if ( ret ! = 0 )
{
mylog ( log_fatal , " epoll created return %d \n " , epollfd ) ;
2017-08-09 09:27:47 +08:00
myexit ( - 1 ) ;
2017-08-08 23:34:35 +08:00
}
int clear_timer_fd = - 1 ;
2017-09-15 03:34:29 -05:00
set_timer_ms ( epollfd , clear_timer_fd , timer_interval ) ;
2017-08-08 23:34:35 +08:00
ev . events = EPOLLIN ;
2017-09-23 02:00:44 -05:00
ev . data . fd = delay_manager . timer_fd ( ) ;
epoll_ctl ( epollfd , EPOLL_CTL_ADD , delay_manager . timer_fd , & ev ) ;
2017-08-08 23:34:35 +08:00
if ( ret < 0 )
{
2017-08-09 09:27:47 +08:00
mylog ( log_fatal , " epoll_ctl return %d \n " , ret ) ;
myexit ( - 1 ) ;
2017-08-08 23:34:35 +08:00
}
for ( ; ; )
{
int nfds = epoll_wait ( epollfd , events , max_events , 180 * 1000 ) ; //3mins
if ( nfds < 0 )
{
mylog ( log_fatal , " epoll_wait return %d \n " , nfds ) ;
2017-08-09 09:27:47 +08:00
myexit ( - 1 ) ;
2017-08-08 23:34:35 +08:00
}
int n ;
2017-08-09 09:27:47 +08:00
int clear_triggered = 0 ;
2017-08-08 23:34:35 +08:00
for ( n = 0 ; n < nfds ; + + n )
{
if ( events [ n ] . data . fd = = local_listen_fd ) //data income from local end
{
2017-08-09 17:15:35 +08:00
2017-08-08 23:34:35 +08:00
char data [ buf_len ] ;
int data_len ;
2017-08-13 10:19:17 +08:00
slen = sizeof ( sockaddr_in ) ;
2017-08-09 17:15:35 +08:00
if ( ( data_len = recvfrom ( local_listen_fd , data , max_data_len , 0 ,
2017-08-08 23:34:35 +08:00
( struct sockaddr * ) & local_other , & slen ) ) = = - 1 ) //<--first packet from a new ip:port turple
{
2017-08-09 17:15:35 +08:00
mylog ( log_error , " recv_from error,errno %s,this shouldnt happen,but lets try to pretend it didnt happen " , strerror ( errno ) ) ;
2017-08-09 09:27:47 +08:00
//myexit(1);
continue ;
2017-08-08 23:34:35 +08:00
}
2017-08-09 17:15:35 +08:00
mylog ( log_trace , " received data from listen fd,%s:%d, len=%d \n " , my_ntoa ( local_other . sin_addr . s_addr ) , ntohs ( local_other . sin_port ) , data_len ) ;
if ( data_len > mtu_warn )
{
mylog ( log_warn , " huge packet,data len=%d (>%d).strongly suggested to set a smaller mtu at upper level,to get rid of this warn \n " , data_len , mtu_warn ) ;
}
2017-08-08 23:34:35 +08:00
data [ data_len ] = 0 ; //for easier debug
u64_t u64 = pack_u64 ( local_other . sin_addr . s_addr , ntohs ( local_other . sin_port ) ) ;
if ( ! conn_manager . exist_u64 ( u64 ) )
{
2017-08-09 17:15:35 +08:00
if ( int ( conn_manager . fd_to_u64 . size ( ) ) > = max_conv_num )
{
mylog ( log_info , " new connection from %s:%d ,but ignored,bc of max_conv_num reached \n " , my_ntoa ( local_other . sin_addr . s_addr ) , ntohs ( local_other . sin_port ) ) ;
continue ;
}
2017-08-08 23:34:35 +08:00
int new_udp_fd ;
2017-09-15 03:34:29 -05:00
if ( create_new_udp ( new_udp_fd , remote_address_uint32 , remote_port ) ! = 0 )
2017-08-08 23:34:35 +08:00
{
2017-08-09 17:15:35 +08:00
mylog ( log_info , " new connection from %s:%d ,but create udp fd failed \n " , my_ntoa ( local_other . sin_addr . s_addr ) , ntohs ( local_other . sin_port ) ) ;
2017-08-08 23:34:35 +08:00
continue ;
}
struct epoll_event ev ;
mylog ( log_trace , " u64: %lld \n " , u64 ) ;
ev . events = EPOLLIN ;
ev . data . fd = new_udp_fd ;
ret = epoll_ctl ( epollfd , EPOLL_CTL_ADD , new_udp_fd , & ev ) ;
if ( ret ! = 0 ) {
2017-08-09 17:15:35 +08:00
mylog ( log_info , " new connection from %s:%d ,but add to epoll failed \n " , my_ntoa ( local_other . sin_addr . s_addr ) , ntohs ( local_other . sin_port ) ) ;
2017-08-08 23:34:35 +08:00
close ( new_udp_fd ) ;
continue ;
}
2017-08-09 17:15:35 +08:00
mylog ( log_info , " new connection from %s:%d ,created new udp fd %d \n " , my_ntoa ( local_other . sin_addr . s_addr ) , ntohs ( local_other . sin_port ) , new_udp_fd ) ;
2017-08-08 23:34:35 +08:00
conn_manager . insert_fd ( new_udp_fd , u64 ) ;
}
2017-09-23 02:00:44 -05:00
2017-08-08 23:34:35 +08:00
int new_udp_fd = conn_manager . find_fd_by_u64 ( u64 ) ;
conn_manager . update_active_time ( new_udp_fd ) ;
int ret ;
if ( is_client )
{
add_seq ( data , data_len ) ;
2017-09-23 02:00:44 -05:00
my_time_t sum = 0 ;
for ( int i = 0 ; i < dup_num ; i + + )
{
printf ( " <%d> \n " , i ) ;
char new_data [ buf_len ] ;
int new_len = 0 ;
do_obscure ( data , data_len , new_data , new_len ) ;
delay_data_t tmp ;
tmp . type = enum_send_fd ;
tmp . data = new_data ;
tmp . len = new_len ;
tmp . dest . fd = new_udp_fd ;
if ( i = = 0 )
sum + = random_between ( jitter_min , jitter_max ) * 100 ;
else
sum + = random_between ( dup_delay_min , dup_delay_max ) * 100 ;
delay_manager . add ( sum , tmp ) ;
}
/*
2017-08-09 17:15:35 +08:00
if ( jitter_max = = 0 )
{
char new_data [ buf_len ] ;
int new_len = 0 ;
do_obscure ( data , data_len , new_data , new_len ) ;
ret = send_fd ( new_udp_fd , new_data , new_len , 0 ) ;
if ( ret < 0 ) {
mylog ( log_warn , " send returned %d ,errno:%s \n " , ret , strerror ( errno ) ) ;
}
add_and_new ( new_udp_fd , dup_num - 1 , random_between ( dup_delay_min , dup_delay_max ) , data , data_len , u64 ) ;
}
else
2017-08-08 23:34:35 +08:00
{
2017-08-09 17:15:35 +08:00
add_and_new ( new_udp_fd , dup_num , random_between ( jitter_min , jitter_max ) , data , data_len , u64 ) ;
2017-09-23 02:00:44 -05:00
} */
2017-08-09 17:15:35 +08:00
packet_send_count + + ;
2017-08-08 23:34:35 +08:00
}
else
{
2017-09-23 02:00:44 -05:00
printf ( " i got a packet \n " ) ;
2017-08-08 23:34:35 +08:00
char new_data [ buf_len ] ;
int new_len ;
2017-08-09 17:15:35 +08:00
2017-08-08 23:34:35 +08:00
if ( de_obscure ( data , data_len , new_data , new_len ) ! = 0 ) {
2017-09-23 02:00:44 -05:00
printf ( " failed 1 \n " ) ;
2017-08-09 09:27:47 +08:00
mylog ( log_trace , " de_obscure failed \n " ) ;
2017-08-08 23:34:35 +08:00
continue ;
}
2017-08-09 17:15:35 +08:00
//dup_packet_recv_count++;
2017-08-08 23:34:35 +08:00
if ( remove_seq ( new_data , new_len ) ! = 0 ) {
2017-09-23 02:00:44 -05:00
printf ( " failed 2 \n " ) ;
2017-08-09 09:27:47 +08:00
mylog ( log_trace , " remove_seq failed \n " ) ;
2017-08-08 23:34:35 +08:00
continue ;
}
2017-08-09 17:15:35 +08:00
//packet_recv_count++;
ret = send_fd ( new_udp_fd , new_data , new_len , 0 ) ;
if ( ret < 0 ) {
mylog ( log_warn , " send returned %d,%s \n " , ret , strerror ( errno ) ) ;
//perror("what happened????");
}
2017-08-08 23:34:35 +08:00
}
2017-08-09 17:15:35 +08:00
2017-08-08 23:34:35 +08:00
}
else if ( events [ n ] . data . fd = = clear_timer_fd )
{
2017-08-09 09:27:47 +08:00
clear_triggered = 1 ;
2017-08-09 17:15:35 +08:00
if ( report_interval ! = 0 & & get_current_time ( ) - last_report_time > u64_t ( report_interval ) * 1000 )
{
last_report_time = get_current_time ( ) ;
if ( is_client )
mylog ( log_info , " client-->server: %llu,%llu(include dup); server-->client %llu,%lld(include dup) \n " , packet_send_count ,
dup_packet_send_count , packet_recv_count , dup_packet_recv_count ) ;
else
mylog ( log_info , " client-->server: %llu,%llu(include dup); server-->client %llu,%lld(include dup) \n " , packet_recv_count , dup_packet_recv_count , packet_send_count ,
dup_packet_send_count ) ;
}
2017-08-08 23:34:35 +08:00
}
2017-09-23 02:00:44 -05:00
else if ( events [ n ] . data . fd = = delay_manager . timer_fd )
2017-08-08 23:34:35 +08:00
{
uint64_t value ;
2017-09-23 02:00:44 -05:00
read ( delay_manager . timer_fd , & value , 8 ) ;
2017-08-08 23:34:35 +08:00
//printf("<timerfd_triggered, %d>",delay_mp.size());
//fflush(stdout);
}
else
{
int udp_fd = events [ n ] . data . fd ;
if ( ! conn_manager . exist_fd ( udp_fd ) ) continue ;
char data [ buf_len ] ;
2017-08-09 17:15:35 +08:00
int data_len = recv ( udp_fd , data , max_data_len , 0 ) ;
mylog ( log_trace , " received data from udp fd %d, len=%d \n " , udp_fd , data_len ) ;
2017-08-08 23:34:35 +08:00
if ( data_len < 0 )
{
2017-08-09 17:15:35 +08:00
if ( errno = = ECONNREFUSED )
{
//conn_manager.clear_list.push_back(udp_fd);
mylog ( log_debug , " recv failed %d ,udp_fd%d,errno:%s \n " , data_len , udp_fd , strerror ( errno ) ) ;
}
mylog ( log_warn , " recv failed %d ,udp_fd%d,errno:%s \n " , data_len , udp_fd , strerror ( errno ) ) ;
2017-08-08 23:34:35 +08:00
continue ;
}
2017-08-09 17:15:35 +08:00
if ( data_len > mtu_warn )
{
mylog ( log_warn , " huge packet,data len=%d (>%d).strongly suggested to set a smaller mtu at upper level,to get rid of this warn \n " , data_len , mtu_warn ) ;
}
2017-08-08 23:34:35 +08:00
assert ( conn_manager . exist_fd ( udp_fd ) ) ;
conn_manager . update_active_time ( udp_fd ) ;
u64_t u64 = conn_manager . find_u64_by_fd ( udp_fd ) ;
if ( is_client )
{
char new_data [ buf_len ] ;
int new_len ;
if ( de_obscure ( data , data_len , new_data , new_len ) ! = 0 ) {
2017-08-09 09:27:47 +08:00
mylog ( log_debug , " data_len=%d \n " , data_len ) ;
2017-08-08 23:34:35 +08:00
continue ;
}
2017-08-09 17:15:35 +08:00
//dup_packet_recv_count++;
2017-08-08 23:34:35 +08:00
if ( remove_seq ( new_data , new_len ) ! = 0 ) {
2017-08-09 09:27:47 +08:00
mylog ( log_debug , " remove_seq error \n " ) ;
2017-08-08 23:34:35 +08:00
continue ;
}
2017-08-09 17:15:35 +08:00
//packet_recv_count++;
2017-09-23 02:00:44 -05:00
ret = sendto_u64 ( u64 , new_data ,
new_len , 0 ) ;
2017-08-09 17:15:35 +08:00
if ( ret < 0 ) {
mylog ( log_warn , " sento returned %d,%s \n " , ret , strerror ( errno ) ) ;
//perror("ret<0");
}
2017-08-08 23:34:35 +08:00
}
else
{
add_seq ( data , data_len ) ;
2017-09-23 02:00:44 -05:00
my_time_t sum = 0 ;
for ( int i = 0 ; i < dup_num ; i + + )
2017-08-09 17:15:35 +08:00
{
2017-09-23 02:00:44 -05:00
printf ( " <%d> \n " , i ) ;
2017-08-09 17:15:35 +08:00
char new_data [ buf_len ] ;
int new_len = 0 ;
do_obscure ( data , data_len , new_data , new_len ) ;
2017-09-23 02:00:44 -05:00
delay_data_t tmp ;
tmp . type = enum_sendto_u64 ;
tmp . data = new_data ;
tmp . len = new_len ;
tmp . dest . u64 = u64 ;
if ( i = = 0 )
sum + = random_between ( jitter_min , jitter_max ) * 100 ;
else
sum + = random_between ( dup_delay_min , dup_delay_max ) * 100 ;
delay_manager . add ( sum , tmp ) ;
2017-08-08 23:34:35 +08:00
}
2017-08-09 17:15:35 +08:00
packet_send_count + + ;
2017-08-08 23:34:35 +08:00
}
2017-08-09 17:15:35 +08:00
//mylog(log_trace, "%s :%d\n", inet_ntoa(tmp_sockaddr.sin_addr),
// ntohs(tmp_sockaddr.sin_port));
//mylog(log_trace, "%d byte sent\n", ret);
2017-08-08 23:34:35 +08:00
}
}
2017-09-23 02:00:44 -05:00
delay_manager . check ( ) ;
//conn_manager.check_clear_list();
2017-08-09 09:27:47 +08:00
if ( clear_triggered ) // 删除操作在epoll event的最后进行, 防止event cache中的fd失效。
{
u64_t value ;
read ( clear_timer_fd , & value , 8 ) ;
mylog ( log_trace , " timer! \n " ) ;
conn_manager . clear_inactive ( ) ;
}
2017-08-08 23:34:35 +08:00
}
2017-08-09 09:27:47 +08:00
myexit ( 0 ) ;
2017-08-08 23:34:35 +08:00
return 0 ;
}
2017-09-14 12:22:47 -05:00
int unit_test ( )
{
int i , j , k ;
void * code = fec_new ( 3 , 6 ) ;
char arr [ 6 ] [ 100 ] =
{
" aaa " , " bbb " , " ccc "
, " ddd " , " eee " , " fff "
} ;
char * data [ 6 ] ;
for ( i = 0 ; i < 6 ; i + + )
{
data [ i ] = arr [ i ] ;
}
rs_encode ( code , data , 3 ) ;
2017-09-15 03:34:29 -05:00
//printf("%d %d",(int)(unsigned char)arr[5][0],(int)('a'^'b'^'c'^'d'^'e'));
2017-09-14 12:22:47 -05:00
for ( i = 0 ; i < 6 ; i + + )
{
printf ( " <%s> " , data [ i ] ) ;
}
data [ 0 ] = 0 ;
2017-09-15 03:34:29 -05:00
//data[1]=0;
//data[5]=0;
2017-09-14 12:22:47 -05:00
int ret = rs_decode ( code , data , 3 ) ;
printf ( " ret:%d \n " , ret ) ;
for ( i = 0 ; i < 6 ; i + + )
{
printf ( " <%s> " , data [ i ] ) ;
}
fec_free ( code ) ;
return 0 ;
}
2017-08-09 17:15:35 +08:00
void print_help ( )
{
2017-09-10 04:04:07 -05:00
char git_version_buf [ 100 ] = { 0 } ;
strncpy ( git_version_buf , gitversion , 10 ) ;
2017-08-09 17:15:35 +08:00
printf ( " UDPspeeder \n " ) ;
2017-09-10 04:04:07 -05:00
printf ( " git version:%s " , git_version_buf ) ;
printf ( " build date:%s %s \n " , __DATE__ , __TIME__ ) ;
2017-08-09 17:15:35 +08:00
printf ( " repository: https://github.com/wangyu-/UDPspeeder \n " ) ;
printf ( " \n " ) ;
printf ( " usage: \n " ) ;
printf ( " run as client : ./this_program -c -l local_listen_ip:local_port -r server_ip:server_port [options] \n " ) ;
printf ( " run as server : ./this_program -s -l server_listen_ip:server_port -r remote_ip:remote_port [options] \n " ) ;
printf ( " \n " ) ;
printf ( " common option,must be same on both sides: \n " ) ;
printf ( " -k,--key <string> key for simple xor encryption,default: \" secret key \" \n " ) ;
printf ( " main options: \n " ) ;
printf ( " -d <number> duplicated packet number, -d 0 means no duplicate. default value:0 \n " ) ;
printf ( " -t <number> duplicated packet delay time, unit: 0.1ms,default value:20(2ms) \n " ) ;
printf ( " -j <number> simulated jitter.randomly delay first packet for 0~jitter_value*0.1 ms,to \n " ) ;
printf ( " create simulated jitter.default value:0.do not use if you dont \n " ) ;
printf ( " know what it means \n " ) ;
printf ( " --report <number> turn on udp send/recv report,and set a time interval for reporting,unit:s \n " ) ;
printf ( " advanced options: \n " ) ;
printf ( " -t tmin:tmax simliar to -t above,but delay randomly between tmin and tmax \n " ) ;
printf ( " -j jmin:jmax simliar to -j above,but create jitter randomly between jmin and jmax \n " ) ;
2017-09-11 10:29:24 -05:00
printf ( " --random-drop <number> simulate packet loss ,unit:0.01%% \n " ) ;
2017-09-11 10:28:32 -05:00
printf ( " --disable-filter disable duplicate packet filter. \n " ) ;
2017-09-11 10:26:56 -05:00
printf ( " -m <number> max pending packets,to prevent the program from eating up all your memory, \n " ) ;
printf ( " default value:0(disabled). \n " ) ;
2017-08-09 17:15:35 +08:00
printf ( " other options: \n " ) ;
printf ( " --log-level <number> 0:never 1:fatal 2:error 3:warn \n " ) ;
printf ( " 4:info (default) 5:debug 6:trace \n " ) ;
printf ( " --log-position enable file name,function name,line number in log \n " ) ;
printf ( " --disable-color disable log color \n " ) ;
2017-08-13 10:19:17 +08:00
printf ( " --sock-buf <number> buf size for socket,>=10 and <=10240,unit:kbyte,default:1024 \n " ) ;
2017-08-09 17:15:35 +08:00
//printf(" -p use multi-process mode instead of epoll.very costly,only for test,do dont use\n");
printf ( " -h,--help print this help message \n " ) ;
//printf("common options,these options must be same on both side\n");
}
2017-08-08 23:34:35 +08:00
void process_arg ( int argc , char * argv [ ] )
{
2017-08-08 17:10:38 +08:00
int i , j , k ;
int opt ;
2017-08-08 23:34:35 +08:00
static struct option long_options [ ] =
{
{ " log-level " , required_argument , 0 , 1 } ,
{ " log-position " , no_argument , 0 , 1 } ,
{ " disable-color " , no_argument , 0 , 1 } ,
2017-08-09 09:27:47 +08:00
{ " disable-filter " , no_argument , 0 , 1 } ,
2017-08-09 17:15:35 +08:00
{ " sock-buf " , required_argument , 0 , 1 } ,
{ " random-drop " , required_argument , 0 , 1 } ,
{ " report " , required_argument , 0 , 1 } ,
2017-08-08 23:34:35 +08:00
{ NULL , 0 , 0 , 0 }
} ;
int option_index = 0 ;
2017-08-09 17:15:35 +08:00
if ( argc = = 1 )
{
print_help ( ) ;
myexit ( - 1 ) ;
}
for ( i = 0 ; i < argc ; i + + )
2017-09-14 12:22:47 -05:00
{
if ( strcmp ( argv [ i ] , " --unit-test " ) = = 0 )
{
unit_test ( ) ;
myexit ( 0 ) ;
}
}
for ( i = 0 ; i < argc ; i + + )
2017-08-09 17:15:35 +08:00
{
if ( strcmp ( argv [ i ] , " -h " ) = = 0 | | strcmp ( argv [ i ] , " --help " ) = = 0 )
{
print_help ( ) ;
myexit ( 0 ) ;
}
}
2017-08-08 23:34:35 +08:00
for ( i = 0 ; i < argc ; i + + )
{
if ( strcmp ( argv [ i ] , " --log-level " ) = = 0 )
{
if ( i < argc - 1 )
{
sscanf ( argv [ i + 1 ] , " %d " , & log_level ) ;
if ( 0 < = log_level & & log_level < log_end )
{
}
else
{
log_bare ( log_fatal , " invalid log_level \n " ) ;
myexit ( - 1 ) ;
}
}
}
if ( strcmp ( argv [ i ] , " --disable-color " ) = = 0 )
{
enable_log_color = 0 ;
}
}
2017-08-09 17:15:35 +08:00
mylog ( log_info , " argc=%d " , argc ) ;
for ( i = 0 ; i < argc ; i + + ) {
log_bare ( log_info , " %s " , argv [ i ] ) ;
}
log_bare ( log_info , " \n " ) ;
2017-08-08 17:10:38 +08:00
if ( argc = = 1 )
{
2017-08-09 17:15:35 +08:00
print_help ( ) ;
myexit ( - 1 ) ;
2017-08-08 17:10:38 +08:00
}
2017-08-09 17:15:35 +08:00
2017-08-08 17:10:38 +08:00
int no_l = 1 , no_r = 1 ;
2017-08-09 17:15:35 +08:00
while ( ( opt = getopt_long ( argc , argv , " l:r:d:t:hcspk:j:m: " , long_options , & option_index ) ) ! = - 1 )
2017-08-08 17:10:38 +08:00
{
//string opt_key;
//opt_key+=opt;
switch ( opt )
{
2017-08-08 23:34:35 +08:00
case ' p ' :
2017-09-23 02:00:44 -05:00
//multi_process_mode=1;
2017-08-08 23:34:35 +08:00
break ;
2017-08-09 09:27:47 +08:00
case ' k ' :
sscanf ( optarg , " %s \n " , key_string ) ;
2017-08-09 17:15:35 +08:00
mylog ( log_debug , " key=%s \n " , key_string ) ;
2017-08-09 09:27:47 +08:00
if ( strlen ( key_string ) = = 0 )
{
mylog ( log_fatal , " key len=0?? \n " ) ;
myexit ( - 1 ) ;
}
break ;
2017-08-09 17:15:35 +08:00
case ' m ' :
sscanf ( optarg , " %d \n " , & max_pending_packet ) ;
if ( max_pending_packet < 1000 )
2017-08-08 17:10:38 +08:00
{
2017-08-09 17:15:35 +08:00
mylog ( log_fatal , " max_pending_packet must be >1000 \n " ) ;
2017-08-09 09:27:47 +08:00
myexit ( - 1 ) ;
2017-08-08 17:10:38 +08:00
}
break ;
2017-08-09 17:15:35 +08:00
case ' j ' :
if ( strchr ( optarg , ' : ' ) = = 0 )
{
int jitter ;
sscanf ( optarg , " %d \n " , & jitter ) ;
if ( jitter < 0 | | jitter > 1000 * 100 )
{
mylog ( log_fatal , " jitter must be between 0 and 100,000(10 second) \n " ) ;
myexit ( - 1 ) ;
}
jitter_min = 0 ;
jitter_max = jitter ;
}
else
{
sscanf ( optarg , " %d:%d \n " , & jitter_min , & jitter_max ) ;
if ( jitter_min < 0 | | jitter_max < 0 | | jitter_min > jitter_max )
{
mylog ( log_fatal , " must satisfy 0<=jmin<=jmax \n " ) ;
myexit ( - 1 ) ;
}
}
break ;
2017-08-08 17:10:38 +08:00
case ' t ' :
2017-08-09 17:15:35 +08:00
if ( strchr ( optarg , ' : ' ) = = 0 )
{
int dup_delay = - 1 ;
sscanf ( optarg , " %d \n " , & dup_delay ) ;
if ( dup_delay < 1 | | dup_delay > 1000 * 100 )
{
mylog ( log_fatal , " dup_delay must be between 1 and 100,000(10 second) \n " ) ;
myexit ( - 1 ) ;
}
dup_delay_min = dup_delay_max = dup_delay ;
}
else
{
sscanf ( optarg , " %d:%d \n " , & dup_delay_min , & dup_delay_max ) ;
if ( dup_delay_min < 1 | | dup_delay_max < 1 | | dup_delay_min > dup_delay_max )
{
mylog ( log_fatal , " must satisfy 1<=dmin<=dmax \n " ) ;
myexit ( - 1 ) ;
}
}
break ;
case ' d ' :
dup_num = - 1 ;
sscanf ( optarg , " %d \n " , & dup_num ) ;
if ( dup_num < 0 | | dup_num > 5 )
2017-08-08 17:10:38 +08:00
{
2017-08-09 17:15:35 +08:00
mylog ( log_fatal , " dup_num must be between 0 and 5 \n " ) ;
2017-08-09 09:27:47 +08:00
myexit ( - 1 ) ;
2017-08-08 17:10:38 +08:00
}
2017-08-09 17:15:35 +08:00
dup_num + = 1 ;
2017-08-08 17:10:38 +08:00
break ;
case ' c ' :
is_client = 1 ;
break ;
case ' s ' :
is_server = 1 ;
break ;
case ' l ' :
no_l = 0 ;
if ( strchr ( optarg , ' : ' ) ! = 0 )
{
sscanf ( optarg , " %[^:]:%d " , local_address , & local_port ) ;
}
else
{
2017-08-09 09:27:47 +08:00
mylog ( log_fatal , " -r ip:port \n " ) ;
myexit ( 1 ) ;
2017-08-08 17:10:38 +08:00
strcpy ( local_address , " 127.0.0.1 " ) ;
sscanf ( optarg , " %d " , & local_port ) ;
}
break ;
case ' r ' :
no_r = 0 ;
if ( strchr ( optarg , ' : ' ) ! = 0 )
{
//printf("in :\n");
//printf("%s\n",optarg);
sscanf ( optarg , " %[^:]:%d " , remote_address , & remote_port ) ;
//printf("%d\n",remote_port);
}
else
{
2017-08-09 09:27:47 +08:00
mylog ( log_fatal , " -r ip:port \n " ) ;
myexit ( 1 ) ;
2017-08-08 17:10:38 +08:00
strcpy ( remote_address , " 127.0.0.1 " ) ;
sscanf ( optarg , " %d " , & remote_port ) ;
}
break ;
case ' h ' :
break ;
2017-08-08 23:34:35 +08:00
case 1 :
if ( strcmp ( long_options [ option_index ] . name , " log-level " ) = = 0 )
{
}
2017-08-09 09:27:47 +08:00
else if ( strcmp ( long_options [ option_index ] . name , " disable-filter " ) = = 0 )
{
disable_replay_filter = 1 ;
//enable_log_color=0;
}
2017-08-08 23:34:35 +08:00
else if ( strcmp ( long_options [ option_index ] . name , " disable-color " ) = = 0 )
{
//enable_log_color=0;
}
else if ( strcmp ( long_options [ option_index ] . name , " log-position " ) = = 0 )
{
enable_log_position = 1 ;
}
2017-08-09 17:15:35 +08:00
else if ( strcmp ( long_options [ option_index ] . name , " random-drop " ) = = 0 )
{
sscanf ( optarg , " %d " , & random_drop ) ;
if ( random_drop < 0 | | random_drop > 10000 )
{
mylog ( log_fatal , " random_drop must be between 0 10000 \n " ) ;
myexit ( - 1 ) ;
}
}
else if ( strcmp ( long_options [ option_index ] . name , " report " ) = = 0 )
{
sscanf ( optarg , " %d " , & report_interval ) ;
if ( report_interval < = 0 )
{
mylog ( log_fatal , " report_interval must be >0 \n " ) ;
myexit ( - 1 ) ;
}
}
else if ( strcmp ( long_options [ option_index ] . name , " sock-buf " ) = = 0 )
{
int tmp = - 1 ;
sscanf ( optarg , " %d " , & tmp ) ;
if ( 10 < = tmp & & tmp < = 10 * 1024 )
{
socket_buf_size = tmp * 1024 ;
}
else
{
mylog ( log_fatal , " sock-buf value must be between 1 and 10240 (kbyte) \n " ) ;
myexit ( - 1 ) ;
}
}
else
{
mylog ( log_fatal , " unknown option \n " ) ;
myexit ( - 1 ) ;
}
2017-08-08 23:34:35 +08:00
break ;
2017-08-08 17:10:38 +08:00
default :
2017-08-09 09:27:47 +08:00
mylog ( log_fatal , " unknown option <%x> " , opt ) ;
myexit ( - 1 ) ;
2017-08-08 17:10:38 +08:00
}
}
if ( no_l )
2017-08-09 09:27:47 +08:00
mylog ( log_fatal , " error: -i not found \n " ) ;
2017-08-08 17:10:38 +08:00
if ( no_r )
2017-08-09 09:27:47 +08:00
mylog ( log_fatal , " error: -o not found \n " ) ;
2017-08-08 17:10:38 +08:00
if ( no_l | | no_r )
2017-08-09 09:27:47 +08:00
myexit ( - 1 ) ;
2017-08-08 17:10:38 +08:00
if ( is_client = = 0 & & is_server = = 0 )
{
2017-08-09 09:27:47 +08:00
mylog ( log_fatal , " -s -c hasnt been set \n " ) ;
myexit ( - 1 ) ;
2017-08-08 17:10:38 +08:00
}
if ( is_client = = 1 & & is_server = = 1 )
{
2017-08-09 09:27:47 +08:00
mylog ( log_fatal , " -s -c cant be both set \n " ) ;
myexit ( - 1 ) ;
2017-08-08 17:10:38 +08:00
}
2017-08-08 23:34:35 +08:00
}
2017-09-14 12:22:47 -05:00
2017-08-08 23:34:35 +08:00
int main ( int argc , char * argv [ ] )
{
2017-09-15 22:45:13 -05:00
if ( argc = = 1 | | argc = = 0 )
{
printf ( " this_program classic \n " ) ;
printf ( " this_program fec \n " ) ;
return 0 ;
}
2017-09-23 02:00:44 -05:00
/*
if ( argc > = 2 & & strcmp ( argv [ 1 ] , " fec " ) ! = 0 )
2017-09-15 22:45:13 -05:00
{
2017-09-23 02:00:44 -05:00
printf ( " running into classic mode! \n " ) ;
2017-09-15 22:45:13 -05:00
return classic : : main ( argc , argv ) ;
2017-09-23 02:00:44 -05:00
} */
2017-08-13 10:19:17 +08:00
assert ( sizeof ( u64_t ) = = 8 ) ;
assert ( sizeof ( i64_t ) = = 8 ) ;
assert ( sizeof ( u32_t ) = = 4 ) ;
assert ( sizeof ( i32_t ) = = 4 ) ;
2017-08-08 23:34:35 +08:00
dup2 ( 1 , 2 ) ; //redirect stderr to stdout
int i , j , k ;
process_arg ( argc , argv ) ;
2017-09-23 02:00:44 -05:00
delay_manager . capacity = max_pending_packet ;
2017-08-09 09:27:47 +08:00
init_random_number_fd ( ) ;
2017-08-08 23:34:35 +08:00
remote_address_uint32 = inet_addr ( remote_address ) ;
2017-09-23 02:00:44 -05:00
event_loop ( ) ;
2017-08-08 23:34:35 +08:00
2017-08-08 17:10:38 +08:00
return 0 ;
}
2017-08-08 23:34:35 +08:00