diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 6de7ea051..238ca225c 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -272,7 +272,7 @@ static void register_response_event(void *user_ctx, const belle_sip_response_eve if (op->registration_refresh_timer>0) { belle_sip_main_loop_cancel_source(belle_sip_stack_get_main_loop(op->base.root->stack),op->registration_refresh_timer); } - op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,belle_sip_header_expires_get_expires(expires_header)*1000); + op->registration_refresh_timer = belle_sip_main_loop_add_timeout(belle_sip_stack_get_main_loop(op->base.root->stack),(belle_sip_source_func_t)register_refresh,op,expires*1000); } sal_remove_pending_auth(op->base.root,op);/*just in case*/ break; diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 7a12c9ea7..9ce4e1162 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -794,7 +794,8 @@ static void ping_reply(SalOp *op){ ms_warning("ping reply without call attached..."); } } -static bool_t auth_requested(SalOp*op, SalAuthInfo* sai) { + +static bool_t fill_auth_info(SalOp*op, SalAuthInfo* sai) { LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username); if (ai) { @@ -807,6 +808,20 @@ static bool_t auth_requested(SalOp*op, SalAuthInfo* sai) { return FALSE; } } +static bool_t auth_requested(SalOp*op, SalAuthInfo* sai) { + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + if (fill_auth_info(op,sai)) { + return TRUE; + } else { + if (lc->vtable.auth_info_requested) { + lc->vtable.auth_info_requested(lc,sai->realm,sai->username); + if (fill_auth_info(op,sai)) { + return TRUE; + } + } + return FALSE; + } +} SalCallbacks linphone_sal_callbacks={ call_received, call_ringing, diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 03db6aeb2..668874e2b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -4144,7 +4144,7 @@ void sip_config_uninit(LinphoneCore *lc) MSList *elem; int i; sip_config_t *config=&lc->sip_conf; - bool_t all_unregistered=FALSE; + bool_t still_registered=TRUE; lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname); lp_config_set_string(lc->config,"sip","contact",config->contact); @@ -4162,11 +4162,12 @@ void sip_config_uninit(LinphoneCore *lc) linphone_proxy_config_edit(cfg); /* to unregister */ } - for (i=0;i<20&&!all_unregistered;i++){ + for (i=0;i<20&&still_registered;i++){ + still_registered=FALSE; sal_iterate(lc->sal); for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); - all_unregistered|=!linphone_proxy_config_is_registered(cfg); + still_registered|=linphone_proxy_config_is_registered(cfg); } #ifndef WIN32 usleep(100000); diff --git a/tester/flexisip.conf b/tester/flexisip.conf new file mode 100644 index 000000000..ffd6acf5f --- /dev/null +++ b/tester/flexisip.conf @@ -0,0 +1,333 @@ +## +## This is the default Flexisip configuration file +## + +## +## Some global settings of the flexisip proxy. +## +[global] +# Outputs very detailed logs +# Default value: false +debug=false + +# List of white space separated host names pointing to this machine. +# This is to prevent loops while routing SIP messages. +# Default value: localhost +aliases=auth.example.org auth1.example.org auth2.example.org sip.example.org + +# The public ip address of the proxy. +# Default value: guess +ip-address=guess + +# The local interface's ip address where to listen. The wildcard +# (*) means all interfaces. +# Default value: * +bind-address=sip.example.org + +# UDP/TCP port number to listen for sip messages. +# Default value: 5060 +port=5060 + + +## +## TLS specific parameters. +## +[tls] +# Enable SIP/TLS (sips) +# Default value: true +enabled=true + +# The port used for SIP/TLS +# Default value: 5061 +port=5061 + +# An absolute path of a directory where TLS certificate can be found. +# The private key for TLS server must be in a agent.pem file within +# this directory +# Default value: /etc/flexisip/tls +certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/flexisip + + +## +## STUN server parameters. +## +[stun-server] +# Enable or disable stun server. +# Default value: true +enabled=true + +# STUN server port number. +# Default value: 3478 +port=3478 + + +## +## The NatHelper module executes small tasks to make SIP work smoothly +## despite firewalls.It corrects the Contact headers that contain +## obviously inconsistent addresses, and adds a Record-Route to ensure +## subsequent requests are routed also by the proxy, through the +## UDP or TCP channel each client opened to the proxy. +## +[module::NatHelper] +# Indicate whether the module is activated. +# Default value: true +enabled=false + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=* + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + + +## +## The authentication module challenges SIP requests according to +## a user/password database. +## +[module::Authentication] +# Indicate whether the module is activated. +# Default value: false +enabled=true + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=auth.example.org auth1.example.org auth2.example.org + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + +# List of whitespace separated domain names to challenge. Others +# are denied. +# Default value: +auth-domains=auth.example.org auth1.example.org auth2.example.org + +# List of whitespace separated IP which will not be challenged. +# Default value: +trusted-hosts= + +# Database backend implementation [odbc, file]. +# Default value: odbc +db-implementation=file + +# Odbc connection string to use for connecting to database. ex1: +# DSN=myodbc3; where 'myodbc3' is the datasource name. ex2: DRIVER={MySQL};SERVER=localhost;DATABASE=dbname;USER=username;PASSWORD=passname;OPTION=3; +# for a DSN-less connection. ex3: /etc/flexisip/passwd; for a file +# containing one 'user@domain password' by line. +# Default value: +datasource=./userdb.conf + +# Odbc SQL request to execute to obtain the password. Named parameters +# are :id, :domain and :authid.' +# Default value: select password from accounts where id = :id and domain = :domain and authid=:authid +request=select password from accounts where id = :id and domain = :domain and authid=:authid + +# Maximum length of the login column in database. +# Default value: 100 +max-id-length=100 + +# Maximum length of the password column in database +# Default value: 100 +max-password-length=100 + +# Use pooling in odbc +# Default value: true +odbc-pooling=true + +# Display timing statistics after this count of seconds +# Default value: 0 +odbc-display-timings-interval=0 + +# Display timing statistics once the number of samples reach this +# number. +# Default value: 0 +odbc-display-timings-after-count=0 + +# Retrieve passwords asynchronously. +# Default value: false +odbc-asynchronous=false + +# Duration of the validity of the credentials added to the cache +# in seconds. +# Default value: 1800 +cache-expire=1800 + +# Retrieve password immediately so that it is cached when an authenticated +# request arrives. +# Default value: true +immediate-retrieve-password=true + +# True if the passwords retrieved from the database are already +# SIP hashed (HA1=MD5(A1)=MD5(username:realm:password)). +# Default value: false +hashed-passwords=false + + + +## +## The Registrar module accepts REGISTERs for domains it manages, +## and store the address of record in order to route other requests +## destinated to the client who registered. +## +[module::Registrar] +# Indicate whether the module is activated. +# Default value: true +enabled=true + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=auth.example.org auth1.example.org auth2.example.org sip.example.org + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + +# List of whitelist separated domain names to be managed by the +# registrar. +# Default value: localhost +reg-domains=auth.example.org auth1.example.org auth2.example.org sip.example.org + + +## +## The purpose of the ContactRouteInserter module is to masquerade +## the contact header of incoming registers that are not handled +## locally (think about flexisip used as a SBC gateway) in such a +## way that it is then possible to route back outgoing invites to +## the original address. It is a kind of similar mechanism as Record-Route, +## but for REGISTER. +## +[module::ContactRouteInserter] +# Indicate whether the module is activated. +# Default value: true +enabled=false + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=* + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + +# Hack for workarounding Nortel CS2k gateways bug. +# Default value: false +masquerade-contacts-for-invites=false + + +## +## This module performs load balancing between a set of configured +## destination proxies. +## +[module::LoadBalancer] +# Indicate whether the module is activated. +# Default value: false +enabled=false + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=* + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + +# Whitespace separated list of sip routes to balance the requests. +# Example: +# Default value: +routes= + + +## +## The MediaRelay module masquerades SDP message so that all RTP +## and RTCP streams go through the proxy. The RTP and RTCP streams +## are then routed so that each client receives the stream of the +## other. MediaRelay makes sure that RTP is ALWAYS established, even +## with uncooperative firewalls. +## +[module::MediaRelay] +# Indicate whether the module is activated. +# Default value: true +enabled=false + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=* + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + + +## +## The purpose of the Transcoder module is to transparently transcode +## from one audio codec to another to make the communication possible +## between clients that do not share the same set of supported codecs. +## Concretely it adds all missing codecs into the INVITEs it receives, +## and adds codecs matching the original INVITE into the 200Ok. Rtp +## ports and addresses are masqueraded so that the streams can be +## processed by the proxy. The transcoding job is done in the background +## by the mediastreamer2 library, as consequence the set of supported +## codecs is exactly the the same as the codec set supported by mediastreamer2, +## including the possible plugins you may installed to extend mediastreamer2. +## WARNING: this module can conflict with the MediaRelay module as +## both are changin the SDP. Make sure to configure them with different +## to-domains or from-domains filter if you want to enable both of +## them. +## +[module::Transcoder] +# Indicate whether the module is activated. +# Default value: false +enabled=true + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=freephonie.net + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=freephonie.net + +# Nominal size of RTP jitter buffer, in milliseconds. A value of +# 0 means no jitter buffer (packet processing). +# Default value: 0 +jb-nom-size=0 + +# Whitespace separated list of user-agent strings for which audio +# rate control is performed. +# Default value: +rc-user-agents= + +# Whitespace seprated list of audio codecs, in order of preference. +# Default value: speex/8000 amr/8000 iLBC/8000 gsm/8000 pcmu/8000 pcma/8000 +#audio-codecs=speex/8000 amr/8000 iLBC/8000 gsm/8000 pcmu/8000 pcma/8000 telephone-event/8000 +audio-codecs=amr/8000 pcmu/8000 pcma/8000 telephone-event/8000 + + +## +## This module executes the basic routing task of SIP requests and +## pass them to the transport layer. It must always be enabled. +## +[module::Forward] +# Indicate whether the module is activated. +# Default value: true +enabled=true + +# List of domain names in sip from allowed to enter the module. +# Default value: * +from-domains=* + +# List of domain names in sip to allowed to enter the module. +# Default value: * +to-domains=* + +# A sip uri where to send all requests +# Default value: +#route= + +# Rewrite request-uri's host and port according to above route +# Default value: false +rewrite-req-uri=false + + diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index f834aedfe..3365f5f77 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -88,19 +88,12 @@ static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyCo } -static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { - ms_message("Auth info requested for user id [%s] at realm [%s]\n" - ,username - ,realm); - number_of_auth_info_requested++; -} static LinphoneCore* create_lc() { LinphoneCoreVTable v_table; memset (&v_table,0,sizeof(v_table)); v_table.registration_state_changed=registration_state_changed; - v_table.auth_info_requested=auth_info_requested; return linphone_core_new(&v_table,NULL,NULL,NULL); } static void register_with_refresh(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { @@ -161,14 +154,57 @@ static void simple_register(){ CU_ASSERT_EQUAL(number_of_auth_info_requested,0); } static void simple_authenticated_register(){ - number_of_auth_info_requested=0; LinphoneCore* lc = create_lc(); LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + register_with_refresh(lc,FALSE,auth_domain,NULL); + CU_ASSERT_EQUAL(number_of_auth_info_requested,0); +} + +static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username) { + ms_message("Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + number_of_auth_info_requested++; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + +} + +static void authenticated_register_with_no_initial_credentials(){ + number_of_auth_info_requested=0; + LinphoneCoreVTable v_table; + LinphoneCore* lc; + memset (&v_table,0,sizeof(v_table)); + v_table.registration_state_changed=registration_state_changed; + v_table.auth_info_requested=auth_info_requested; + lc = linphone_core_new(&v_table,NULL,NULL,NULL); + register_with_refresh(lc,FALSE,auth_domain,NULL); CU_ASSERT_EQUAL(number_of_auth_info_requested,1); } + + +static void multiple_proxy(){ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + int retry=0; + memset (&v_table,0,sizeof(v_table)); + reset_counters(); + v_table.registration_state_changed=registration_state_changed; + lc = linphone_core_new(&v_table,NULL,"./multi_account_lrc",NULL); + + CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),3); + + while (number_of_LinphoneRegistrationOk<3 && retry++ <20) { + linphone_core_iterate(lc); + ms_usleep(100000); + } + CU_ASSERT_EQUAL(number_of_LinphoneRegistrationOk,3); + linphone_core_destroy(lc); +} + int init_test_suite () { CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); @@ -185,6 +221,12 @@ CU_pSuite pSuite = CU_add_suite("liblinphone init test suite", init, uninit); if (NULL == CU_add_test(pSuite, "simple register with digest auth tester", simple_authenticated_register)) { return CU_get_error(); } + if (NULL == CU_add_test(pSuite, "register with digest auth tester without initial credentials", authenticated_register_with_no_initial_credentials)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { + return CU_get_error(); + } return 0; } int main (int argc, char *argv[]) { diff --git a/tester/multi_account_lrc b/tester/multi_account_lrc new file mode 100644 index 000000000..5f1bf21a0 --- /dev/null +++ b/tester/multi_account_lrc @@ -0,0 +1,48 @@ +[sip] +sip_port=5072 +sip_tcp_port=5072 +sip_tls_port=5073 + +[auth_info_0] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm="auth.example.org" + +[auth_info_1] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm="auth1.example.org" + +[auth_info_2] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm="auth2.example.org" + +[proxy_0] +reg_proxy=auth.example.org +reg_identity=sip:liblinphone_tester@auth.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[proxy_1] +reg_proxy=auth.example.org +reg_identity=sip:liblinphone_tester@auth1.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[proxy_2] +reg_proxy=auth.example.org +reg_identity=sip:liblinphone_tester@auth2.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +