diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 47242cdd5..be3c9ba17 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -162,8 +162,8 @@ void sal_process_authentication(SalOp *op) { static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){ belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_event_get_dialog(event); SalOp* op = belle_sip_dialog_get_application_data(dialog); - if (op && op->callbacks.process_dialog_terminated) { - op->callbacks.process_dialog_terminated(op,event); + if (op && op->callbacks && op->callbacks->process_dialog_terminated) { + op->callbacks->process_dialog_terminated(op,event); } else { ms_error("sal process_dialog_terminated no op found for this dialog [%p], ignoring",dialog); } @@ -177,8 +177,8 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); /*also reset auth count on IO error*/ op->auth_requests=0; - if (op->callbacks.process_io_error) { - op->callbacks.process_io_error(op,event); + if (op->callbacks && op->callbacks->process_io_error) { + op->callbacks->process_io_error(op,event); } } else { /*ms_error("sal process_io_error not implemented yet for non transaction");*/ @@ -290,8 +290,8 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve sal_op_set_privacy_from_message(op,(belle_sip_message_t*)req); sal_op_assign_recv_headers(op,(belle_sip_message_t*)req); - if (op->callbacks.process_request_event) { - op->callbacks.process_request_event(op,event); + if (op->callbacks && op->callbacks->process_request_event) { + op->callbacks->process_request_event(op,event); } else { ms_error("sal process_request_event not implemented yet"); } @@ -329,7 +329,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even sal_op_assign_recv_headers(op,(belle_sip_message_t*)response); - if (op->callbacks.process_response_event) { + if (op->callbacks && op->callbacks->process_response_event) { /*handle authorization*/ switch (response_code) { case 200: @@ -365,7 +365,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even /*not an auth request*/ op->auth_requests=0; } - op->callbacks.process_response_event(op,event); + op->callbacks->process_response_event(op,event); } else { ms_error("Unhandled event response [%p]",event); } @@ -375,8 +375,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event); SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); - if (op && op->callbacks.process_timeout) { - op->callbacks.process_timeout(op,event); + if (op && op->callbacks && op->callbacks->process_timeout) { + op->callbacks->process_timeout(op,event); } else { ms_error("Unhandled event timeout [%p]",event); } @@ -393,8 +393,8 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans trans=BELLE_SIP_TRANSACTION(server_transaction); op = (SalOp*)belle_sip_transaction_get_application_data(trans); - if (op && op->callbacks.process_transaction_terminated) { - op->callbacks.process_transaction_terminated(op,event); + if (op && op->callbacks && op->callbacks->process_transaction_terminated) { + op->callbacks->process_transaction_terminated(op,event); } else { ms_message("Unhandled transaction terminated [%p]",trans); } @@ -443,6 +443,7 @@ Sal * sal_init(){ sal->refresher_retry_after=60000; /*default value in ms*/ return sal; } + void sal_set_user_pointer(Sal *sal, void *user_data){ sal->up=user_data; } diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 1a38ce7dc..c203c9cb1 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -76,7 +76,8 @@ const char* sal_op_type_to_string(SalOpType type); struct SalOp{ SalOpBase base; - belle_sip_listener_callbacks_t callbacks; + const belle_sip_listener_callbacks_t *callbacks; + SalErrorInfo 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; @@ -132,8 +133,10 @@ bool_t sal_op_is_secure(const SalOp* op); void sal_process_authentication(SalOp *op); belle_sip_header_contact_t* sal_op_create_contact(SalOp *op) ; -bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size); -void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) ; +bool_t _sal_compute_sal_errors(belle_sip_response_t* response, SalReason* sal_reason, char* reason, size_t reason_size); +SalReason _sal_reason_from_sip_code(int code); + +void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response); /*presence*/ void sal_op_presence_fill_cbs(SalOp*op); /*messaging*/ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 01422e224..a77acafd0 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -38,19 +38,8 @@ static void call_set_released_and_unref(SalOp* op) { static void call_set_error(SalOp* op,belle_sip_response_t* response){ - SalError error=SalErrorUnknown; - SalReason sr=SalReasonUnknown; - belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); - char* reason=(char*)belle_sip_response_get_reason_phrase(response); - int code = belle_sip_response_get_status_code(response); - if (reason_header){ - reason = ms_strdup_printf("%s %s",reason,belle_sip_header_get_unparsed_value(reason_header)); - } - sal_compute_sal_errors_from_code(code,&error,&sr); - op->base.root->callbacks.call_failure(op,error,sr,reason,code); - if (reason_header != NULL){ - ms_free(reason); - } + sal_op_set_error_info_from_response(op,response); + op->base.root->callbacks.call_failure(op); } static void sdp_process(SalOp *h){ @@ -127,7 +116,8 @@ static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event if (!op->dialog) { /*call terminated very early*/ - op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503); + sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO error",NULL); + op->base.root->callbacks.call_failure(op); call_set_released(op); } else { /*dialog will terminated shortly, nothing to do*/ @@ -290,7 +280,8 @@ static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t if (!op->dialog) { /*call terminated very early*/ - op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408); + sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL); + op->base.root->callbacks.call_failure(op); call_set_released(op); } else { /*dialog will terminated shortly, nothing to do*/ @@ -631,13 +622,18 @@ int sal_call(SalOp *op, const char *from, const char *to){ return sal_op_send_request(op,invite); } +static belle_sip_listener_callbacks_t call_op_callbacks={0}; + void sal_op_call_fill_cbs(SalOp*op) { - op->callbacks.process_io_error=call_process_io_error; - op->callbacks.process_response_event=call_process_response; - 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; + if (call_op_callbacks.process_response_event==NULL){ + call_op_callbacks.process_io_error=call_process_io_error; + call_op_callbacks.process_response_event=call_process_response; + call_op_callbacks.process_timeout=call_process_timeout; + call_op_callbacks.process_transaction_terminated=call_process_transaction_terminated; + call_op_callbacks.process_request_event=process_request_event; + call_op_callbacks.process_dialog_terminated=process_dialog_terminated; + } + op->callbacks=&call_op_callbacks; op->type=SalOpCall; } diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index 1972c97f6..4409c73a3 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -37,8 +37,6 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher ,unsigned int status_code ,const char* reason_phrase) { SalOp* op = (SalOp*)user_pointer; - SalError error=SalErrorUnknown; - SalReason sr=SalReasonUnknown; belle_sip_transaction_t *tr=BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)); /*belle_sip_response_t* response=belle_sip_transaction_get_response(tr);*/ SalSubscribeStatus sss=SalSubscribeTerminated; @@ -50,8 +48,8 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher set_or_update_dialog(op,belle_sip_transaction_get_dialog(tr)); } if (status_code>=200){ - sal_compute_sal_errors_from_code(status_code,&error,&sr); - op->base.root->callbacks.subscribe_response(op,sss,error,sr); + sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + op->base.root->callbacks.subscribe_response(op,sss); }else if (status_code==0){ op->base.root->callbacks.on_expire(op); } @@ -172,13 +170,18 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque } } +static belle_sip_listener_callbacks_t op_subscribe_callbacks={ 0 }; + void sal_op_subscribe_fill_cbs(SalOp*op) { - op->callbacks.process_io_error=subscribe_process_io_error; - op->callbacks.process_response_event=subscribe_response_event; - op->callbacks.process_timeout=subscribe_process_timeout; - op->callbacks.process_transaction_terminated=subscribe_process_transaction_terminated; - op->callbacks.process_request_event=subscribe_process_request_event; - op->callbacks.process_dialog_terminated=subscribe_process_dialog_terminated; + if (op_subscribe_callbacks.process_io_error==NULL){ + op_subscribe_callbacks.process_io_error=subscribe_process_io_error; + op_subscribe_callbacks.process_response_event=subscribe_response_event; + op_subscribe_callbacks.process_timeout=subscribe_process_timeout; + op_subscribe_callbacks.process_transaction_terminated=subscribe_process_transaction_terminated; + op_subscribe_callbacks.process_request_event=subscribe_process_request_event; + op_subscribe_callbacks.process_dialog_terminated=subscribe_process_dialog_terminated; + } + op->callbacks=&op_subscribe_callbacks; op->type=SalOpSubscribe; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index b3124300c..3e5ebe2a5 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -62,6 +62,7 @@ void sal_op_release_impl(SalOp *op){ if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans); if (op->event) belle_sip_object_unref(op->event); + sal_error_info_reset(&op->error_info); __sal_op_free(op); return ; } @@ -334,6 +335,12 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { SalReason sal_reason_to_sip_code(SalReason r){ int ret=500; switch(r){ + case SalReasonNone: + ret=200; + break; + case SalReasonIOError: + ret=503; + break; case SalReasonUnknown: ret=400; break; @@ -401,110 +408,123 @@ SalReason sal_reason_to_sip_code(SalReason r){ return ret; } -void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) { - *sal_err=SalErrorFailure; +SalReason _sal_reason_from_sip_code(int code) { + if (code>=100 && code<300) return SalReasonNone; + switch(code) { + case 0: + return SalReasonIOError; case 301: - *sal_reason=SalReasonMovedPermanently; - break; + return SalReasonMovedPermanently; case 302: - *sal_reason=SalReasonRedirect; - break; + return SalReasonRedirect; case 401: case 407: - *sal_reason=SalReasonUnauthorized; - break; + return SalReasonUnauthorized; case 403: - *sal_reason=SalReasonForbidden; - break; + return SalReasonForbidden; case 404: - *sal_reason=SalReasonNotFound; - break; + return SalReasonNotFound; case 408: - *sal_reason=SalReasonRequestTimeout; - break; + return SalReasonRequestTimeout; case 410: - *sal_reason=SalReasonGone; - break; + return SalReasonGone; case 415: - *sal_reason=SalReasonUnsupportedContent; - break; + return SalReasonUnsupportedContent; case 422: ms_error ("422 not implemented yet");; break; case 480: - *sal_reason=SalReasonTemporarilyUnavailable; - break; + return SalReasonTemporarilyUnavailable; case 481: - *sal_reason=SalReasonNoMatch; - break; + return SalReasonNoMatch; case 484: - *sal_reason=SalReasonAddressIncomplete; - break; + return SalReasonAddressIncomplete; case 486: - *sal_reason=SalReasonBusy; - break; + return SalReasonBusy; case 487: - break; + return SalReasonNone; case 488: - *sal_reason=SalReasonNotAcceptable; - break; + return SalReasonNotAcceptable; case 491: - *sal_reason=SalReasonRequestPending; - break; + return SalReasonRequestPending; case 501: - *sal_reason=SalReasonNotImplemented; - break; + return SalReasonNotImplemented; case 502: - *sal_reason=SalReasonBadGateway; - break; + return SalReasonBadGateway; case 504: - *sal_reason=SalReasonServerTimeout; - break; + return SalReasonServerTimeout; case 600: - *sal_reason=SalReasonDoNotDisturb; - break; + return SalReasonDoNotDisturb; case 603: - *sal_reason=SalReasonDeclined; - break; + return SalReasonDeclined; case 503: - *sal_reason=SalReasonServiceUnavailable; - break; + return SalReasonServiceUnavailable; default: - if (code>=300){ - *sal_err=SalErrorFailure; - *sal_reason=SalReasonUnknown; - }else if (code>=100){ - *sal_err=SalErrorNone; - *sal_reason=SalReasonUnknown; - }else if (code==0){ - *sal_err=SalErrorNoResponse; - } - /* no break */ + return SalReasonUnknown; + } + return SalReasonUnknown; +} + +const SalErrorInfo *sal_error_info_none(void){ + static SalErrorInfo none={ + SalReasonNone, + "Ok", + 200, + NULL, + NULL + }; + return &none; +} + +void sal_error_info_reset(SalErrorInfo *ei){ + if (ei->status_string){ + ms_free(ei->status_string); + ei->status_string=NULL; + } + if (ei->warnings){ + ms_free(ei->warnings); + ei->warnings=NULL; + + } + if (ei->full_string){ + ms_free(ei->full_string); + ei->full_string=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){ + sal_error_info_reset(ei); + if (reason==SalReasonUnknown) 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; + if (ei->status_string){ + if (ei->warnings) + ei->full_string=ms_strdup_printf("%s %s",ei->status_string,ei->warnings); + else ei->full_string=ms_strdup(ei->status_string); } } -/*return TRUE if error code*/ -bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) { - int code = belle_sip_response_get_status_code(response); - belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason"); - *sal_err=SalErrorUnknown; - *sal_reason = SalReasonUnknown; - if (reason_header){ - snprintf(reason - ,reason_size - ,"%s %s" - ,belle_sip_response_get_reason_phrase(response) - ,belle_sip_header_get_unparsed_value(reason_header)); - } else { - strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size); - } - if (code>=400) { - sal_compute_sal_errors_from_code(code,sal_err,sal_reason); - return TRUE; - } else { - return FALSE; - } +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); +} + +const SalErrorInfo *sal_op_get_error_info(const SalOp *op){ + return &op->error_info; } void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index bf7f7b82a..05f1199b8 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void process_error( SalOp* op) { if (op->dir == SalOpDirOutgoing) { - op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed, SalReasonUnknown); + op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed); } else { ms_warning("unexpected io error for incoming message on op [%p]",op); } @@ -30,33 +30,20 @@ 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; -// belle_sip_object_t* source = belle_sip_io_error_event_get_source(event); -// if (BELLE_SIP_IS_INSTANCE_OF(source,belle_sip_transaction_t)) { -// /*reset op to make sure transaction terminated does not need op*/ -// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(source),NULL); -// } + sal_error_info_set(&op->error_info,SalReasonIOError,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; -// belle_sip_client_transaction_t *client_transaction=belle_sip_timeout_event_get_client_transaction(event); -// belle_sip_server_transaction_t *server_transaction=belle_sip_timeout_event_get_server_transaction(event); -// /*reset op to make sure transaction terminated does not need op*/ -// if (client_transaction) { -// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL); -// } else { -// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),NULL); -// } + sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL); process_error(op); } static void process_response_event(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; - /*belle_sip_client_transaction_t *client_transaction=belle_sip_response_event_get_client_transaction(event);*/ int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); SalTextDeliveryStatus status; - SalReason reason=SalReasonUnknown; - SalError err=SalErrorNone; + sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event)); if (code>=100 && code <200) status=SalTextDeliveryInProgress; @@ -64,13 +51,10 @@ static void process_response_event(void *op_base, const belle_sip_response_event status=SalTextDeliveryDone; else status=SalTextDeliveryFailed; - if (status != SalTextDeliveryInProgress) { - /*reset op to make sure transaction terminated does not need op - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*/ - } - sal_compute_sal_errors_from_code(code,&err,&reason); - op->base.root->callbacks.text_delivery_update(op,status, reason); + + op->base.root->callbacks.text_delivery_update(op,status); } + static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) { return strcmp("text",belle_sip_header_content_type_get_type(content_type))==0 && strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0; @@ -191,10 +175,15 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) return sal_message_send(op,from,to,"text/plain",msg); } +static belle_sip_listener_callbacks_t op_message_callbacks={0}; + void sal_op_message_fill_cbs(SalOp*op) { - op->callbacks.process_io_error=process_io_error; - op->callbacks.process_response_event=process_response_event; - op->callbacks.process_timeout=process_timeout; - op->callbacks.process_request_event=process_request_event; + if (op_message_callbacks.process_io_error==NULL){ + op_message_callbacks.process_io_error=process_io_error; + op_message_callbacks.process_response_event=process_response_event; + op_message_callbacks.process_timeout=process_timeout; + op_message_callbacks.process_request_event=process_request_event; + } + op->callbacks=&op_message_callbacks; op->type=SalOpMessage; } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index 9f7d6f871..ca526fd5d 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -94,13 +94,12 @@ static void presence_response_event(void *op_base, const belle_sip_response_even belle_sip_response_t* response=belle_sip_response_event_get_response(event); belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); int code = belle_sip_response_get_status_code(response); - char reason[256]={0}; - SalError error=SalErrorUnknown; - SalReason sr=SalReasonUnknown; belle_sip_header_expires_t* expires; + + sal_op_set_error_info_from_response(op,response); - if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) { - ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr)); + if (code>=300) { + ms_message("subscription to [%s] rejected",sal_op_get_to(op)); op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ return; } @@ -267,13 +266,18 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques } } +static belle_sip_listener_callbacks_t op_presence_callbacks={0}; + void sal_op_presence_fill_cbs(SalOp*op) { - op->callbacks.process_io_error=presence_process_io_error; - op->callbacks.process_response_event=presence_response_event; - op->callbacks.process_timeout=presence_process_timeout; - op->callbacks.process_transaction_terminated=presence_process_transaction_terminated; - op->callbacks.process_request_event=presence_process_request_event; - op->callbacks.process_dialog_terminated=presence_process_dialog_terminated; + if (op_presence_callbacks.process_request_event==NULL){ + op_presence_callbacks.process_io_error=presence_process_io_error; + op_presence_callbacks.process_response_event=presence_response_event; + op_presence_callbacks.process_timeout=presence_process_timeout; + op_presence_callbacks.process_transaction_terminated=presence_process_transaction_terminated; + op_presence_callbacks.process_request_event=presence_process_request_event; + op_presence_callbacks.process_dialog_terminated=presence_process_dialog_terminated; + } + op->callbacks=&op_presence_callbacks; op->type=SalOpPresence; } diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c index a55042919..81a7ce724 100644 --- a/coreapi/bellesip_sal/sal_op_publish.c +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -35,24 +35,26 @@ static void publish_refresher_listener (belle_sip_refresher_t* refresher }else if (status_code==0){ op->base.root->callbacks.on_expire(op); }else if (status_code>=200){ - SalError err; - SalReason reason; - sal_compute_sal_errors_from_code(status_code,&err,&reason); - op->base.root->callbacks.on_publish_response(op,err,reason); + sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + op->base.root->callbacks.on_publish_response(op); } } static void publish_response_event(void *userctx, const belle_sip_response_event_t *event){ SalOp *op=(SalOp*)userctx; - int code=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); - SalError err; - SalReason reason; - sal_compute_sal_errors_from_code(code,&err,&reason); - op->base.root->callbacks.on_publish_response(op,err,reason); + sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event)); + if (op->error_info.protocol_code>=200){ + op->base.root->callbacks.on_publish_response(op); + } } -void sal_op_publish_fill_cbs(SalOp*op) { - op->callbacks.process_response_event=publish_response_event; +static belle_sip_listener_callbacks_t op_publish_callbacks={0}; + +void sal_op_publish_fill_cbs(SalOp *op) { + if (op_publish_callbacks.process_response_event==NULL){ + op_publish_callbacks.process_response_event=publish_response_event; + } + op->callbacks=&op_publish_callbacks; op->type=SalOpPublish; } diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 2f12d4533..17a3861b4 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -24,8 +24,6 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher ,unsigned int status_code ,const char* reason_phrase) { SalOp* op = (SalOp*)user_pointer; - SalError sal_err; - SalReason sal_reason; belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher))); ms_message("Register refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op)); @@ -57,9 +55,8 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher chooses not to re-register, the UA SHOULD discard any stored service route for that address-of-record. */ sal_op_set_service_route(op,NULL); - - sal_compute_sal_errors_from_code(status_code,&sal_err,&sal_reason); - op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase); + sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL); + op->base.root->callbacks.register_failure(op); if (op->auth_info) { /*add pending auth*/ sal_add_pending_auth(op->base.root,op); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 469baf8af..80818be37 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #endif -static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details); +static void register_failure(SalOp *op); static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) { if (call->params.in_conference != call->current_params.in_conference) return SAL_MEDIA_DESCRIPTION_CHANGED; @@ -550,7 +550,7 @@ static void call_terminated(SalOp *op, const char *from){ break; case LinphoneCallIncomingReceived: case LinphoneCallIncomingEarlyMedia: - call->reason=LinphoneReasonNotAnswered; + sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,0,"Incoming call cancelled",NULL); break; default: break; @@ -593,14 +593,15 @@ static int resume_call_after_failed_transfer(LinphoneCall *call){ return BELLE_SIP_STOP; } -static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){ +static void call_failure(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + const SalErrorInfo *ei=sal_op_get_error_info(op); char *msg486=_("User is busy."); char *msg480=_("User is temporarily unavailable."); /*char *retrymsg=_("%s. Retry after %i minute(s).");*/ char *msg600=_("User does not want to be disturbed."); char *msg603=_("Call declined."); - const char *msg=details; + const char *msg=ei->full_string; LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); LinphoneCall *referer=call->referer; @@ -610,102 +611,95 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de } if (lc->vtable.show) lc->vtable.show(lc); - - if (error==SalErrorNoResponse){ - msg=_("No response."); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); - }else if (error==SalErrorProtocol){ - msg=details ? details : _("Protocol error."); - if (lc->vtable.display_status) - lc->vtable.display_status(lc, msg); - }else if (error==SalErrorFailure){ - switch(sr){ - case SalReasonDeclined: - msg=msg603; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg603); - break; - case SalReasonBusy: - msg=msg486; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg486); - break; - case SalReasonRedirect: - { - ms_error("case SalReasonRedirect"); + switch(ei->reason){ + case SalReasonNone: + break; + case SalReasonRequestTimeout: + msg=_("Request timeout."); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg); + break; + case SalReasonDeclined: + msg=msg603; + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg603); + break; + case SalReasonBusy: + msg=msg486; + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg486); + break; + case SalReasonRedirect: + { + linphone_call_stop_media_streams(call); + if ( call->state==LinphoneCallOutgoingInit + || call->state==LinphoneCallOutgoingProgress + || call->state==LinphoneCallOutgoingRinging /*push case*/ + || call->state==LinphoneCallOutgoingEarlyMedia){ + LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op); + if( redirection_to ){ + char* url = linphone_address_as_string(redirection_to); + ms_warning("Redirecting call [%p] to %s",call, url); + ms_free(url); + linphone_call_create_op(call); + linphone_core_start_invite(lc, call, redirection_to); + return; + } + } + msg=_("Redirected"); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg); + } + break; + case SalReasonTemporarilyUnavailable: + msg=msg480; + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg480); + break; + case SalReasonNotFound: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg); + break; + case SalReasonDoNotDisturb: + msg=msg600; + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg600); + break; + case SalReasonUnsupportedContent: /*params.media_encryption == LinphoneMediaEncryptionSRTP && + !linphone_core_is_media_encryption_mandatory(lc)) { + int i; + ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call); linphone_call_stop_media_streams(call); - if ( call->state==LinphoneCallOutgoingInit + if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress || call->state==LinphoneCallOutgoingRinging /*push case*/ || call->state==LinphoneCallOutgoingEarlyMedia){ - LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op); - if( redirection_to ){ - char* url = linphone_address_as_string(redirection_to); - ms_error("Redirecting call [%p] to %s",call, url); - ms_free(url); - linphone_call_create_op(call); - linphone_core_start_invite(lc, call, redirection_to); - return; + ms_message("Retrying call [%p] with AVP",call); + /* clear SRTP local params */ + call->params.media_encryption = LinphoneMediaEncryptionNone; + for(i=0; ilocaldesc->n_active_streams; i++) { + call->localdesc->streams[i].proto = SalProtoRtpAvp; + memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); } + linphone_core_restart_invite(lc, call); + return; } - msg=_("Redirected"); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); } - break; - case SalReasonTemporarilyUnavailable: - msg=msg480; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg480); - break; - case SalReasonNotFound: - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); - break; - case SalReasonDoNotDisturb: - msg=msg600; - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg600); - break; - case SalReasonUnsupportedContent: /*params.media_encryption == LinphoneMediaEncryptionSRTP && - !linphone_core_is_media_encryption_mandatory(lc)) { - int i; - ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call); - linphone_call_stop_media_streams(call); - if ( call->state==LinphoneCallOutgoingInit - || call->state==LinphoneCallOutgoingProgress - || call->state==LinphoneCallOutgoingRinging /*push case*/ - || call->state==LinphoneCallOutgoingEarlyMedia){ - ms_message("Retrying call [%p] with AVP",call); - /* clear SRTP local params */ - call->params.media_encryption = LinphoneMediaEncryptionNone; - for(i=0; ilocaldesc->n_active_streams; i++) { - call->localdesc->streams[i].proto = SalProtoRtpAvp; - memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); - } - linphone_core_restart_invite(lc, call); - return; - } - - } - msg=_("Incompatible media parameters."); - if (lc->vtable.display_status) - lc->vtable.display_status(lc,msg); - break; - case SalReasonRequestPending: - /*restore previous state, the application will decide to resubmit the action if relevant*/ - call->reason=linphone_reason_from_sal(sr); - linphone_call_set_state(call,call->prevstate,msg); - return; - break; - default: - if (lc->vtable.display_status) - lc->vtable.display_status(lc,_("Call failed.")); - } + msg=_("Incompatible media parameters."); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,msg); + break; + case SalReasonRequestPending: + /*restore previous state, the application will decide to resubmit the action if relevant*/ + linphone_call_set_state(call,call->prevstate,msg); + return; + break; + default: + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Call failed.")); } /*some call error are not fatal*/ @@ -714,8 +708,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de case LinphoneCallPausing: case LinphoneCallResuming: ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate)); - call->reason=linphone_reason_from_sal(sr); - linphone_call_set_state(call, call->prevstate,details); + linphone_call_set_state(call, call->prevstate,ei->full_string); return; default: break; /*nothing to do*/ @@ -728,13 +721,14 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de linphone_call_delete_upnp_session(call); #endif //BUILD_UPNP - call->reason=linphone_reason_from_sal(sr); - if (sr==SalReasonDeclined){ - linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); - }else{ - linphone_call_set_state(call,LinphoneCallError,details); + if (call->state!=LinphoneCallEnd && call->state!=LinphoneCallError){ + if (ei->reason==SalReasonDeclined){ + linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); + }else{ + linphone_call_set_state(call,LinphoneCallError,ei->full_string); + } + if (ei->reason!=SalReasonNone) linphone_core_play_call_error_tone(lc,linphone_reason_from_sal(ei->reason)); } - linphone_core_play_call_error_tone(lc,call->reason); if (referer){ /*notify referer of the failure*/ @@ -773,7 +767,6 @@ static void register_success(SalOp *op, bool_t registered){ ms_message("Registration success for removed proxy config, ignored"); return; } - linphone_proxy_config_set_error(cfg,LinphoneReasonNone); linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared , registered ? "Registration successful" : "Unregistration done"); if (lc->vtable.display_status){ @@ -785,9 +778,11 @@ static void register_success(SalOp *op, bool_t registered){ } -static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){ +static void register_failure(SalOp *op){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); + const SalErrorInfo *ei=sal_op_get_error_info(op); + const char *details=ei->full_string; if (cfg==NULL){ ms_warning("Registration failed for unknown proxy config."); @@ -801,15 +796,12 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const details=_("no response timeout"); if (lc->vtable.display_status) { - char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details ); + char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op), details); lc->vtable.display_status(lc,msg); ms_free(msg); } - linphone_proxy_config_set_error(cfg,linphone_reason_from_sal(reason)); - - if (error== SalErrorFailure - && reason == SalReasonServiceUnavailable + if ((ei->reason == SalReasonServiceUnavailable || ei->reason == SalReasonIOError) && linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) { linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying")); } else { @@ -1031,22 +1023,15 @@ static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus sta return LinphoneChatMessageStateIdle; } -static int op_equals(LinphoneCall *a, SalOp *b) { - return a->op !=b; /*return 0 if equals*/ -} - -static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status, SalReason reason){ +static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op); - const MSList* calls; if (chat_msg == NULL) { // Do not handle delivery status for isComposing messages. return; } - calls = linphone_core_get_calls(chat_msg->chat_room->lc); chat_msg->state=chatStatusSal2Linphone(status); - chat_msg->reason=linphone_reason_from_sal(reason); linphone_chat_message_store_state(chat_msg); if (chat_msg && chat_msg->cb) { ms_message("Notifying text delivery with status %i",chat_msg->state); @@ -1056,11 +1041,6 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status, SalRea } if (status != SalTextDeliveryInProgress) { /*don't release op if progress*/ linphone_chat_message_destroy(chat_msg); - - if (!ms_list_find_custom((MSList*)calls, (MSCompareFunc) op_equals, op)) { - /*op was only create for messaging purpose, destroying*/ - sal_op_release(op); - } } } @@ -1069,7 +1049,7 @@ static void info_received(SalOp *op, const SalBody *body){ linphone_core_notify_info_message(lc,op,body); } -static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason){ +static void subscribe_response(SalOp *op, SalSubscribeStatus status){ LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); if (lev==NULL) return; @@ -1079,7 +1059,6 @@ static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError er }else if (status==SalSubscribePending){ linphone_event_set_state(lev,LinphoneSubscriptionPending); }else{ - linphone_event_set_reason(lev, linphone_reason_from_sal(reason)); linphone_event_set_state(lev,LinphoneSubscriptionError); } } @@ -1121,18 +1100,18 @@ static void subscribe_closed(SalOp *op){ linphone_event_set_state(lev,LinphoneSubscriptionTerminated); } -static void on_publish_response(SalOp* op, SalError err, SalReason reason){ +static void on_publish_response(SalOp* op){ LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + const SalErrorInfo *ei=sal_op_get_error_info(op); if (lev==NULL) return; - if (err==SalErrorNone){ + if (ei->reason==SalReasonNone){ if (!lev->terminating) linphone_event_set_publish_state(lev,LinphonePublishOk); else linphone_event_set_publish_state(lev,LinphonePublishCleared); }else{ - linphone_event_set_reason(lev,linphone_reason_from_sal(reason)); linphone_event_set_publish_state(lev,LinphonePublishError); } } diff --git a/coreapi/chat.c b/coreapi/chat.c index bb944e1cc..264d6d768 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -160,7 +160,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM identity=linphone_proxy_config_get_identity(proxy); }else identity=linphone_core_get_primary_contact(cr->lc); /*sending out of calls*/ - op = sal_op_new(cr->lc->sal); + msg->op = op = sal_op_new(cr->lc->sal); linphone_configure_op(cr->lc,op,cr->peer_url,msg->custom_headers,lp_config_get_int(cr->lc->config,"sip","chat_msg_with_contact",0)); sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/ } @@ -779,6 +779,7 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) * Destroys a LinphoneChatMessage. **/ void linphone_chat_message_destroy(LinphoneChatMessage* msg) { + if (msg->op) sal_op_release(msg->op); if (msg->message) ms_free(msg->message); if (msg->external_body_url) ms_free(msg->external_body_url); if (msg->from) linphone_address_destroy(msg->from); @@ -787,9 +788,17 @@ void linphone_chat_message_destroy(LinphoneChatMessage* msg) { ms_free(msg); } +/** + * Get full details about delivery error of a chat message. + * @param msg a LinphoneChatMessage + * @return a LinphoneErrorInfo describing the details. +**/ +const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg){ + return linphone_error_info_from_sal_op(msg->op); +} LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg) { - return msg->reason; + return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); } /** diff --git a/coreapi/event.c b/coreapi/event.c index 6a7930943..e4d66db3e 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -114,12 +114,12 @@ LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev){ return lev->publish_state; } -void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason){ - lev->reason=reason; +const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev){ + return linphone_error_info_from_sal_op(lev->op); } LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){ - return lev->reason; + return linphone_error_info_get_reason(linphone_event_get_error_info(lev)); } LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){ diff --git a/coreapi/event.h b/coreapi/event.h index e01ab9414..5985d1c96 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -207,6 +207,11 @@ LINPHONE_PUBLIC int linphone_event_update_publish(LinphoneEvent *lev, const Linp **/ LINPHONE_PUBLIC LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev); +/** + * Get full details about an error occured. +**/ +const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev); + /** * Get subscription state. If the event object was not created by a subscription mechanism, #LinphoneSubscriptionNone is returned. **/ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d5c0bdf3c..4ff3537fb 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -793,11 +793,11 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const call->state=cstate; } if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){ - switch(call->reason){ - case LinphoneReasonDeclined: + switch(call->non_op_error.reason){ + case SalReasonDeclined: call->log->status=LinphoneCallDeclined; break; - case LinphoneReasonNotAnswered: + case SalReasonRequestTimeout: call->log->status=LinphoneCallMissed; break; default: @@ -814,6 +814,11 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const lc->vtable.call_state_changed(lc,call,cstate,message); if (cstate==LinphoneCallReleased){ 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); + } /* so that we cannot have anymore upcalls for SAL concerning this call*/ sal_op_release(call->op); @@ -877,6 +882,7 @@ static void linphone_call_destroy(LinphoneCall *obj) } linphone_call_params_uninit(&obj->params); linphone_call_params_uninit(&obj->current_params); + sal_error_info_reset(&obj->non_op_error); ms_free(obj); } @@ -998,7 +1004,16 @@ LinphoneCallState linphone_call_get_state(const LinphoneCall *call){ * Returns the reason for a call termination (either error or normal termination) **/ LinphoneReason linphone_call_get_reason(const LinphoneCall *call){ - return call->reason; + return linphone_error_info_get_reason(linphone_call_get_error_info(call)); +} + +/** + * Returns full details about call errors or termination reasons. +**/ +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); } /** diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 38093e7c8..9cd36d0fd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2281,7 +2281,7 @@ void linphone_core_iterate(LinphoneCore *lc){ ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout); decline_reason=lc->current_call ? LinphoneReasonBusy : LinphoneReasonDeclined; call->log->status=LinphoneCallMissed; - call->reason=LinphoneReasonNotAnswered; + sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,408,"Not answered",NULL); linphone_core_decline_call(lc,call,decline_reason); } } @@ -3470,8 +3470,8 @@ int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *e static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ if (call->state==LinphoneCallIncomingReceived){ - if (call->reason!=LinphoneReasonNotAnswered) - call->reason=LinphoneReasonDeclined; + if (call->non_op_error.reason!=SalReasonRequestTimeout) + call->non_op_error.reason=SalReasonDeclined; } /*stop ringing*/ linphone_core_stop_ringing(lc); @@ -3490,7 +3490,7 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri){ if (call->state==LinphoneCallIncomingReceived){ sal_call_decline(call->op,SalReasonRedirect,redirect_uri); - call->reason=LinphoneReasonDeclined; + sal_error_info_set(&call->non_op_error,SalReasonRedirect,603,"Call redirected",NULL); terminate_call(lc,call); }else{ ms_error("Bad state for call redirection."); @@ -6152,6 +6152,8 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "Bad gateway"; case LinphoneReasonServerTimeout: return "Server timeout"; + case LinphoneReasonUnknown: + return "Unknown error"; } return "unknown error"; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 2af2d54de..f2d4b2514 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -159,6 +159,7 @@ typedef struct _LinphoneCall LinphoneCall; * Enum describing various failure reasons or contextual information for some events. * @see linphone_call_get_reason() * @see linphone_proxy_config_get_error() + * @see linphone_error_info_get_reason() * @ingroup misc **/ enum _LinphoneReason{ @@ -181,7 +182,8 @@ enum _LinphoneReason{ LinphoneReasonAddressIncomplete, /**
reason); +} + +/** + * Get textual phrase from the error info. + * This is the text that is provided by the peer in the protocol (SIP). + * @param ei the error info. + * @return the error phrase + * @ingroup misc +**/ +const char *linphone_error_info_get_phrase(const LinphoneErrorInfo *ei){ + const SalErrorInfo *sei=(const SalErrorInfo*)ei; + return sei->status_string; +} + +/** + * Provides additional information regarding the failure. + * With SIP protocol, the "Reason" and "Warning" headers are returned. + * @param ei the error info. + * @return more details about the failure. + * @ingroup misc +**/ +const char *linphone_error_info_get_details(const LinphoneErrorInfo *ei){ + const SalErrorInfo *sei=(const SalErrorInfo*)ei; + return sei->warnings; +} + +/** + * Get the status code from the low level protocol (ex a SIP status code). + * @param ei the error info. + * @return the status code. + * @ingroup misc +**/ +int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei){ + const SalErrorInfo *sei=(const SalErrorInfo*)ei; + return sei->protocol_code; +} + /** * Set the name of the mediastreamer2 filter to be used for rendering video. * This is for advanced users of the library, mainly to workaround hardware/driver bugs. diff --git a/coreapi/private.h b/coreapi/private.h index 9e8d0af0f..18de67587 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -146,7 +146,7 @@ struct _LinphoneChatMessage { LinphoneChatMessageState state; bool_t is_read; unsigned int storage_id; - LinphoneReason reason; + SalOp *op; }; typedef struct StunCandidate{ @@ -159,6 +159,7 @@ struct _LinphoneCall { int magic; /*used to distinguish from proxy config*/ struct _LinphoneCore *core; + SalErrorInfo non_op_error; 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*/ @@ -174,7 +175,6 @@ struct _LinphoneCall LinphoneCallState state; LinphoneCallState prevstate; LinphoneCallState transfer_state; /*idle if no transfer*/ - LinphoneReason reason; LinphoneProxyConfig *dest_proxy; int refcnt; void * user_pointer; @@ -204,7 +204,7 @@ struct _LinphoneCall unsigned int remote_session_ver; LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */ - int localdesc_changed; + int localdesc_changed;/*not a boolean, contains a mask representing changes*/ bool_t refer_pending; bool_t expect_media_in_ack; @@ -373,7 +373,6 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md); extern SalCallbacks linphone_sal_callbacks; -void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg, LinphoneReason error); bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LinphoneCall * is_a_linphone_call(void *user_pointer); @@ -413,7 +412,6 @@ struct _LinphoneProxyConfig bool_t pad[3]; void* user_data; time_t deletion_date; - LinphoneReason error; LinphonePrivacyMask privacy; }; @@ -693,7 +691,6 @@ struct _LinphoneEvent{ SalCustomHeader *send_custom_headers; LinphoneSubscriptionState subscription_state; LinphonePublishState publish_state; - LinphoneReason reason; void *userdata; int refcnt; char *name; @@ -806,7 +803,6 @@ LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name); void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state); void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state); -void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason); LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss); const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref); void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); @@ -847,6 +843,10 @@ char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char * void linphone_free_xml_text_content(const char *text); xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression); +static 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); +} /** Belle Sip-based objects need unique ids */ diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 5e0b8ff18..74c8a7730 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1368,11 +1368,11 @@ LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyCon } LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg) { - return cfg->error; + return linphone_error_info_get_reason(linphone_proxy_config_get_error_info(cfg)); } -void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneReason error) { - cfg->error = error; +const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProxyConfig *cfg){ + return linphone_error_info_from_sal_op(cfg->op); } const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg) { diff --git a/include/sal/sal.h b/include/sal/sal.h index 650b5085a..f508484ec 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -254,6 +254,7 @@ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type); void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir); + /*this structure must be at the first byte of the SalOp structure defined by implementors*/ typedef struct SalOpBase{ Sal *root; @@ -279,15 +280,8 @@ typedef struct SalOpBase{ } SalOpBase; -typedef enum SalError{ - SalErrorNone, - SalErrorNoResponse, - SalErrorProtocol, - SalErrorFailure, /* see SalReason for more details */ - SalErrorUnknown -} SalError; - typedef enum SalReason{ + SalReasonNone, /*no error, please leave first so that it takes 0 value*/ SalReasonDeclined, SalReasonBusy, SalReasonRedirect, @@ -308,11 +302,20 @@ typedef enum SalReason{ SalReasonAddressIncomplete, SalReasonNotImplemented, SalReasonBadGateway, - SalReasonServerTimeout + SalReasonServerTimeout, + SalReasonIOError }SalReason; const char* sal_reason_to_string(const SalReason reason); +typedef struct SalErrorInfo{ + SalReason reason; + char *status_string; + int protocol_code; + char *warnings; + char *full_string; /*concatenation of status_string + warnings*/ +}SalErrorInfo; + typedef enum SalPresenceStatus{ SalPresenceOffline, SalPresenceOnline, @@ -400,21 +403,21 @@ typedef void (*SalOnCallAccepted)(SalOp *op); typedef void (*SalOnCallAck)(SalOp *op); typedef void (*SalOnCallUpdating)(SalOp *op);/*< Called when a reINVITE/UPDATE is received*/ typedef void (*SalOnCallTerminated)(SalOp *op, const char *from); -typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code); +typedef void (*SalOnCallFailure)(SalOp *op); typedef void (*SalOnCallReleased)(SalOp *salop); typedef void (*SalOnAuthRequestedLegacy)(SalOp *op, const char *realm, const char *username); typedef bool_t (*SalOnAuthRequested)(Sal *sal,SalAuthInfo* info); typedef void (*SalOnAuthFailure)(SalOp *op, SalAuthInfo* info); typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered); -typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason, const char *details); +typedef void (*SalOnRegisterFailure)(SalOp *op); typedef void (*SalOnVfuRequest)(SalOp *op); typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf); typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto); typedef void (*SalOnTextReceived)(SalOp *op, const SalMessage *msg); -typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus, SalReason); +typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus); typedef void (*SalOnIsComposingReceived)(SalOp *op, const SalIsComposing *is_composing); typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state); -typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason); +typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status); typedef void (*SalOnNotify)(SalOp *op, SalSubscribeStatus status, const char *event, const SalBody *body); typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *event, const SalBody *body); typedef void (*SalOnSubscribeClosed)(SalOp *salop); @@ -425,7 +428,7 @@ typedef void (*SalOnSubscribePresenceReceived)(SalOp *salop, const char *from); typedef void (*SalOnSubscribePresenceClosed)(SalOp *salop, const char *from); typedef void (*SalOnPingReply)(SalOp *salop); typedef void (*SalOnInfoReceived)(SalOp *salop, const SalBody *body); -typedef void (*SalOnPublishResponse)(SalOp *salop, SalError error, SalReason reason); +typedef void (*SalOnPublishResponse)(SalOp *salop); typedef void (*SalOnExpire)(SalOp *salop); /*allows sal implementation to access auth info if available, return TRUE if found*/ @@ -577,6 +580,11 @@ bool_t sal_op_is_ipv6(SalOp *op); /*returns TRUE if there is no pending request that may block a future one */ bool_t sal_op_is_idle(SalOp *op); +const SalErrorInfo *sal_error_info_none(void); +const SalErrorInfo *sal_op_get_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); + /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); int sal_call(SalOp *h, const char *from, const char *to); diff --git a/tester/call_tester.c b/tester/call_tester.c index 515c7980e..ed44faa9e 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -914,7 +914,7 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); linphone_core_set_play_file(laure->lc,hellopath); if (enable_caller_privacy) - linphone_call_params_set_privacy(laure_params,LinphonePrivacyId); + linphone_call_params_set_privacy(laure_params,LinphonePrivacyId); CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(laure->lc,pauline->identity,laure_params)); @@ -1185,7 +1185,7 @@ static void early_media_call_with_ringing(void){ marie_call = linphone_core_invite_address(marie->lc, pauline->identity); - CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging,1,1000));