Reason Header support

Last modified by SandrineAvakian on 2017/04/26 14:37

Introduction

This page describes the liblinphone API implementation to support the reason header usage as defined in  the   RFC3326 The Reason Header Field for the Session Initiation Protocol (SIP).

Reason header description

The reason header is defined as follows: 

Reason: SIP ;cause=200 ;text="Call completed elsewhere"

It is composed of :

  • A reason, which is the name of the protocol used
  • A cause, the protocol's code
  • A sentence, giving more details on  the error 

Sometimes,  the reason header is included in a response to give more information about the error cause : 

SIP /2.0 480 Temporarily unavailable

Reason: Q.850; cause=18; text= "no user responding"

Reason header implementation

In order to describe and use the reason header appropriately, some structures and associated functions have been implemented in linphone submodule's following files:

  • linphone/call.h  and  call.c
  • linphone/error_info.h and error_info.c
  • linphone/factory.h and factory.c
  • linphone/misc.h

LinphoneReason

The LinphoneReason is an enum defined in linphone/types.h describing the errors defined below. This facilitates the creation of a LinphoneErrorInfo object if the reason is one of the following errors:

LinphoneReasonNone,
LinphoneReasonNoResponse,
LinphoneReasonForbidden,
LinphoneReasonDeclined,
LinphoneReasonNotFound,
LinphoneReasonNotAnswered,
LinphoneReasonBusy,
LinphoneReasonUnsupportedContent,
LinphoneReasonIOError,
LinphoneReasonDoNotDisturb,
LinphoneReasonUnauthorized,
LinphoneReasonNotAcceptable,
LinphoneReasonNoMatch,
LinphoneReasonMovedPermanently
LinphoneReasonGone,
LinphoneReasonTemporarilyUnavailable,
LinphoneReasonAddressIncomplete,
LinphoneReasonNotImplemented,
LinphoneReasonBadGateway,
LinphoneReasonServerTimeout,
LinphoneReasonUnknown
Throughout this document, we will call a frequent error or usual error , an error that is already defined by this enum and whose value is different from the LinphoneReasonUnknown value.     

Internally, the mapping of these errors with the associated protocol code error_code_reason_map_t error_code_reason_map, and the mapping with the associated description sentence const char *linphone_reason_to_string(LinphoneReason err) enables the functions const char *linphone_reason_to_string(LinphoneReason err), and int linphone_reason_to_error_code(LinphoneReason reason) respectively to find the error explanation sentence and the error protocol code based on the LinphoneReason enumerated above.

On the other hand, the function LinphoneReason linphone_error_code_to_reason(int err) returns the LinphoneReason based on the protocol error code, if this error is a frequent error.

The LinphoneErrorInfo structure

It is based on the  struct _LinphoneErrorInfo which contains the following fields :
belle_sip_object_t base;
Every objects inherit from belle_sip_object_t to allow memory usage tracking.  It is used by linphone_error_info_ref and linphone_error_info_unref.

LinphoneReason reason;
An error and reason enum of the most frequent errors for the SIP protocol. To specify a reason different from the predefined ones, this field must be set to LinphoneReasonUnknown.

char *protocol;
the procotol name used, usually SIP.

protocol_code;
the error code associated. This can be easily inferred from the LinphoneReason, provided that it is not LinphoneReasonUnknown nor an unusual error, using a call to linphone_reason_to_error_code.

char *phrase;
The error text describing it. If it is a frequent error, it has already been defined : as a consequence, it can be easily retrieved with linphone_reason_to_string.

char *warnings;
The warning header fied as defined by the RFC3261, if it exists. This is not a mandatory field and can be set to NULL.

char *full_string;
This holds the concatenation of all the reason header information available in order to make a valid reason header.  This field is used internally and is not supposed to be used elsewhere. 

struct _LinphoneErrorInfo *sub_ei
A pointer to another LinphoneErrorInfo structure it there is several errors to notify in one message. There is usually at most 2 errors notified. Unless it is explicitely given another value with a call to inphone_error_info_set_sub_error_info, this field is set to NULL by linphone_error_info_set. 

Usage

Instantiate, set and free

In order to terminate or decline a call with a reason header, a LinphoneErrorInfo object has to be instanciated and all the necessary fields must be defined beforehand. The memory used by this object must be freed when the object is no longer used. 

  • To instanciate a  LinphoneErrorInfo object [Recommended] :  LinphoneErrorInfo *linphone_factory_create_error_info(LinphoneFactory *factory)
  • To defined all the fields of a LinphoneErrorInfo object (except the pointer sub_ei):  void linphone_error_info_set(LinphoneErrorInfo *ei, const char *protocol, LinphoneReason reason, int code, const char *status_string, const char *warning);  Before defining the appropriate fields, this functions sets to NULL all the structure's pointers. 
  • To define another linked LinphoneErrorInfo (LinphoneErrorInfo *sub_ei) void linphone_error_info_set_sub_error_info(LinphoneErrorInfo *ei, LinphoneErrorInfo *appended_ei);
  • To free the allocated memiory : void linphone_error_info_unref(LinphoneErrorInfo *ei);

