diff --git a/.cproject b/.cproject index 539e03aa9..beb21f7cb 100644 --- a/.cproject +++ b/.cproject @@ -81,6 +81,8 @@ + + @@ -133,6 +135,29 @@ + + + + + + + + + + + + + + + + + + + + + + + @@ -200,5 +225,4 @@ - diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 110a1b04f..f981afaa2 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -45,8 +45,14 @@ void sal_process_authentication(SalOp *op, belle_sip_response_t *response) { } } -static void process_dialog_terminated(void *user_ctx, const belle_sip_dialog_terminated_event_t *event){ - ms_error("process_dialog_terminated not implemented yet"); +static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){ + belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_get_dialog(event); + SalOp* op = belle_sip_dialog_get_application_data(dialog); + if (op->callbacks.process_dialog_terminated) { + op->callbacks.process_dialog_terminated(op,event); + } else { + ms_error("sal process_dialog_terminated not implemented yet"); + } } static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ ms_error("process_io_error not implemented yet"); @@ -119,7 +125,10 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_request_t* old_request=NULL;; belle_sip_response_t* old_response=NULL;; int response_code = belle_sip_response_get_status_code(response); - + if (op->state == SalOpStateTerminated) { + belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); + return; + } if (!op->base.remote_ua) { sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); } @@ -204,8 +213,13 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even } case 401: case 407:{ - sal_process_authentication(op,response); - return; + if (op->state == SalOpStateTerminating) { + belle_sip_message("Op is in state terminating, nothing else to do"); + return; + } else { + sal_process_authentication(op,response); + return; + } } } op->callbacks.process_response_event(op,event); @@ -245,6 +259,7 @@ static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event } Sal * sal_init(){ char stack_string[64]; + belle_sip_listener_t* listener; Sal * sal=ms_new0(Sal,1); snprintf(stack_string,sizeof(stack_string)-1,"(belle-sip/%s)",belle_sip_version_to_string()); sal->user_agent=belle_sip_header_user_agent_new(); @@ -260,7 +275,8 @@ Sal * sal_init(){ sal->listener_callbacks.process_timeout=process_timeout; sal->listener_callbacks.process_transaction_terminated=process_transaction_terminated; sal->listener_callbacks.process_auth_requested=process_auth_requested; - belle_sip_provider_add_sip_listener(sal->prov,belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); + belle_sip_provider_add_sip_listener(sal->prov,listener=belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); + belle_sip_object_unref(listener); return sal; } void sal_set_user_pointer(Sal *sal, void *user_data){ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 309e779ba..695799d09 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -38,6 +38,7 @@ struct Sal{ typedef enum SalOpSate { SalOpStateEarly=0 ,SalOpStateActive + ,SalOpStateTerminating /*this state is used to wait until a procedding state, so we can send the cancel*/ ,SalOpStateTerminated }SalOpSate_t; @@ -52,6 +53,7 @@ struct SalOp{ belle_sip_request_t* request; belle_sip_response_t* response; belle_sip_server_transaction_t* pending_server_trans; + belle_sip_client_transaction_t* pending_inv_client_trans; SalAuthInfo auth_info; unsigned long int registration_refresh_timer; bool_t sdp_offering; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index d5a65b44c..94c9b4d94 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -83,6 +83,9 @@ static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ ms_error("process_io_error not implemented yet"); } +static void process_dialog_terminated(void *op, const belle_sip_dialog_terminated_event_t *event) { + if (((SalOp*)op)->dialog) ((SalOp*)op)->dialog=NULL; +} static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { belle_sdp_session_description_t* sdp; if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(response)))) { @@ -91,6 +94,13 @@ static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { if (op->base.local_media) sdp_process(op); } } +static void cancelling_invite(SalOp* op ){ + belle_sip_request_t* cancel; + ms_message("Cancelling INVITE requets from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op)); + cancel = belle_sip_client_transaction_create_cancel(op->pending_inv_client_trans); + sal_op_send_request(op,cancel); + op->state=SalOpStateTerminated; +} static void call_response_event(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; belle_sip_request_t* ack; @@ -154,9 +164,19 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } return; } + /*check if op is terminating*/ + dialog_state=belle_sip_dialog_get_state(op->dialog); + + if (op->state == SalOpStateTerminating + && (dialog_state==BELLE_SIP_DIALOG_NULL + || dialog_state==BELLE_SIP_DIALOG_EARLY)) { + cancelling_invite(op); + + return; + } /*else dialog*/ - dialog_state=belle_sip_dialog_get_state(op->dialog); + switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: { @@ -211,6 +231,21 @@ static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { ms_error("process_transaction_terminated not implemented yet"); } +static void call_terminated(SalOp* op,belle_sip_server_transaction_t* server_transaction, belle_sip_request_t* request,int status_code) { + belle_sip_response_t* resp; + op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); + resp=belle_sip_response_create_from_request(request,status_code); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->state=SalOpStateTerminated; + return; +} +static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request) { + belle_sip_response_t* resp; + resp=belle_sip_response_create_from_request(request,500); + belle_sip_server_transaction_send_response(server_transaction,resp); + return; +} + static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { SalOp* op = (SalOp*)op_base; belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); @@ -223,7 +258,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t belle_sip_dialog_state_t dialog_state; belle_sdp_session_description_t* sdp; belle_sip_header_t* call_info; - belle_sip_response_t* resp; + if (!op->dialog) { op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans)); belle_sip_dialog_set_application_data(op->dialog,op); @@ -258,6 +293,30 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t break; } + case BELLE_SIP_DIALOG_EARLY: { + //hmm probably a cancel + if (strcmp("CANCEL",belle_sip_request_get_method(req))==0) { + if(belle_sip_request_event_get_server_transaction(event)) { + /*first answer 200 ok to cancel*/ + belle_sip_server_transaction_send_response(server_transaction + ,belle_sip_response_create_from_request(req,200)); + /*terminate invite request*/ + call_terminated(op + ,belle_sip_request_event_get_server_transaction(event) + ,belle_sip_request_event_get_request(event),487); + + + } else { + /*call leg does not exist*/ + belle_sip_server_transaction_send_response(server_transaction + ,belle_sip_response_create_from_request(req,481)); + } + } else { + belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY"); + unsupported_method(server_transaction,belle_sip_request_event_get_request(event)); + } + break; + } case BELLE_SIP_DIALOG_CONFIRMED: /*great ACK received*/ if (strcmp("ACK",belle_sip_request_get_method(req))==0) { @@ -277,9 +336,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t }*/ op->base.root->callbacks.call_ack(op); } else if(strcmp("BYE",belle_sip_request_get_method(req))==0) { - op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); - resp=belle_sip_response_create_from_request(belle_sip_request_event_get_request(event),200); - belle_sip_server_transaction_send_response(server_transaction,resp); + call_terminated(op,server_transaction,belle_sip_request_event_get_request(event),200); } else { ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); } @@ -305,9 +362,9 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ int sal_call(SalOp *op, const char *from, const char *to){ belle_sip_request_t* req; belle_sip_header_allow_t* header_allow; - belle_sip_client_transaction_t* client_transaction; +/* belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; - belle_sip_header_route_t* route_header; + belle_sip_header_route_t* route_header;*/ op->dir=SalOpDirOutgoing; sal_op_set_from(op,from); sal_op_set_to(op,to); @@ -325,16 +382,17 @@ int sal_call(SalOp *op, const char *from, const char *to){ set_sdp_from_desc(BELLE_SIP_MESSAGE(req),op->base.local_media); }else op->sdp_offering=FALSE; - if (sal_op_get_route_address(op)) { +/* if (sal_op_get_route_address(op)) { route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(route_header)); - } + }*/ sal_op_call_fill_cbs(op); - client_transaction = belle_sip_provider_create_client_transaction(prov,req); + sal_op_send_request(op,req); + /*op->pending_inv_client_trans = client_transaction = belle_sip_provider_create_client_transaction(prov,req); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); op->dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction)); belle_sip_client_transaction_send_request(client_transaction); - + */ return 0; } void sal_op_call_fill_cbs(SalOp*op) { @@ -343,6 +401,7 @@ void sal_op_call_fill_cbs(SalOp*op) { op->callbacks.process_timeout=call_process_timeout; op->callbacks.process_transaction_terminated=call_process_transaction_terminated; op->callbacks.process_request_event=process_request_event; + op->callbacks.process_dialog_terminated=process_dialog_terminated; } int sal_call_notify_ringing(SalOp *op, bool_t early_media){ belle_sip_response_t* ringing_response; @@ -414,6 +473,9 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti case SalReasonMedia: status=415; break; + case SalReasonDeclined: + status=603; + break; case SalReasonRedirect: if(redirection!=NULL) { if (strstr(redirection,"sip:")!=0) status=302; @@ -483,12 +545,35 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){ } int sal_call_terminate(SalOp *op){ belle_sip_dialog_state_t dialog_state=belle_sip_dialog_get_state(op->dialog); - + op->state=SalOpStateTerminating; switch(dialog_state) { case BELLE_SIP_DIALOG_CONFIRMED: { sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); + op->state=SalOpStateTerminated; + break; + } + case BELLE_SIP_DIALOG_NULL: { + if (op->dir == SalOpDirIncoming) { + sal_call_decline(op, SalReasonDeclined,NULL); + op->state=SalOpStateTerminated; + } else if (op->pending_inv_client_trans + && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_inv_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){ + cancelling_invite(op); + break; + } else { + ms_error("Don't know how to termination NUL dialog [%p]",op->dialog); + } + break; + } + case BELLE_SIP_DIALOG_EARLY: { + if (op->dir == SalOpDirIncoming) { + sal_call_decline(op, SalReasonDeclined,NULL); + op->state=SalOpStateTerminated; + } else { + cancelling_invite(op); + } + break; } - break; default: { ms_fatal("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); return -1; diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 2de7d8388..f61ff5ab7 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -159,12 +159,11 @@ void sal_op_send_request(SalOp* op, belle_sip_request_t* request) { client_transaction = belle_sip_provider_create_client_transaction(prov,request); belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); /*in case DIALOG is in state NULL create a new dialog*/ - if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_NULL) { - belle_sip_dialog_delete(op->dialog); + if (!op->dialog && strcmp("INVITE",belle_sip_request_get_method(request))==0) { op->dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction)); + op->pending_inv_client_trans=client_transaction; /*update pending inv for being able to cancel*/ belle_sip_dialog_set_application_data(op->dialog,op); - } else - if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) + } else if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION) && !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) { /*hmm just in case we already have authentication param in cache*/ belle_sip_provider_add_authorization(op->base.root->prov,request,NULL); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f64edcb83..41e666f47 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3548,6 +3548,9 @@ const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc){ **/ void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val){ lc->video_conf.show_local=val; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config,"video","show_local",linphone_core_video_preview_enabled(lc)); + } } /** @@ -3570,6 +3573,9 @@ void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){ #ifdef VIDEO_ENABLED LinphoneCall *call=linphone_core_get_current_call (lc); lc->video_conf.selfview=val; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config,"video","self_view",linphone_core_self_view_enabled(lc)); + } if (call && call->videostream){ video_stream_enable_self_view(call->videostream,val); } diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 5c1ee3ece..61d55fb2f 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -10,44 +10,39 @@ # Default value: false debug=false +# Automatically respawn flexisip in case of abnormal termination +# (crashes) +# Default value: true +auto-respawn=true + # 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 +aliases=localhost -# The public ip address of the proxy. -# Default value: guess -ip-address=auth.example.org +# List of white space separated SIP uris where the proxy must listen.Wildcard +# (*) can be used to mean 'all local ip addresses'. If 'transport' +# prameter is unspecified, it will listen to both udp and tcp. An +# local address to bind can be indicated in the 'maddr' parameter, +# while the domain part of the uris are used as public domain or +# ip address. Here some examples to understand: +# * listen on all local interfaces for udp and tcp, on standart +# port: +# transports=sip:* +# * listen on all local interfaces for udp,tcp and tls, on standart +# ports: +# transports=sip:* sips:* +# * listen on 192.168.0.29:6060 with tls, but public hostname is +# 'sip.linphone.org' used in SIP messages. Bind address won't appear: +# transports=sips:sip.linphone.org:6060;maddr=192.168.0.29 +# Default value: sip:* +transports=sip:* sips:* -# The local interface's ip address where to listen. The wildcard -# (*) means all interfaces. -# Default value: * -bind-address=auth.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 +# An absolute path of a directory where TLS server certificate and +# private key can be found, concatenated inside an 'agent.pem' file. # Default value: /etc/flexisip/tls -#certificates-dir=/Users/jehanmonnier/workspaces/workspace-macosx/flexisip -certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip - +#tls-certificates-dir=/etc/flexisip/tls +tls-certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip ## ## STUN server parameters. @@ -57,10 +52,43 @@ certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip # Default value: true enabled=true +# Local ip address where to bind the socket. +# Default value: 0.0.0.0 +bind-address=0.0.0.0 + # STUN server port number. # Default value: 3478 port=3478 +## +## DOS protection parameters. +## +[dos-protection] +# Enable or disable DOS protection using IPTables firewall. +# Default value: false +enabled=false + +# List of whitelist IPs which won't be affected by DOS protection. +# Default value: 127.0.0.1 +authorized-ip=127.0.0.1 + +# Local ports to protect. +# Default value: 5060 +port=5060 + +# Time (in seconds) while an IP have to not send any packet in order +# to leave the blacklist. +# Default value: 60 +ban-duration=60 + +# Number of packets authorized in 1sec before considering them as +# DOS attack. +# Default value: 20 +packets-limit=20 + +# Maximal amount of simultaneous connections to accept. +# Default value: 1000 +maximum-connections=1000 ## ## The NatHelper module executes small tasks to make SIP work smoothly @@ -72,16 +100,19 @@ port=3478 [module::NatHelper] # Indicate whether the module is activated. # Default value: true -enabled=false +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 request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= +# Internal URI parameter added to response contact by first proxy +# and cleaned by last one. +# Default value: verified +contact-verified-param=verified ## ## The authentication module challenges SIP requests according to @@ -92,18 +123,17 @@ to-domains=* # 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=* +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= # List of whitespace separated domain names to challenge. Others # are denied. # Default value: -auth-domains=auth.example.org auth1.example.org auth2.example.org +auth-domains= auth.example.org # List of whitespace separated IP which will not be challenged. # Default value: @@ -114,14 +144,16 @@ trusted-hosts= 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; +# DSN=myodbc3; where 'myodbc3' is the datasource name. ex2: DRIVER={MySQL};SERVER=host;DATABASE=db;USER=user;PASSWORD=pass;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.' +# Odbc SQL request to execute to obtain the password +# . Named parameters are :id (the user found in the from header), +# :domain (the authorization realm) and :authid (the authorization +# username). The use of the :id parameter is mandatory. # 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 @@ -160,12 +192,52 @@ cache-expire=1800 # 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)). +# True if retrieved passwords from the database are hashed. HA1=MD5(A1) +# = MD5(username:realm:pass). # Default value: false hashed-passwords=false +# When receiving a proxy authenticate challenge, generate a new +# challenge for this proxy. +# Default value: false +new-auth-on-407=false +## +## ... +## +[module::GatewayAdapter] +# Indicate whether the module is activated. +# Default value: false +enabled=false + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# A gateway uri where to send all requests, as a SIP url (eg 'sip:gateway.example.net') +# Default value: +gateway= + +# Modify the from and to domains of incoming register +# Default value: +gateway-domain= + +# The gateway will be added to the incoming register contacts. +# Default value: true +fork-to-gateway=true + +# Send a REGISTER to the gateway using this server as a contact +# in order to be notified on incoming calls by the gateway. +# Default value: true +register-on-gateway=true + +# Parameter name hosting the incoming domain that will be sent in +# the register to the gateway. +# Default value: routing-domain +routing-param=routing-domain ## ## The Registrar module accepts REGISTERs for domains it manages, @@ -177,19 +249,135 @@ hashed-passwords=false # 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=* +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= # 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 +reg-domains=localhost auth.example.org +# Maximum number of registered contacts of an address of record. +# Default value: 15 +max-contacts-by-aor=15 + +# List of contact uri parameters that can be used to identify a +# user's device. +# Default value: line +unique-id-parameters=line + +# Maximum expire time for a REGISTER, in seconds. +# Default value: 86400 +max-expires=86400 + +# Minimum expire time for a REGISTER, in seconds. +# Default value: 60 +min-expires=60 + +# File containing the static records to add to database at startup. +# Format: one 'sip_uri contact_header' by line. Example: +# , +# Default value: +static-records-file= + +# Timeout in seconds after which the static records file is re-read +# and the contacts updated. +# Default value: 600 +static-records-timeout=600 + +# Implementation used for storing address of records contact uris. +# [redis-async, redis-sync, internal] +# Default value: internal +db-implementation=internal + +# Store and retrieve contacts without using the domain. +# Default value: false +use-global-domain=false + +# Fork messages to all registered devices +# Default value: true +fork=true + +# Force forking and thus the creation of an outgoing transaction +# even when only one contact found +# Default value: true +stateful=true + +# Fork invites to late registers +# Default value: false +fork-late=false + +# Only forward one response of forked invite to the caller +# Default value: true +fork-one-response=true + +# All the forked have to decline in order to decline the caller +# invite +# Default value: false +fork-no-global-decline=false + +# Maximum duration for delivering a message (text) +# Default value: 3600 +message-delivery-timeout=3600 + +# Generate a contact from the TO header and route it to the above +# destination. [sip:host:port] +# Default value: +generated-contact-route= + +# Require presence of authorization header for specified realm. +# [Realm] +# Default value: +generated-contact-expected-realm= + +## +## This module performs push notifications +## +[module::PushNotification] +# Indicate whether the module is activated. +# Default value: false +enabled=false + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# Number of second to wait before sending a push notification to +# device(if <=0 then disabled) +# Default value: 5 +timeout=5 + +# Maximum number of notifications queued for each client +# Default value: 10 +max-queue-size=10 + +# Enable push notification for apple devices +# Default value: true +apple=true + +# Path to directory where to find Apple Push Notification service +# certificates. They should bear the appid of the application, suffixed +# by the release mode and .pem extension. For example: org.linphone.dev.pem +# org.linphone.prod.pem com.somephone.dev.pem etc... The files should +# be .pem format, and made of certificate followed by private key. +# Default value: /etc/flexisip/apn +apple-certificate-dir=/etc/flexisip/apn + +# Enable push notification for android devices +# Default value: true +google=true + +# List of couple projectId:ApiKey for each android project which +# support push notifications +# Default value: +google-projects-api-keys= ## ## The purpose of the ContactRouteInserter module is to masquerade @@ -204,19 +392,17 @@ reg-domains=auth.example.org auth1.example.org auth2.example.org sip.example.org # 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=* +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= # 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. @@ -226,20 +412,18 @@ masquerade-contacts-for-invites=false # 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=* +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= # 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 @@ -250,16 +434,41 @@ routes= [module::MediaRelay] # Indicate whether the module is activated. # Default value: true -enabled=true +enabled=false -# List of domain names in sip from allowed to enter the module. -# Default value: * -from-domains=* +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= -# List of domain names in sip to allowed to enter the module. -# Default value: * -to-domains=* +# SDP attribute set by the first proxy to forbid subsequent proxies +# to provide relay. +# Default value: nortpproxy +nortpproxy=nortpproxy +# Set the RTP direction during early media state (duplex, forward) +# Default value: duplex +early-media-rtp-dir=duplex + +# The minimal value of SDP port range +# Default value: 1024 +sdp-port-range-min=1024 + +# The maximal value of SDP port range +# Default value: 65535 +sdp-port-range-max=65535 + +# Enable I-frame only filtering for video H264 for clients annoucing +# a total bandwith below this value expressed in kbit/s. Use 0 to +# disable the feature +# Default value: 0 +h264-filtering-bandwidth=0 + +# When above option is activated, keep one I frame over this number. +# Default value: 1 +h264-iframe-decim=1 ## ## The purpose of the Transcoder module is to transparently transcode @@ -282,13 +491,12 @@ to-domains=* # 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=* +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= # Nominal size of RTP jitter buffer, in milliseconds. A value of # 0 means no jitter buffer (packet processing). @@ -302,9 +510,13 @@ 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 +audio-codecs=speex/8000 amr/8000 iLBC/8000 gsm/8000 pcmu/8000 pcma/8000 +# If true, retransmissions of INVITEs will be blocked. The purpose +# of this option is to limit bandwidth usage and server load on +# reliable networks. +# Default value: false +block-retransmissions=false ## ## This module executes the basic routing task of SIP requests and @@ -315,21 +527,18 @@ audio-codecs=amr/8000 pcmu/8000 pcma/8000 telephone-event/8000 # 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 request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= # A sip uri where to send all requests # Default value: -#route= +route= # Rewrite request-uri's host and port according to above route # Default value: false rewrite-req-uri=false -[dos-protection] -enabled=false diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 4745dc4f0..417319d24 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -292,28 +292,7 @@ static void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCal CU_FAIL("unexpected event");break; } } -static void simple_call_declined() { - LinphoneCoreVTable v_table; - LinphoneCore* lc; - int retry=0; - memset (&v_table,0,sizeof(LinphoneCoreVTable)); - v_table.registration_state_changed=registration_state_changed; - v_table.call_state_changed=call_state_changed; - lc=configure_lc(&v_table); - stats* counters = (stats*)linphone_core_get_user_data(lc); - linphone_core_invite(lc,"marie"); - - while (counters->number_of_LinphoneCallIncomingReceived<1 && retry++ <20) { - linphone_core_iterate(lc); - ms_usleep(100000); - } - CU_ASSERT_EQUAL(counters->number_of_LinphoneCallIncomingReceived,1); - CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc)); - /*linphone_core_terminate_call(lc,linphone_core_get_current_call(lc));*/ - CU_ASSERT_EQUAL(counters->number_of_LinphoneCallReleased,1); - linphone_core_destroy(lc); -} static bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { int retry=0; while (*counterv_table.registration_state_changed=registration_state_changed; + mgr->v_table.call_state_changed=call_state_changed; + + mgr->lc=configure_lc_from(&mgr->v_table,rc_file,1); + enable_codec(mgr->lc,"PCMU",8000); + linphone_core_set_user_data(mgr->lc,&mgr->stat); + return mgr; +} +static void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { + linphone_core_destroy(mgr->lc); + free(mgr); +} static void simple_call() { - LinphoneCoreVTable v_table_marie; - LinphoneCore* lc_marie; - LinphoneCoreVTable v_table_pauline; - LinphoneCore* lc_pauline; - stats stat_marie; - stats stat_pauline; - reset_counters(&stat_marie); - reset_counters(&stat_pauline); + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCore* lc_marie=marie->lc; + LinphoneCore* lc_pauline=pauline->lc; + stats* stat_marie=&marie->stat; + stats* stat_pauline=&pauline->stat; - memset (&v_table_marie,0,sizeof(LinphoneCoreVTable)); - v_table_marie.registration_state_changed=registration_state_changed; - v_table_marie.call_state_changed=call_state_changed; - - lc_marie=configure_lc_from(&v_table_marie,"./tester/marie_rc",1); - enable_codec(lc_marie,"PCMU",8000); - linphone_core_set_user_data(lc_marie,&stat_marie); - - memset (&v_table_pauline,0,sizeof(LinphoneCoreVTable)); - v_table_pauline.registration_state_changed=registration_state_changed; - v_table_pauline.call_state_changed=call_state_changed; - - lc_pauline=configure_lc_from(&v_table_pauline,"./tester/pauline_rc",1); - linphone_core_set_user_data(lc_pauline,&stat_pauline); - linphone_core_invite(lc_marie,"pauline"); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); - CU_ASSERT_EQUAL(stat_marie.number_of_LinphoneCallOutgoingProgress,1); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallOutgoingRinging,1)); + CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); LinphoneProxyConfig* proxy; linphone_core_get_default_proxy(lc_marie,&proxy); CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); - - CU_ASSERT_STRING_EQUAL(linphone_proxy_config_get_identity(proxy),linphone_core_get_current_call_remote_address(lc_pauline)) + LinphoneAddress* identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); + linphone_address_destroy(identity); linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallConnected,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallStreamsRunning,1)); - CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallStreamsRunning,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,1)); + CU_ASSERT_TRUE_FATAL(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); /*just to sleep*/ - wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallStreamsRunning,3); + wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); linphone_core_terminate_all_calls(lc_pauline); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline.number_of_LinphoneCallEnd,1)); - CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); - linphone_core_destroy(lc_marie); - linphone_core_destroy(lc_pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void call_canceled() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + + linphone_core_terminate_call(pauline->lc,out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonCanceled); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void call_ringing_canceled() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + + linphone_core_terminate_call(pauline->lc,out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + //CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); + //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_early_declined() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE_FATAL(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + LinphoneCall* in_call=linphone_core_get_current_call(marie->lc); + linphone_call_ref(in_call); + + linphone_core_terminate_call(marie->lc,in_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + linphone_call_unref(in_call); + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); } int init_test_suite () { @@ -419,7 +459,13 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "multi account", multiple_proxy)) { return CU_get_error(); } - if (NULL == CU_add_test(pSuite, "simple_call_declined", simple_call_declined)) { + if (NULL == CU_add_test(pSuite, "call_early_declined", call_early_declined)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_canceled", call_canceled)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_ringing_canceled", call_ringing_canceled)) { return CU_get_error(); } if (NULL == CU_add_test(pSuite, "simple_call", simple_call)) { @@ -441,6 +487,9 @@ int main (int argc, char *argv[]) { }else if (strcmp(argv[i],"--domain")==0){ i++; test_domain=argv[i]; + } else if (strcmp(argv[i],"--auth-domain")==0){ + i++; + auth_domain=argv[i]; }else if (strcmp(argv[i],"--test")==0){ i++; test_name=argv[i];