diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 48e477fde..9ed481d11 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -87,6 +87,7 @@ struct SalOp{ SalOpBase base; const belle_sip_listener_callbacks_t *callbacks; SalErrorInfo error_info; + SalErrorInfo reason_error_info; belle_sip_client_transaction_t *pending_auth_transaction; belle_sip_server_transaction_t* pending_server_trans; belle_sip_server_transaction_t* pending_update_server_trans; diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index e3d5571e4..6b4bc13d6 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -150,7 +150,7 @@ static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event if (op->pending_client_trans && (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_INIT)) { - sal_error_info_set(&op->error_info, SalReasonIOError, 503, "IO error", NULL); + sal_error_info_set(&op->error_info, SalReasonIOError, "SIP", 503, "IO error", NULL); op->base.root->callbacks.call_failure(op); if (!op->dialog || belle_sip_dialog_get_state(op->dialog) != BELLE_SIP_DIALOG_CONFIRMED){ @@ -386,7 +386,7 @@ static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t if (!op->dialog) { /*call terminated very early*/ - sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL); + sal_error_info_set(&op->error_info, SalReasonRequestTimeout, "SIP", 408, "Request timeout", NULL); op->base.root->callbacks.call_failure(op); op->state = SalOpStateTerminating; call_set_released(op); @@ -421,7 +421,7 @@ static void call_process_transaction_terminated(void *user_ctx, const belle_sip_ release_call=TRUE; }else if (op->state == SalOpStateEarly && code < 200){ /*call terminated early*/ - sal_error_info_set(&op->error_info,SalReasonIOError,503,"I/O error",NULL); + sal_error_info_set(&op->error_info, SalReasonIOError, "SIP", 503, "I/O error", NULL); op->state = SalOpStateTerminating; op->base.root->callbacks.call_failure(op); release_call=TRUE; @@ -1004,9 +1004,9 @@ int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ } /*it failed why ?*/ if (belle_sip_dialog_request_pending(op->dialog)) - sal_error_info_set(&op->error_info,SalReasonRequestPending,491,NULL,NULL); + sal_error_info_set(&op->error_info,SalReasonRequestPending, "SIP", 491,NULL,NULL); else - sal_error_info_set(&op->error_info,SalReasonUnknown,500,NULL,NULL); + sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", 500,NULL,NULL); return -1; } diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index 1d03c09a5..d3198fde9 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -52,7 +52,7 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher if (status_code == 503) { /*refresher returns 503 for IO error*/ reason = SalReasonIOError; } - sal_error_info_set(&op->error_info,reason,status_code,reason_phrase,NULL); + sal_error_info_set(&op->error_info, reason, "SIP", status_code,reason_phrase,NULL); op->base.root->callbacks.subscribe_response(op,sss, will_retry); }else if (status_code==0){ op->base.root->callbacks.on_expire(op); @@ -72,7 +72,7 @@ static void subscribe_process_io_error(void *user_ctx, const belle_sip_io_error_ /*this is handling outgoing out-of-dialog notifies*/ if (strcmp(method,"NOTIFY")==0){ SalErrorInfo *ei=&op->error_info; - sal_error_info_set(ei,SalReasonIOError,0,NULL,NULL); + sal_error_info_set(ei,SalReasonIOError, "SIP", 0,NULL,NULL); op->base.root->callbacks.on_notify_response(op); } } @@ -131,7 +131,7 @@ static void subscribe_process_timeout(void *user_ctx, const belle_sip_timeout_ev /*this is handling outgoing out-of-dialog notifies*/ if (strcmp(method,"NOTIFY")==0){ SalErrorInfo *ei=&op->error_info; - sal_error_info_set(ei,SalReasonRequestTimeout,0,NULL,NULL); + sal_error_info_set(ei,SalReasonRequestTimeout, "SIP", 0,NULL,NULL); op->base.root->callbacks.on_notify_response(op); } } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 135b53c4c..d7ddaa959 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -580,17 +580,22 @@ void sal_error_info_reset(SalErrorInfo *ei){ ms_free(ei->full_string); ei->full_string=NULL; } + if (ei->protocol){ + ms_free(ei->protocol); + ei->protocol = NULL; + } ei->protocol_code=0; ei->reason=SalReasonNone; } -void sal_error_info_set(SalErrorInfo *ei, SalReason reason, int code, const char *status_string, const char *warning){ +void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol, int code, const char *status_string, const char *warning){ sal_error_info_reset(ei); - if (reason==SalReasonUnknown) ei->reason=_sal_reason_from_sip_code(code); + if (reason==SalReasonUnknown && strcmp(protocol, "SIP") == 0) ei->reason=_sal_reason_from_sip_code(code); else ei->reason=reason; ei->protocol_code=code; ei->status_string=status_string ? ms_strdup(status_string) : NULL; ei->warnings=warning ? ms_strdup(warning) : NULL; + ei->protocol = protocol ? ms_strdup(protocol) : NULL; if (ei->status_string){ if (ei->warnings) ei->full_string=ms_strdup_printf("%s %s",ei->status_string,ei->warnings); @@ -598,24 +603,36 @@ void sal_error_info_set(SalErrorInfo *ei, SalReason reason, int code, const char } } +void sal_op_set_reason_error_info(SalOp *op, belle_sip_message_t *msg){ + belle_sip_header_reason_t* reason_header = belle_sip_message_get_header_by_type(msg,belle_sip_header_reason_t); + if (reason_header){ + SalErrorInfo *ei=&op->reason_error_info; + const char *protocol = belle_sip_header_reason_get_protocol(reason_header); + int code = belle_sip_header_reason_get_cause(reason_header); + const char *text = belle_sip_header_reason_get_text(reason_header); + sal_error_info_set(ei, SalReasonUnknown, protocol, code, text, NULL); + } +} + void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response){ int code = belle_sip_response_get_status_code(response); const char *reason_phrase=belle_sip_response_get_reason_phrase(response); - /*Remark: the reason header is to be used mainly in SIP requests, thus the use and prototype of this function should be changed.*/ - belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); belle_sip_header_t *warning=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Warning"); SalErrorInfo *ei=&op->error_info; const char *warnings; warnings=warning ? belle_sip_header_get_unparsed_value(warning) : NULL; - if (warnings==NULL) warnings=reason_header ? belle_sip_header_get_unparsed_value(reason_header) : NULL; - sal_error_info_set(ei,SalReasonUnknown,code,reason_phrase,warnings); + sal_error_info_set(ei,SalReasonUnknown,"SIP", code,reason_phrase,warnings); } const SalErrorInfo *sal_op_get_error_info(const SalOp *op){ return &op->error_info; } +const SalErrorInfo * sal_op_get_reason_error_info(const SalOp *op){ + return &op->reason_error_info; +} + static void unlink_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){ belle_sip_dialog_set_application_data(dialog,NULL); sal_op_unref(op); diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 348e271ec..cfb73763a 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -34,12 +34,12 @@ static void process_error( SalOp* op) { static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ SalOp* op = (SalOp*)user_ctx; - sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO Error",NULL); + sal_error_info_set(&op->error_info,SalReasonIOError, "SIP", 503,"IO Error",NULL); process_error(op); } static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { SalOp* op=(SalOp*)user_ctx; - sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL); + sal_error_info_set(&op->error_info,SalReasonRequestTimeout, "SIP", 408,"Request timeout",NULL); process_error(op); } diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index 7e832c6bb..2de596519 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -36,7 +36,7 @@ static void publish_refresher_listener (belle_sip_refresher_t* refresher sip_etag_string = belle_sip_header_get_unparsed_value(sip_etag); } sal_op_set_entity_tag(op, sip_etag_string); - sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", status_code,reason_phrase,NULL); sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); op->base.root->callbacks.on_publish_response(op); } diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 72b57b773..1d0ccbb3e 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -32,7 +32,7 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher /*only take first one for now*/ op->auth_info=sal_auth_info_create((belle_sip_auth_event_t*)(belle_sip_refresher_get_auth_events(refresher)->data)); } - sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", status_code,reason_phrase,NULL); if (status_code>=200){ sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index ea1f69d7b..9dbd95dd8 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -818,7 +818,8 @@ static void call_terminated(SalOp *op, const char *from){ break; case LinphoneCallIncomingReceived: case LinphoneCallIncomingEarlyMedia: - sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,0,"Incoming call cancelled",NULL); + linphone_error_info_set(call->ei, LinphoneReasonNotAnswered, 0, "Incoming call cancelled", NULL); + call->non_op_error = TRUE; break; default: break; diff --git a/coreapi/chat.c b/coreapi/chat.c index cfcfae604..761195ad6 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -463,7 +463,7 @@ void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage } if (retval > 0) { - sal_error_info_set((SalErrorInfo *)sal_op_get_error_info(op), SalReasonNotAcceptable, retval, "Unable to encrypt IM", NULL); + sal_error_info_set((SalErrorInfo *)sal_op_get_error_info(op), SalReasonNotAcceptable, "SIP", retval, "Unable to encrypt IM", NULL); store_or_update_chat_message(msg); linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered); linphone_chat_message_unref(msg); @@ -1656,6 +1656,8 @@ void linphone_chat_message_destroy(LinphoneChatMessage *msg) { static void _linphone_chat_message_destroy(LinphoneChatMessage *msg) { if (msg->op) sal_op_release(msg->op); + if (msg->ei) + linphone_error_info_unref(msg->ei); if (msg->message) ms_free(msg->message); if (msg->external_body_url) @@ -1706,7 +1708,9 @@ static void linphone_chat_message_release(LinphoneChatMessage *msg) { } const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg) { - return linphone_error_info_from_sal_op(msg->op); + if (!msg->ei) ((LinphoneChatMessage*)msg)->ei = linphone_error_info_new(); /*let's do it mutable*/ + linphone_error_info_from_sal_op(msg->ei, msg->op); + return msg->ei; } LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage *msg) { diff --git a/coreapi/error_info.c b/coreapi/error_info.c index 102c68e10..288b8e793 100644 --- a/coreapi/error_info.c +++ b/coreapi/error_info.c @@ -20,6 +20,49 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "linphone/core.h" #include "private.h" +BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneErrorInfo); + +#define STRING_RESET(field) if (field) ms_free(field); field = NULL; + + + +static void error_info_destroy(LinphoneErrorInfo *ei){ + if (ei->protocol) ms_free(ei->protocol); + if (ei->phrase) ms_free(ei->phrase); + if (ei->warnings) ms_free(ei->phrase); + if (ei->full_string) ms_free(ei->full_string); +} + +static void error_info_clone(LinphoneErrorInfo *ei, const LinphoneErrorInfo *other){ + ei->protocol = ms_strdup_safe(other->protocol); + ei->phrase = ms_strdup_safe(other->phrase); + ei->warnings = ms_strdup_safe(other->phrase); + ei->full_string = ms_strdup_safe(other->full_string); +} + +BELLE_SIP_INSTANCIATE_VPTR(LinphoneErrorInfo, belle_sip_object_t, + error_info_destroy, // destroy + error_info_clone, // clone + NULL, // Marshall + FALSE +); + +LinphoneErrorInfo *linphone_error_info_new(void){ + LinphoneErrorInfo *ei = belle_sip_object_new(LinphoneErrorInfo); + return ei; +} + +LinphoneErrorInfo* linphone_error_info_ref ( LinphoneErrorInfo* ei ) { + return (LinphoneErrorInfo*) belle_sip_object_ref(ei); +} + +void linphone_error_info_unref ( LinphoneErrorInfo* ei ) { + belle_sip_object_unref(ei); +} + +void linphone_error_info_set_reason ( LinphoneErrorInfo* ei, LinphoneReason reason ) { + ei->reason = reason; +} const char *linphone_reason_to_string(LinphoneReason err){ switch(err) { @@ -112,23 +155,101 @@ int linphone_reason_to_error_code(LinphoneReason reason) { return 400; } +void linphone_error_info_reset(LinphoneErrorInfo *ei){ + ei->reason = LinphoneReasonNone; + STRING_RESET(ei->protocol); + STRING_RESET(ei->phrase); + STRING_RESET(ei->full_string); + STRING_RESET(ei->warnings); + ei->protocol_code = 0; + if (ei->sub_ei) { + linphone_error_info_unref(ei->sub_ei); + ei->sub_ei = NULL; + } +} + +void linphone_error_info_from_sal(LinphoneErrorInfo *ei, const SalErrorInfo *sei){ + ei->reason = linphone_reason_from_sal(sei->reason); + ei->phrase = ms_strdup_safe(sei->status_string); + ei->full_string = ms_strdup_safe(sei->full_string); + ei->warnings = ms_strdup_safe(sei->warnings); + ei->protocol_code = sei->protocol_code; + ei->protocol = ms_strdup_safe(sei->protocol); +} + +/* If a reason header is provided (in reason_ei), then create a sub LinphoneErrorInfo attached to the first one, unless the reason header + is in the request, in which case no primary error is given.*/ +void linphone_error_info_from_sal_reason_ei(LinphoneErrorInfo *ei, const SalErrorInfo *reason_ei){ + if (ei->reason == LinphoneReasonNone){ + /*no primary error given*/ + linphone_error_info_reset(ei); + linphone_error_info_from_sal(ei, reason_ei); + return; + } + + if (ei->sub_ei){ + if (reason_ei->reason == SalReasonNone){ + linphone_error_info_unref(ei->sub_ei); + ei->sub_ei = NULL; + } + }else{ + if (reason_ei->reason != SalReasonNone){ + ei->sub_ei = linphone_error_info_new(); + } + } + if (reason_ei->reason != SalReasonNone){ + linphone_error_info_from_sal(ei->sub_ei, reason_ei); + } +} + +void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const SalOp *op){ + if (op==NULL) { + /*leave previous values in LinphoneErrorInfo, the op may have been released already.*/ + return; + }else{ + const SalErrorInfo *sei; + linphone_error_info_reset(ei); + sei = sal_op_get_error_info(op); + linphone_error_info_from_sal(ei, sei); + sei = sal_op_get_reason_error_info(op); + linphone_error_info_from_sal_reason_ei(ei, sei); + } +} + +void linphone_error_info_set(LinphoneErrorInfo *ei, LinphoneReason reason, int code, const char *status_string, const char *warning){ + linphone_error_info_reset(ei); + ei->reason = reason; + ei->protocol_code = code; + ei->phrase = ms_strdup_safe(status_string); + ei->warnings = ms_strdup_safe(warning); +} + LinphoneReason linphone_error_info_get_reason(const LinphoneErrorInfo *ei) { - const SalErrorInfo *sei = (const SalErrorInfo *)ei; - return linphone_reason_from_sal(sei->reason); + return ei->reason; +} + +const char *linphone_error_info_get_protocol(const LinphoneErrorInfo *ei){ + return ei->protocol; } const char *linphone_error_info_get_phrase(const LinphoneErrorInfo *ei) { - const SalErrorInfo *sei = (const SalErrorInfo *)ei; - return sei->status_string; + return ei->phrase; } -const char *linphone_error_info_get_details(const LinphoneErrorInfo *ei) { - const SalErrorInfo *sei = (const SalErrorInfo *)ei; - return sei->warnings; +/*deprecated, kept for binary compatibility*/ +const char *linphone_error_info_get_details(const LinphoneErrorInfo *ei){ + return linphone_error_info_get_warnings(ei); +} + +const char *linphone_error_info_get_warnings(const LinphoneErrorInfo *ei) { + return ei->warnings; } int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei) { - const SalErrorInfo *sei = (const SalErrorInfo *)ei; - return sei->protocol_code; + return ei->protocol_code; +} + +const LinphoneErrorInfo * linphone_error_info_get_sub_error_info(const LinphoneErrorInfo *ei){ + return ei->sub_ei; } diff --git a/coreapi/event.c b/coreapi/event.c index eafea9947..2f331c7be 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -156,7 +156,9 @@ LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev){ } const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev){ - return linphone_error_info_from_sal_op(lev->op); + if (!lev->ei) ((LinphoneEvent*)lev)->ei = linphone_error_info_new(); + linphone_error_info_from_sal_op(lev->ei, lev->op); + return lev->ei; } LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){ @@ -393,6 +395,7 @@ LinphoneEvent *linphone_event_ref(LinphoneEvent *lev){ } static void linphone_event_destroy(LinphoneEvent *lev){ + if (lev->ei) linphone_error_info_unref(lev->ei); if (lev->op) sal_op_release(lev->op); if (lev->send_custom_headers) sal_custom_header_free(lev->send_custom_headers); ms_free(lev->name); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 916d03856..afe792887 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1000,6 +1000,7 @@ static void port_config_set(LinphoneCall *call, int stream_index, int min_port, static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ int min_port, max_port; ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version()); + call->ei = linphone_error_info_new(); call->core->send_call_stats_periodical_updates = lp_config_get_int(call->core->config, "misc", "send_call_stats_periodical_updates", 0); call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO; call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO; @@ -1544,9 +1545,8 @@ static void linphone_call_free_media_resources(LinphoneCall *call){ static void linphone_call_set_released(LinphoneCall *call){ if (call->op!=NULL) { /*transfer the last error so that it can be obtained even in Released state*/ - if (call->non_op_error.reason==SalReasonNone){ - const SalErrorInfo *ei=sal_op_get_error_info(call->op); - sal_error_info_set(&call->non_op_error,ei->reason,ei->protocol_code,ei->status_string,ei->warnings); + if (!call->non_op_error){ + linphone_error_info_from_sal_op(call->ei, call->op); } /* so that we cannot have anymore upcalls for SAL concerning this call*/ @@ -1857,7 +1857,7 @@ static void linphone_call_destroy(LinphoneCall *obj){ } if (obj->onhold_file) ms_free(obj->onhold_file); - sal_error_info_reset(&obj->non_op_error); + if (obj->ei) linphone_error_info_unref(obj->ei); } LinphoneCall * linphone_call_ref(LinphoneCall *obj){ @@ -2046,9 +2046,10 @@ LinphoneReason linphone_call_get_reason(const LinphoneCall *call){ } const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call){ - if (call->non_op_error.reason!=SalReasonNone){ - return (const LinphoneErrorInfo*)&call->non_op_error; - }else return linphone_error_info_from_sal_op(call->op); + if (!call->non_op_error){ + linphone_error_info_from_sal_op(call->ei, call->op); + } + return call->ei; } void *linphone_call_get_user_data(const LinphoneCall *call) @@ -4325,7 +4326,8 @@ static void linphone_call_lost(LinphoneCall *call){ if (from) ms_free(from); ms_message("LinphoneCall [%p]: %s", call, temp); linphone_core_notify_display_warning(lc, temp); - sal_error_info_set(&call->non_op_error, SalReasonIOError, 503, "IO error", NULL); + call->non_op_error = TRUE; + linphone_error_info_set(call->ei, LinphoneReasonIOError, 503, "Media lost", NULL); linphone_call_terminate(call); linphone_core_play_named_tone(lc, LinphoneToneCallLost); ms_free(temp); @@ -5029,8 +5031,10 @@ int linphone_call_resume(LinphoneCall *call) { static void terminate_call(LinphoneCall *call) { LinphoneCore *lc = linphone_call_get_core(call); - if ((call->state == LinphoneCallIncomingReceived) && (call->non_op_error.reason != SalReasonRequestTimeout)) - call->non_op_error.reason=SalReasonDeclined; + if ((call->state == LinphoneCallIncomingReceived) && (linphone_error_info_get_reason(call->ei) != LinphoneReasonNotAnswered)){ + linphone_error_info_set_reason(call->ei, LinphoneReasonDeclined); + call->non_op_error = TRUE; + } /* Stop ringing */ linphone_core_stop_ringing(lc); @@ -5089,7 +5093,8 @@ int linphone_call_redirect(LinphoneCall *call, const char *redirect_uri) { real_url = linphone_address_as_string(real_parsed_url); sal_call_decline(call->op, SalReasonRedirect, real_url); ms_free(real_url); - sal_error_info_set(&call->non_op_error, SalReasonRedirect, 603, "Call redirected", NULL); + linphone_error_info_set(call->ei, LinphoneReasonMovedPermanently, 302, "Call redirected", NULL); + call->non_op_error = TRUE; terminate_call(call); linphone_address_unref(real_parsed_url); return 0; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index ca5fa9d64..d4c64e416 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2979,7 +2979,8 @@ void linphone_core_iterate(LinphoneCore *lc){ ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout); decline_reason = (lc->current_call != call) ? LinphoneReasonBusy : LinphoneReasonDeclined; call->log->status=LinphoneCallMissed; - sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,408,"Not answered",NULL); + call->non_op_error = TRUE; + linphone_error_info_set(call->ei, decline_reason, linphone_reason_to_error_code(decline_reason), "Not answered", NULL); linphone_call_decline(call, decline_reason); } } diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 191249d1e..54b9f4146 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -7278,7 +7278,7 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getPhrase(JNIEnv * Signature: (J)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getDetails(JNIEnv *env, jobject jobj, jlong ei){ - const char *tmp=linphone_error_info_get_details((const LinphoneErrorInfo*)ei); + const char *tmp=linphone_error_info_get_warnings((const LinphoneErrorInfo*)ei); return tmp ? env->NewStringUTF(tmp) : NULL; } diff --git a/coreapi/private.h b/coreapi/private.h index 9a06306cf..0ff8700cc 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -124,6 +124,8 @@ #ifdef __cplusplus extern "C" { #endif + +#define ms_strdup_safe(str) ((str) ? ms_strdup(str) : NULL) struct _LinphoneCallParams{ belle_sip_object_t base; @@ -230,6 +232,7 @@ struct _LinphoneChatMessage { belle_sip_object_t base; LinphoneChatRoom* chat_room; LinphoneChatMessageCbs *callbacks; + LinphoneErrorInfo *ei; LinphoneChatMessageDir dir; char* message; void* message_state_changed_user_data; @@ -288,7 +291,7 @@ struct _LinphoneCall{ belle_sip_object_t base; void *user_data; struct _LinphoneCore *core; - SalErrorInfo non_op_error; + LinphoneErrorInfo *ei; int af; /*the address family to prefer for RTP path, guessed from signaling path*/ LinphoneCallDir dir; SalMediaDescription *biggestdesc; /*media description with all already proposed streams, used to remember the mapping of streams*/ @@ -370,7 +373,9 @@ struct _LinphoneCall{ bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */ bool_t defer_notify_incoming; bool_t need_localip_refresh; + bool_t reinvite_on_cancel_response_requested; + bool_t non_op_error; /*set when the LinphoneErrorInfo was set at higher level than sal*/ }; BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCall); @@ -624,6 +629,7 @@ struct _LinphoneProxyConfig belle_sip_object_t base; void *user_data; struct _LinphoneCore *lc; + LinphoneErrorInfo *ei; char *reg_proxy; char *reg_identity; LinphoneAddress* identity_address; @@ -1101,6 +1107,7 @@ struct _LinphoneCore struct _LinphoneEvent{ belle_sip_object_t base; + LinphoneErrorInfo *ei; LinphoneSubscriptionDir dir; LinphoneCore *lc; SalOp *op; @@ -1514,10 +1521,7 @@ void linphone_xml_xpath_context_init_carddav_ns(xmlparsing_context_t *xml_ctx); char * linphone_timestamp_to_rfc3339_string(time_t timestamp); -static MS2_INLINE const LinphoneErrorInfo *linphone_error_info_from_sal_op(const SalOp *op){ - if (op==NULL) return (LinphoneErrorInfo*)sal_error_info_none(); - return (const LinphoneErrorInfo*)sal_op_get_error_info(op); -} +void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const SalOp *op); static MS2_INLINE void payload_type_set_enable(PayloadType *pt,int value) { @@ -1606,7 +1610,7 @@ BELLE_SIP_TYPE_ID(LinphonePresenceService), BELLE_SIP_TYPE_ID(LinphonePresencePerson), BELLE_SIP_TYPE_ID(LinphonePresenceActivity), BELLE_SIP_TYPE_ID(LinphonePresenceNote), -BELLE_SIP_TYPE_ID(LinphoneTunnel), +BELLE_SIP_TYPE_ID(LinphoneErrorInfo) BELLE_SIP_TYPE_ID(LinphoneConferenceParams), BELLE_SIP_TYPE_ID(LinphoneConference), BELLE_SIP_TYPE_ID(LinphoneInfoMessage) @@ -1733,6 +1737,18 @@ void linphone_call_check_ice_session(LinphoneCall *call, IceRole role, bool_t is bool_t linphone_call_state_is_early(LinphoneCallState state); +struct _LinphoneErrorInfo{ + belle_sip_object_t base; + LinphoneReason reason; + char *protocol; /* */ + int protocol_code; /*from SIP response*/ + char *phrase; /*from SIP response*/ + char *warnings; /*from SIP response*/ + char *full_string; /*concatenation of status_string + warnings*/ + struct _LinphoneErrorInfo *sub_ei; +}; +BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneErrorInfo); + #ifdef __cplusplus } #endif diff --git a/coreapi/proxy.c b/coreapi/proxy.c index a522b2101..1968d7896 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -225,6 +225,9 @@ void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg){ if (cfg->nat_policy != NULL) { linphone_nat_policy_unref(cfg->nat_policy); } + if (cfg->ei){ + linphone_error_info_unref(cfg->ei); + } _linphone_proxy_config_release_ops(cfg); } @@ -1334,7 +1337,9 @@ LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg) { } const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProxyConfig *cfg){ - return linphone_error_info_from_sal_op(cfg->op); + if (!cfg->ei) ((LinphoneProxyConfig*)cfg)->ei = linphone_error_info_new(); + linphone_error_info_from_sal_op(cfg->ei, cfg->op); + return cfg->ei; } const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg) { diff --git a/include/linphone/error_info.h b/include/linphone/error_info.h index af54bc387..22f5e59fa 100644 --- a/include/linphone/error_info.h +++ b/include/linphone/error_info.h @@ -31,6 +31,30 @@ extern "C" { * @{ */ +/** + * Create an empty LinphoneErrorInfo object. + * The LinphoneErrorInfo object carries these fields: + * - a LinphoneReason enum member giving overall signification of the error reported. + * - the "protocol" name in which the protocol reason code has meaning, for example SIP or Q.850 + * - the "protocol code", an integer referencing the kind of error reported + * - the "phrase", a text phrase describing the error + * - the "warning", the content of warning headers if any + * - a sub "LinphoneErrorInfo" may be provided if a SIP response includes a Reason header (RFC3326). +**/ +LINPHONE_PUBLIC LinphoneErrorInfo *linphone_error_info_new(void); + +/** + * Increment refcount. + * @param[in] ei ErrorInfo object +**/ +LINPHONE_PUBLIC LinphoneErrorInfo *linphone_error_info_ref(LinphoneErrorInfo *ei); + +/** + * Decrement refcount and possibly free the object. + * @param[in] ei ErrorInfo object +**/ +LINPHONE_PUBLIC void linphone_error_info_unref(LinphoneErrorInfo *ei); + /** * Get reason code from the error info. * @param[in] ei ErrorInfo object @@ -48,11 +72,12 @@ LINPHONE_PUBLIC const char * linphone_error_info_get_phrase(const LinphoneErrorI /** * Provides additional information regarding the failure. - * With SIP protocol, the "Reason" and "Warning" headers are returned. + * With SIP protocol, the content of "Warning" headers are returned. * @param[in] ei ErrorInfo object * @return More details about the failure **/ -LINPHONE_PUBLIC const char * linphone_error_info_get_details(const LinphoneErrorInfo *ei); +LINPHONE_PUBLIC const char * linphone_error_info_get_warnings(const LinphoneErrorInfo *ei); + /** * Get the status code from the low level protocol (ex a SIP status code). @@ -61,6 +86,14 @@ LINPHONE_PUBLIC const char * linphone_error_info_get_details(const LinphoneError **/ LINPHONE_PUBLIC int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei); +/** + * Assign information to a LinphoneErrorInfo object. + * @param[in] ei ErrorInfo object + */ +LINPHONE_PUBLIC void linphone_error_info_set(LinphoneErrorInfo *ei, LinphoneReason reason, int code, const char *status_string, const char *warning); + +LINPHONE_PUBLIC void linphone_error_info_set_reason(LinphoneErrorInfo *ei, LinphoneReason reason); + /** * @} */ diff --git a/include/sal/sal.h b/include/sal/sal.h index 1e355c722..40ed02341 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -410,6 +410,7 @@ typedef struct SalErrorInfo{ char *status_string; int protocol_code; char *warnings; + char *protocol; char *full_string; /*concatenation of status_string + warnings*/ }SalErrorInfo; @@ -726,8 +727,9 @@ bool_t sal_op_is_idle(SalOp *op); const SalErrorInfo *sal_error_info_none(void); LINPHONE_PUBLIC const SalErrorInfo *sal_op_get_error_info(const SalOp *op); +const SalErrorInfo *sal_op_get_reason_error_info(const SalOp *op); void sal_error_info_reset(SalErrorInfo *ei); -void sal_error_info_set(SalErrorInfo *ei, SalReason reason, int code, const char *status_string, const char *warning); +void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol, int code, const char *status_string, const char *warning); /*entity tag used for publish (see RFC 3903)*/ const char *sal_op_get_entity_tag(const SalOp* op); diff --git a/mediastreamer2 b/mediastreamer2 index 237786682..ffdd8375f 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2377866823f41056109519fbc362ddd6fc8214e9 +Subproject commit ffdd8375f332e04c0d7642fb1da414124145256e diff --git a/oRTP b/oRTP index 920817911..235e5175b 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 920817911d9287250d9ddf506aede06744faae4b +Subproject commit 235e5175b2befa2d3e5f19cd969b0f3bda5b9b4c diff --git a/tester/register_tester.c b/tester/register_tester.c index ca55e17ee..33819efb7 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -465,7 +465,7 @@ static void authenticated_register_with_wrong_credentials_with_params_base(const BC_ASSERT_PTR_NOT_NULL(phrase); if (phrase) BC_ASSERT_STRING_EQUAL(phrase,"Forbidden"); BC_ASSERT_EQUAL(linphone_error_info_get_protocol_code(ei),403, int, "%d"); - BC_ASSERT_PTR_NULL(linphone_error_info_get_details(ei)); + BC_ASSERT_PTR_NULL(linphone_error_info_get_warnings(ei)); } }