Get

To get the fields'value of a LinphoneErrorInfo object, the following getters have been implemented :

  • Returns the reason  : LinphoneReason linphone_error_info_get_reason(const LinphoneErrorInfo *ei)
  • Returns the pointer to the other LinphoneErrorInfo associated with the object:  LinphoneErrorInfo* linphone_error_info_get_sub_error_info(const LinphoneErrorInfo *ei)
  • Returns the pointer on the error text :  const char * linphone_error_info_get_phrase(const LinphoneErrorInfo *ei)
  • Returns the pointer on the protocol name : const char *linphone_error_info_get_protocol(const LinphoneErrorInfo *ei)
  • Returns the pointer on the warning header: const char * linphone_error_info_get_warnings(const LinphoneErrorInfo *ei)
  • Returns the protocol code value :  int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei)

Decline or terminate a call

In order to use a reason header, a LinphoneErrorInfo object has to be instanciated with a call to linphone_factory_create_error_info and the fields  must be defined with linphone_error_info_set. The warning pointer can be set to NULL if not used.

With the LinphoneErrorInfo object then created, a call can be :

  • declined with int linphone_call_decline_with_error_info(LinphoneCall * call, const LinphoneErrorInfo *ei); 

The LinphoneErrorInfo ei is then mapped to the SIP response code and status phrase. In order to specify a Reason header in the response, the LinphoneErrorInfo must contain a "sub" error info object describing the Reason header content (set by linphone_error_info_set_sub_error_info()).

  • terminated with int linphone_call_terminate_with_error_info(LinphoneCall * call, const LinphoneErrorInfo *ei);

For each LinphoneErrorInfo created, a call to oid linphone_error_info_unref(LinphoneErrorInfo *ei) allows to free the allocated memory.  

Determining the causes of an ended call

The function const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call) returns a pointer on the reason header of call which allows to get the error information on a call declined or terminated. If an outgoing call is declined by the remote party, and the decline response contains a Reason header, a sub LinphoneErrorInfo will be attached to the returned LinphoneErrorInfo.

If knowing the cause is enough, and the other fields are not needed, one can simply use : LinphoneReason linphone_call_get_reason(const LinphoneCall *call).

API functions list

linphone/call.h

Declining and terminating a call
LINPHONE_PUBLIC int linphone_call_decline_with_error_info(LinphoneCall * call, const LinphoneErrorInfo *ei);
LINPHONE_PUBLIC int linphone_call_terminate_with_error_info(LinphoneCall *call, const LinphoneErrorInfo *ei);

Getting information on the reason header though a LinphoneCall
LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call);
LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call);

linphone/error_info.h

Mananging the creation and deletion of  LinphoneErrorInfo
LINPHONE_PUBLIC LinphoneErrorInfo *linphone_error_info_new(void);
LINPHONE_PUBLIC LinphoneErrorInfo *linphone_error_info_ref(LinphoneErrorInfo *ei);
LINPHONE_PUBLIC void linphone_error_info_unref(LinphoneErrorInfo *ei);

Getters on LinphoneErrorInfo
LINPHONE_PUBLIC LinphoneReason linphone_error_info_get_reason(const LinphoneErrorInfo *ei);
LINPHONE_PUBLIC LinphoneErrorInfo* linphone_error_info_get_sub(const LinphoneErrorInfo *ei);
LINPHONE_PUBLIC const char * linphone_error_info_get_phrase(const LinphoneErrorInfo *ei);    
LINPHONE_PUBLIC const char *linphone_error_info_get_protocol(const LinphoneErrorInfo *ei);
LINPHONE_PUBLIC const char * linphone_error_info_get_warnings(const LinphoneErrorInfo *ei);
LINPHONE_PUBLIC int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei);

Setters sur un LinphoneErrorInfo
LINPHONE_PUBLIC void linphone_error_info_set(LinphoneErrorInfo *ei, const char *protocol, LinphoneReason reason, int code, const char *status_string, const char *warning);    
LINPHONE_PUBLIC void linphone_error_info_set_sub_error_info(LinphoneErrorInfo *ei, LinphoneErrorInfo *appended_ei);
LINPHONE_PUBLIC void linphone_error_info_set_reason(LinphoneErrorInfo *ei, LinphoneReason reason);

linphone/factory.h

Creation of a LinphoneErrorInfo [Recommended]
LINPHONE_PUBLIC  LinphoneErrorInfo *linphone_factory_create_error_info(LinphoneFactory *factory);

linphone/misc.h

Transformations on usual errors:
LINPHONE_PUBLIC const char *linphone_reason_to_string(LinphoneReason err);
LINPHONE_PUBLIC int linphone_reason_to_error_code(LinphoneReason reason);
LINPHONE_PUBLIC LinphoneReason linphone_error_code_to_reason(int err);

Created by SandrineAvakian on 2017/04/19 14:47