From e4149d19a8c2f85ebe5933cda34c3bf8dbbd9320 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 26 Jun 2017 22:46:15 +0200 Subject: [PATCH] Add LinphoneCall callback to be notified about ACKs, in order to be able to add custom headers in sent ACKs and read custom headers in received ACKs. --- coreapi/bellesip_sal/sal_impl.c | 10 ++++ coreapi/bellesip_sal/sal_op_call.c | 5 +- coreapi/callbacks.c | 17 ++++++- coreapi/linphonecall.c | 13 +++++ coreapi/misc.c | 27 +++++++++- coreapi/private.h | 2 + include/CMakeLists.txt | 1 + include/linphone/Makefile.am | 1 + include/linphone/call.h | 14 ++++++ include/linphone/callbacks.h | 8 +++ include/linphone/core.h | 1 + include/linphone/headers.h | 81 ++++++++++++++++++++++++++++++ include/linphone/types.h | 5 ++ include/sal/sal.h | 8 ++- tester/call_single_tester.c | 38 +++++++++++++- 15 files changed, 223 insertions(+), 8 deletions(-) create mode 100644 include/linphone/headers.h diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 2809d9309..3f5da96cf 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -966,6 +966,16 @@ int sal_auth_compute_ha1(const char* userid,const char* realm,const char* passwo return belle_sip_auth_helper_compute_ha1(userid, realm, password, ha1); } +SalCustomHeader *sal_custom_header_ref(SalCustomHeader *ch){ + if (ch == NULL) return NULL; + belle_sip_object_ref(ch); + return ch; +} + +void sal_custom_header_unref(SalCustomHeader *ch){ + if (ch == NULL) return; + belle_sip_object_unref(ch); +} SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){ belle_sip_message_t *msg=(belle_sip_message_t*)ch; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index c89f38289..cb0abeb9a 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -315,8 +315,9 @@ static void call_process_response(void *op_base, const belle_sip_response_event_ op->sdp_answer=NULL; } belle_sip_message_add_header(BELLE_SIP_MESSAGE(ack),BELLE_SIP_HEADER(op->base.root->user_agent)); - belle_sip_dialog_send_ack(op->dialog,ack); op->base.root->callbacks.call_accepted(op); /*INVITE*/ + op->base.root->callbacks.call_ack_being_sent(op, (SalCustomHeader*)ack); + belle_sip_dialog_send_ack(op->dialog,ack); op->state=SalOpStateActive; }else if (code >= 300){ call_set_error(op,response, FALSE); @@ -644,7 +645,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } } } - op->base.root->callbacks.call_ack(op); + op->base.root->callbacks.call_ack_received(op, (SalCustomHeader*)req); }else{ ms_message("Ignored received ack since a new client transaction has been started since."); } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e717f050d..b32aaf878 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -817,7 +817,7 @@ static void call_updating(SalOp *op, bool_t is_update){ } -static void call_ack(SalOp *op){ +static void call_ack_received(SalOp *op, SalCustomHeader *ack){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); @@ -825,6 +825,7 @@ static void call_ack(SalOp *op){ ms_warning("call_ack(): no call for which an ack is expected"); return; } + linphone_call_notify_ack_processing(call, ack, TRUE); if (call->expect_media_in_ack){ switch(call->state){ case LinphoneCallStreamsRunning: @@ -838,6 +839,17 @@ static void call_ack(SalOp *op){ } } + +static void call_ack_being_sent(SalOp *op, SalCustomHeader *ack){ + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + + if (call == NULL){ + ms_warning("call_ack(): no call for which an ack is supposed to be sent"); + return; + } + linphone_call_notify_ack_processing(call, ack, FALSE); +} + static void call_terminated(SalOp *op, const char *from){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); @@ -1508,7 +1520,8 @@ SalCallbacks linphone_sal_callbacks={ call_rejected, call_ringing, call_accepted, - call_ack, + call_ack_received, + call_ack_being_sent, call_updating, call_terminated, call_failure, diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 3b91b0b13..68185ea1b 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -131,6 +131,14 @@ void linphone_call_cbs_set_transfer_state_changed(LinphoneCallCbs *cbs, Linphone cbs->transfer_state_changed_cb = cb; } +LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_processing(LinphoneCallCbs *cbs){ + return cbs->ack_processing; +} + +void linphone_call_cbs_set_ack_processing(LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb){ + cbs->ack_processing = cb; +} + bool_t linphone_call_state_is_early(LinphoneCallState state){ switch (state){ @@ -6165,3 +6173,8 @@ void linphone_call_notify_info_message_received(LinphoneCall *call, const Linpho NOTIFY_IF_EXIST(info_message_received_cb, call, msg) linphone_core_notify_info_received(linphone_call_get_core(call), call, msg); } + +void linphone_call_notify_ack_processing(LinphoneCall *call, void *msg, bool_t is_received) { + NOTIFY_IF_EXIST(ack_processing, call, msg, is_received) +} + diff --git a/coreapi/misc.c b/coreapi/misc.c index 4ad769c9f..8192f002d 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1861,4 +1861,29 @@ void linphone_range_set_min(LinphoneRange *range, int min) { void linphone_range_set_max(LinphoneRange *range, int max) { range->max = max; -} \ No newline at end of file +} + + + +LinphoneHeaders * linphone_headers_ref(LinphoneHeaders *obj){ + sal_custom_header_ref((SalCustomHeader*)obj); + return obj; +} + + +void linphone_headers_unref(LinphoneHeaders *obj){ + sal_custom_header_unref((SalCustomHeader*)obj); +} + + +const char* linphone_headers_get_value(LinphoneHeaders *obj, const char *header_name){ + return sal_custom_header_find((SalCustomHeader*)obj, header_name); +} + +void linphone_headers_add(LinphoneHeaders *obj, const char *name, const char *value){ + sal_custom_header_append((SalCustomHeader*)obj, name, value); +} + +void linphone_headers_remove(LinphoneHeaders *obj, const char *name){ + sal_custom_header_remove((SalCustomHeader*)obj, name); +} diff --git a/coreapi/private.h b/coreapi/private.h index d3c2b933f..cd8d49a4b 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -307,6 +307,7 @@ struct _LinphoneCallCbs { LinphoneCallCbsStateChangedCb state_changed_cb; LinphoneCallCbsStatsUpdatedCb stats_updated_cb; LinphoneCallCbsTransferStateChangedCb transfer_state_changed_cb; + LinphoneCallCbsAckProcessingCb ack_processing; }; LinphoneCallCbs * _linphone_call_cbs_new(void); @@ -417,6 +418,7 @@ void linphone_call_notify_encryption_changed(LinphoneCall *call, bool_t on, cons void linphone_call_notify_transfer_state_changed(LinphoneCall *call, LinphoneCallState cstate); void linphone_call_notify_stats_updated(LinphoneCall *call, const LinphoneCallStats *stats); void linphone_call_notify_info_message_received(LinphoneCall *call, const LinphoneInfoMessage *msg); +void linphone_call_notify_ack_processing(LinphoneCall *call, void *msg, bool_t is_received); LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 54094d903..fac14e8d6 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -63,6 +63,7 @@ set(HEADER_FILES video_definition.h wrapper_utils.h xmlrpc.h + headers.h # Deprecated header files linphonecore.h diff --git a/include/linphone/Makefile.am b/include/linphone/Makefile.am index 316f9b5e5..dc9488e0b 100644 --- a/include/linphone/Makefile.am +++ b/include/linphone/Makefile.am @@ -43,6 +43,7 @@ linphone_include_HEADERS=\ video_definition.h \ wrapper_utils.h \ xmlrpc.h \ + headers.h \ linphonecore.h \ linphonecore_utils.h \ linphonefriend.h \ diff --git a/include/linphone/call.h b/include/linphone/call.h index c7749e536..7854dd400 100644 --- a/include/linphone/call.h +++ b/include/linphone/call.h @@ -665,6 +665,20 @@ LINPHONE_PUBLIC LinphoneCallCbsTransferStateChangedCb linphone_call_cbs_get_tran */ LINPHONE_PUBLIC void linphone_call_cbs_set_transfer_state_changed(LinphoneCallCbs *cbs, LinphoneCallCbsTransferStateChangedCb cb); +/** + * Get the ACK processing callback. + * @param[in] cbs LinphoneCallCbs object. + * @return The current ack processing callback. + */ +LINPHONE_PUBLIC LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_processing(LinphoneCallCbs *cbs); + +/** + * Set ACK processing callback. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] cb The ack processing callback to be used. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_ack_processing(LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb); + /** * @} */ diff --git a/include/linphone/callbacks.h b/include/linphone/callbacks.h index 067d6ca11..e25180714 100644 --- a/include/linphone/callbacks.h +++ b/include/linphone/callbacks.h @@ -126,6 +126,14 @@ typedef void (*LinphoneCallCbsStatsUpdatedCb)(LinphoneCall *call, const Linphone */ typedef void (*LinphoneCallCbsTransferStateChangedCb)(LinphoneCall *call, LinphoneCallState cstate); +/** + * Callback for notifying the processing SIP ACK messages. + * @param call LinphoneCall for which an ACK is being received or sent + * @param ack the ACK message + * @param is_received if TRUE this ACK is an incoming one, otherwise it is an ACK about to be sent. + */ +typedef void (*LinphoneCallCbsAckProcessingCb)(LinphoneCall *call, LinphoneHeaders *ack, bool_t is_received); + /** * @} **/ diff --git a/include/linphone/core.h b/include/linphone/core.h index 5ff17db4d..3596e1b8e 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -64,6 +64,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/vcard.h" #include "linphone/video_definition.h" #include "linphone/xmlrpc.h" +#include "linphone/headers.h" #ifdef __cplusplus diff --git a/include/linphone/headers.h b/include/linphone/headers.h new file mode 100644 index 000000000..8e9a91f6e --- /dev/null +++ b/include/linphone/headers.h @@ -0,0 +1,81 @@ +/* +content.h +Copyright (C) 2010-2017 Belledonne Communications SARL + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef LINPHONE_HEADERS_H_ +#define LINPHONE_HEADERS_H_ + + +#include "linphone/types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @addtogroup misc + * @{ + */ + +/** + * Increments ref count. +**/ +LINPHONE_PUBLIC LinphoneHeaders * linphone_headers_ref(LinphoneHeaders *obj); + +/** + * Decrements ref count. +**/ +LINPHONE_PUBLIC void linphone_headers_unref(LinphoneHeaders *obj); + +/** + * Search for a given header name and return its value. + * @param obj the LinphoneHeaders object + * @param name the header's name + * @return the header's value or NULL if not found. +**/ + +LINPHONE_PUBLIC const char* linphone_headers_get_value(LinphoneHeaders *obj, const char *header_name); + +/** + * Add given header name and corresponding value. + * @param obj the LinphoneHeaders object + * @param name the header's name + * @param the header's value +**/ +LINPHONE_PUBLIC void linphone_headers_add(LinphoneHeaders *obj, const char *name, const char *value); + +/** + * Add given header name and corresponding value. + * @param obj the LinphoneHeaders object + * @param name the header's name + * @param the header's value +**/ +LINPHONE_PUBLIC void linphone_headers_remove(LinphoneHeaders *obj, const char *name); + + +/** + * @} +**/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/linphone/types.h b/include/linphone/types.h index 1a99dc630..9d65dce72 100644 --- a/include/linphone/types.h +++ b/include/linphone/types.h @@ -1259,5 +1259,10 @@ typedef struct _LinphoneRange LinphoneRange; */ typedef int LinphoneStatus; +/** + * Object representing a chain of protocol headers. + * It provides read/write access to the headers of the underlying protocol. +**/ +typedef struct _LinphoneHeaders LinphoneHeaders; #endif /* LINPHONE_TYPES_H_ */ diff --git a/include/sal/sal.h b/include/sal/sal.h index 750392dea..9179ec78b 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -492,7 +492,8 @@ typedef struct SalAuthInfo{ typedef void (*SalOnCallReceived)(SalOp *op); typedef void (*SalOnCallRinging)(SalOp *op); typedef void (*SalOnCallAccepted)(SalOp *op); -typedef void (*SalOnCallAck)(SalOp *op); +typedef void (*SalOnCallAckReceived)(SalOp *op, SalCustomHeader *ack); +typedef void (*SalOnCallAckBeingSent)(SalOp *op, SalCustomHeader *ack); typedef void (*SalOnCallUpdating)(SalOp *op, bool_t is_update);/*< Called when a reINVITE/UPDATE is received*/ typedef void (*SalOnCallTerminated)(SalOp *op, const char *from); typedef void (*SalOnCallFailure)(SalOp *op); @@ -532,7 +533,8 @@ typedef struct SalCallbacks{ SalOnCallReceived call_rejected; SalOnCallRinging call_ringing; SalOnCallAccepted call_accepted; - SalOnCallAck call_ack; + SalOnCallAckReceived call_ack_received; + SalOnCallAckBeingSent call_ack_being_sent; SalOnCallUpdating call_updating; SalOnCallTerminated call_terminated; SalOnCallFailure call_failure; @@ -861,6 +863,8 @@ LINPHONE_PUBLIC SalResolverContext * sal_resolve_a(Sal* sal, const char *name, i LINPHONE_PUBLIC SalResolverContext * sal_resolve(Sal *sal, const char *service, const char *transport, const char *name, int port, int family, SalResolverCallback cb, void *data); void sal_resolve_cancel(SalResolverContext *ctx); +SalCustomHeader *sal_custom_header_ref(SalCustomHeader *ch); +void sal_custom_header_unref(SalCustomHeader *ch); SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value); const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name); SalCustomHeader *sal_custom_header_remove(SalCustomHeader *ch, const char *name); diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 314d546bb..383722743 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -1676,6 +1676,29 @@ end: linphone_core_manager_destroy(pauline); } +static void on_ack_processing(LinphoneCall *call, LinphoneHeaders *ack, bool_t is_received){ + if (!is_received){ + linphone_headers_add(ack, "Coucou", "me voila"); + /*We put something in user_data to indicate that we went through this callback*/ + linphone_call_set_user_data(call, (void*)1); + }else{ + const char *ack_header; + ack_header = linphone_headers_get_value(ack, "Coucou"); + BC_ASSERT_PTR_NOT_NULL(ack_header); + if (ack_header){ + BC_ASSERT_STRING_EQUAL(ack_header, "me voila"); + } + linphone_call_set_user_data(call, (void*)1); + } +} + +static void call_created(LinphoneCore *lc, LinphoneCall *call){ + LinphoneCallCbs *cbs = linphone_factory_create_call_cbs(linphone_factory_get()); + linphone_call_cbs_set_ack_processing(cbs, on_ack_processing); + linphone_call_add_callbacks(call, cbs); + linphone_call_cbs_unref(cbs); +} + static void call_with_custom_headers(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); @@ -1690,6 +1713,8 @@ static void call_with_custom_headers(void) { LinphoneAddress* marie_identity; char* tmp=linphone_address_as_string_uri_only(marie->identity); char tmp2[256]; + LinphoneCoreCbs *core_cbs = linphone_factory_create_core_cbs(linphone_factory_get()); + snprintf(tmp2,sizeof(tmp2),"%s?uriHeader=myUriHeader",tmp); marie_identity=linphone_address_new(tmp2); ms_free(tmp); @@ -1699,6 +1724,10 @@ static void call_with_custom_headers(void) { params=linphone_core_create_call_params(marie->lc, NULL); linphone_call_params_add_custom_header(params,"Weather","bad"); linphone_call_params_add_custom_header(params,"Working","yes"); + + linphone_core_cbs_set_call_created(core_cbs, call_created); + linphone_core_add_callbacks(marie->lc, core_cbs); + linphone_core_add_callbacks(pauline->lc, core_cbs); if (!BC_ASSERT_TRUE(call_with_caller_params(pauline,marie,params))) goto end; @@ -1717,7 +1746,6 @@ static void call_with_custom_headers(void) { BC_ASSERT_PTR_NOT_NULL(hvalue); BC_ASSERT_STRING_EQUAL(hvalue,"myUriHeader"); - // FIXME: we have to strdup because successive calls to get_remote_params erase the returned const char*!! pauline_remote_contact = ms_strdup(linphone_call_get_remote_contact(call_pauline)); pauline_remote_contact_header = ms_strdup(linphone_call_params_get_custom_header(linphone_call_get_remote_params(call_pauline), "Contact")); @@ -1731,6 +1759,13 @@ static void call_with_custom_headers(void) { BC_ASSERT_PTR_NOT_NULL(marie_remote_contact_header); BC_ASSERT_STRING_EQUAL(pauline_remote_contact,pauline_remote_contact_header); BC_ASSERT_STRING_EQUAL(marie_remote_contact,marie_remote_contact_header); + + + /*we need to wait for the ack to arrive*/ + wait_for_until(marie->lc, pauline->lc, NULL, 0, 3000); + + BC_ASSERT_TRUE(linphone_call_get_user_data(call_marie) == (void*)1); + BC_ASSERT_TRUE(linphone_call_get_user_data(call_pauline) == (void*)1); ms_free(pauline_remote_contact); ms_free(pauline_remote_contact_header); @@ -1740,6 +1775,7 @@ static void call_with_custom_headers(void) { end_call(pauline, marie); end: + linphone_core_cbs_unref(core_cbs); linphone_call_params_unref(params); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline);