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];