Commit d41ede3e authored by Simon Morlat's avatar Simon Morlat

implement transport timeout for tcp and tls. Default value is set to 63 seconds, as Linux.

parent f1f6fd7c
......@@ -48,6 +48,9 @@ BELLESIP_EXPORT void belle_sip_stack_main(belle_sip_stack_t *stack);
BELLESIP_EXPORT void belle_sip_stack_sleep(belle_sip_stack_t *stack, unsigned int milliseconds);
/*the transport timeout is typically the maximum time given for making a connection*/
BELLESIP_EXPORT void belle_sip_stack_set_transport_timeout(belle_sip_stack_t *stack, int timeout_ms);
BELLESIP_EXPORT int belle_sip_stack_get_transport_timeout(const belle_sip_stack_t *stack);
BELLESIP_EXPORT int belle_sip_stack_get_dns_timeout(const belle_sip_stack_t *stack);
......
......@@ -112,7 +112,7 @@ belle_sip_stack_t * belle_sip_stack_new(const char *properties){
stack->timer_config.T1=500;
stack->timer_config.T2=4000;
stack->timer_config.T4=5000;
stack->transport_timeout=30000;
stack->transport_timeout=63000;
stack->dns_timeout=15000;
stack->dns_srv_enabled=TRUE;
stack->inactive_transport_timeout=3600; /*one hour*/
......@@ -123,6 +123,10 @@ const belle_sip_timer_config_t *belle_sip_stack_get_timer_config(const belle_sip
return &stack->timer_config;
}
void belle_sip_stack_set_transport_timeout(belle_sip_stack_t *stack, int timeout_ms){
stack->transport_timeout=timeout_ms;
}
int belle_sip_stack_get_transport_timeout(const belle_sip_stack_t *stack){
return stack->transport_timeout;
}
......
......@@ -141,6 +141,7 @@ int stream_channel_connect(belle_sip_stream_channel_t *obj, const struct addrinf
}
belle_sip_channel_set_socket((belle_sip_channel_t*)obj,sock,(belle_sip_source_func_t)stream_channel_process_data);
belle_sip_source_set_events((belle_sip_source_t*)obj,BELLE_SIP_EVENT_WRITE|BELLE_SIP_EVENT_ERROR);
belle_sip_source_set_timeout((belle_sip_source_t*)obj,belle_sip_stack_get_transport_timeout(obj->base.stack));
belle_sip_main_loop_add_source(obj->base.stack->ml,(belle_sip_source_t*)obj);
return 0;
}
......@@ -164,11 +165,24 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_stream_channel_t)
}
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
int finalize_stream_connection(belle_sip_stream_channel_t *obj, struct sockaddr *addr, socklen_t* slen) {
int finalize_stream_connection(belle_sip_stream_channel_t *obj, unsigned int revents, struct sockaddr *addr, socklen_t* slen) {
int err, errnum;
socklen_t optlen=sizeof(errnum);
belle_sip_socket_t sock=belle_sip_source_get_socket((belle_sip_source_t*)obj);
if (revents & BELLE_SIP_EVENT_READ){
belle_sip_warning("channel [%p]: getting read event while connecting",obj);
return -1;
}
if (revents==BELLE_SIP_EVENT_TIMEOUT){
belle_sip_warning("channel [%p]: user-defined transport timeout.",obj);
return -1;
}
if (!(revents & BELLE_SIP_EVENT_WRITE)){
belle_sip_warning("channel [%p]: getting unexpected event while connecting",obj);
return -1;
}
err=getsockopt(sock,SOL_SOCKET,SO_ERROR,(void*)&errnum,&optlen);
if (err!=0){
belle_sip_error("Failed to retrieve connection status for fd [%i]: cause [%s]",sock,belle_sip_get_socket_error_string());
......@@ -203,17 +217,16 @@ static int stream_channel_process_data(belle_sip_stream_channel_t *obj,unsigned
belle_sip_message("TCP channel process_data");
if (state == BELLE_SIP_CHANNEL_CONNECTING && (revents & BELLE_SIP_EVENT_WRITE)) {
if (finalize_stream_connection(obj,(struct sockaddr*)&ss,&addrlen)) {
if (state == BELLE_SIP_CHANNEL_CONNECTING ) {
if (finalize_stream_connection(obj,revents,(struct sockaddr*)&ss,&addrlen)) {
belle_sip_error("Cannot connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(base),base->peer_name,base->peer_port);
channel_set_state(base,BELLE_SIP_CHANNEL_ERROR);
return BELLE_SIP_STOP;
}
belle_sip_source_set_events((belle_sip_source_t*)obj,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR);
belle_sip_source_set_timeout((belle_sip_source_t*)obj,-1);
belle_sip_channel_set_ready(base,(struct sockaddr*)&ss,addrlen);
return BELLE_SIP_CONTINUE;
} else if (state == BELLE_SIP_CHANNEL_READY) {
return belle_sip_channel_process_data(base,revents);
} else {
......
......@@ -49,7 +49,7 @@ belle_sip_channel_t * belle_sip_stream_channel_new_child(belle_sip_stack_t *stac
void stream_channel_close(belle_sip_stream_channel_t *obj);
int stream_channel_connect(belle_sip_stream_channel_t *obj, const struct addrinfo *ai);
/*return 0 if succeed*/
int finalize_stream_connection(belle_sip_stream_channel_t *obj, struct sockaddr *addr, socklen_t* slen);
int finalize_stream_connection(belle_sip_stream_channel_t *obj, unsigned int revents, struct sockaddr *addr, socklen_t* slen);
int stream_channel_send(belle_sip_stream_channel_t *obj, const void *buf, size_t buflen);
int stream_channel_recv(belle_sip_stream_channel_t *obj, void *buf, size_t buflen);
......
......@@ -180,33 +180,50 @@ static int tls_channel_handshake(belle_sip_tls_channel_t *channel) {
}
return ret;
}
static int tls_process_handshake(belle_sip_channel_t *obj){
belle_sip_tls_channel_t* channel=(belle_sip_tls_channel_t*)obj;
int err=tls_channel_handshake(channel);
if (err==0){
belle_sip_message("Channel [%p]: SSL handshake finished.",obj);
belle_sip_source_set_timeout((belle_sip_source_t*)obj,-1);
belle_sip_channel_set_ready(obj,(struct sockaddr*)&channel->ss,channel->socklen);
}else if (err==POLARSSL_ERR_NET_WANT_READ || err==POLARSSL_ERR_NET_WANT_WRITE){
belle_sip_message("Channel [%p]: SSL handshake in progress...",obj);
}else{
char tmp[128];
error_strerror(err,tmp,sizeof(tmp));
belle_sip_error("Channel [%p]: SSL handshake failed : %s",obj,tmp);
return -1;
}
return 0;
}
static int tls_process_data(belle_sip_channel_t *obj,unsigned int revents){
belle_sip_tls_channel_t* channel=(belle_sip_tls_channel_t*)obj;
int err;
if (obj->state == BELLE_SIP_CHANNEL_CONNECTING ) {
if (!channel->socket_connected && (revents & BELLE_SIP_EVENT_WRITE)) {
if (!channel->socket_connected) {
channel->socklen=sizeof(channel->ss);
if (finalize_stream_connection((belle_sip_stream_channel_t*)obj,(struct sockaddr*)&channel->ss,&channel->socklen)) {
if (finalize_stream_connection((belle_sip_stream_channel_t*)obj,revents,(struct sockaddr*)&channel->ss,&channel->socklen)) {
goto process_error;
}
belle_sip_source_set_events((belle_sip_source_t*)channel,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR);
channel->socket_connected=1;
belle_sip_message("Channel [%p]: Connected at TCP level, now doing TLS handshake",obj);
}
err=tls_channel_handshake(channel) /*ssl_handshake(&channel->sslctx)*/;
if (err==0){
belle_sip_message("Channel [%p]: SSL handshake finished.",obj);
belle_sip_channel_set_ready(obj,(struct sockaddr*)&channel->ss,channel->socklen);
}else if (err==POLARSSL_ERR_NET_WANT_READ || err==POLARSSL_ERR_NET_WANT_WRITE){
belle_sip_message("Channel [%p]: SSL handshake in progress...",obj);
channel->socket_connected=1;
belle_sip_source_set_events((belle_sip_source_t*)channel,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR);
belle_sip_source_set_timeout((belle_sip_source_t*)obj,belle_sip_stack_get_transport_timeout(obj->stack));
if (tls_process_handshake(obj)==-1) goto process_error;
}else{
char tmp[128];
error_strerror(err,tmp,sizeof(tmp));
belle_sip_error("Channel [%p]: SSL handshake failed : %s",obj,tmp);
goto process_error;
if (revents & BELLE_SIP_EVENT_READ){
if (tls_process_handshake(obj)==-1) goto process_error;
}else if (revents==BELLE_SIP_EVENT_TIMEOUT){
belle_sip_error("channel [%p]: SSL handshake took too much time.",obj);
goto process_error;
}else{
belle_sip_warning("channel [%p]: unexpected event [%i] during TLS handshake.",obj,revents);
}
}
} else if ( obj->state == BELLE_SIP_CHANNEL_READY) {
return belle_sip_channel_process_data(obj,revents);
} else {
......
......@@ -29,10 +29,15 @@ const char *test_domain="test.linphone.org";
const char *auth_domain="sip.linphone.org";
const char *client_auth_domain="client.example.org";
const char *client_auth_outbound_proxy="sips:sip2.linphone.org:5063";
const char *no_server_running_here="sip:test.linphone.org:3;transport=tcp";
const char *no_response_here="sip:78.220.48.77:3;transport=tcp";
const char *test_domain_tls_to_tcp="sip:test.linphone.org:5060;transport=tls";
static int is_register_ok;
static int number_of_challenge;
static int using_transaction;
static int io_error_count=0;
belle_sip_stack_t * stack;
belle_sip_provider_t *prov;
static belle_sip_listener_t* l;
......@@ -50,8 +55,9 @@ static void process_dialog_terminated(void *user_ctx, const belle_sip_dialog_ter
static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
BELLESIP_UNUSED(user_ctx);
BELLESIP_UNUSED(event);
belle_sip_message("process_io_error");
belle_sip_message("process_io_error, exiting main loop");
belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack));
io_error_count++;
/*CU_ASSERT(CU_FALSE);*/
}
......@@ -278,6 +284,7 @@ belle_sip_request_t* try_register_user_at_domain(belle_sip_stack_t * stack
belle_sip_header_via_new(),
70);
is_register_ok=0;
io_error_count=0;
using_transaction=0;
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(600)));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_contact_new()));
......@@ -287,7 +294,7 @@ belle_sip_request_t* try_register_user_at_domain(belle_sip_stack_t * stack
belle_sip_client_transaction_t *t=belle_sip_provider_create_client_transaction(prov,req);
belle_sip_client_transaction_send_request_to(t,outbound?belle_sip_uri_parse(outbound):NULL);
}else belle_sip_provider_send_request(prov,req);
for(i=0;!is_register_ok && i<2 ;i++)
for(i=0;!is_register_ok && i<2 && io_error_count==0;i++)
belle_sip_stack_sleep(stack,5000);
CU_ASSERT_EQUAL(is_register_ok,success_expected);
if (success_expected) CU_ASSERT_EQUAL(using_transaction,use_transaction);
......@@ -400,6 +407,7 @@ static void test_bad_request(void) {
belle_sip_header_route_t* route;
belle_sip_header_to_t* to = belle_sip_header_to_create2("sip:toto@titi.com",NULL);
belle_sip_listener_callbacks_t cbs;
belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(prov,"TCP");
int bad_request_response_received=0;
memset(&cbs,0,sizeof(cbs));
......@@ -432,6 +440,8 @@ static void test_bad_request(void) {
CU_ASSERT_TRUE(bad_request_response_received==1);
belle_sip_provider_remove_sip_listener(prov,bad_req_listener);
belle_sip_object_unref(bad_req_listener);
belle_sip_listening_point_clean_channels(lp);
}
static void test_register_authenticate(void) {
......@@ -475,6 +485,37 @@ static void test_register_client_authenticated(void) {
if (reg) belle_sip_object_unref(reg);
}
static void test_connection_failure(void){
belle_sip_request_t *req;
io_error_count=0;
req=try_register_user_at_domain(stack, prov, "TCP",1,"tester","sip.linphone.org",no_server_running_here,0);
CU_ASSERT_TRUE(io_error_count>=1);
if (req) belle_sip_object_unref(req);
}
static void test_connection_too_long(void){
belle_sip_request_t *req;
io_error_count=0;
int orig=belle_sip_stack_get_transport_timeout(stack);
belle_sip_stack_set_transport_timeout(stack,2000);
req=try_register_user_at_domain(stack, prov, "TCP",1,"tester","sip.linphone.org",no_response_here,0);
CU_ASSERT_TRUE(io_error_count>=1);
belle_sip_stack_set_transport_timeout(stack,orig);
if (req) belle_sip_object_unref(req);
}
static void test_tls_to_tcp(void){
io_error_count=0;
belle_sip_request_t *req;
int orig=belle_sip_stack_get_transport_timeout(stack);
belle_sip_stack_set_transport_timeout(stack,2000);
req=try_register_user_at_domain(stack, prov, "TLS",1,"tester",test_domain,test_domain_tls_to_tcp,0);
if (req){
CU_ASSERT_TRUE(io_error_count>=1);
belle_sip_object_unref(req);
}
belle_sip_stack_set_transport_timeout(stack,orig);
}
test_t register_tests[] = {
{ "Stateful UDP", stateful_register_udp },
......@@ -490,7 +531,10 @@ test_t register_tests[] = {
{ "Bad TCP request", test_bad_request },
{ "Authenticate", test_register_authenticate },
{ "TLS client cert authentication", test_register_client_authenticated },
{ "Channel inactive", test_register_channel_inactive }
{ "Channel inactive", test_register_channel_inactive },
{ "TCP connection failure", test_connection_failure },
{ "TCP connection too long", test_connection_too_long },
{ "TLS connection to TCP server", test_tls_to_tcp }
};
test_suite_t register_test_suite = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment