Introduction to Osip protocol stack (Continued 1: Pure protocol stack logic analysis)

Source: Internet
Author: User

A long time ago, I took a rough look at Osip, exosip, ortp and quickly "encapsulate" a Windows-based vc6-based mfc sip Soft Phone (all source code vc6 project files and Lib libraries can be found in this blog shared folder ), due to time constraints, I can only analyze the code of Osip, exosip, and other development libraries in a pure "application" manner. As a matter of interest, I can refer to the working principles of the SIP Phone, but as a reference for commercial product development, it is still too simple :)
Recently, the SIP function module (based on Osip) has been extended on the embedded Linux platform. Because the Osip used does not include call transfer related fields (refer, policy, etc) resolution and state machine control (whether the latest Osip version has been extended and not checked) cannot support call forwarding and must be manually extended, I have the opportunity to have a better understanding of the main transaction state machines and database parsing of Osip. I will share the following with the summary of the SIP RFC.
(Note: The following assumes that the reader has a general understanding of the simple call process of the SIP protocol, and will use ethereal and other packet capture tools to analyze the SIP Message structure, have a good understanding of the concepts of C pointers, linked lists, memory control, and state machines .)

To apply Osip to our program, we should first look at the official documentation, which gives a detailed description of how to use the various functional components provided by The oSIP protocol stack, however, no comprehensive analysis is conducted, and some Chinese guidance documents are still being translated. It cannot be used for quick reference by users who are not familiar with the protocol stack, this document does not describe the Osip code in parts by function, but analyzes the main logical flow according to the code usage sequence in actual use, the functional components used in the process are described as appropriate. For more detailed functional instructions or questions, you can directly view the explanations in the corresponding part of the official documentation or directly view the functional function source code.

  • Preparations
    First, we should know several structs: osip_t, osip_message_t, osip_dialog_t, osip_transaction_t;
    Osip_t is a global variable, all programs that need to use the transaction processing capability of The oSIP protocol stack need to initialize it in the first step (relative to applications that only use the osipparser library for SIP Message Field parsing, if you only use the parser library to your own program, you must be familiar with the SIP protocol stack and do not need to read it again. ^_^ ), it mainly defines four major transaction linked lists of The oSIP protocol stack, the actual sending function of the message, and the callback function under each State event of the state machine;
    Osip_message_t is the C language structure storage space of the SIP message. After receiving the resolution of the SIP message, it exists in this structure so that the program can use the specified field in the received message, before sending a message, set the value of the field to be sent. The content to be sent will be converted to a string when the structure is medium;
    Osip_dialog_t is the definition of dialog in the sip rfc or call leg. It identifies the relationship between UAC and UAS and keeps the session end, A complete dialog consists of from, to, callid, fromtag, totag, and State (source code can be viewed). fromtag, totag, and callid are complete only after a dialog is created successfully, it is reflected in the SIP message, that is, the tag of from and to, and the value of the call-Id field are the same. These messages belong to a corresponding dialog. For example, when an invite is to be initiated, only fromtag and callid are filled with values. When a remote response is received, totag is received and filled into dialog. A dialog is created successfully, the subsequent logic is to use this dialog for processing (such as transaction processing). State indicates the status of the current dialog, which is closely related to the state of transaction, the sharing is defined by the enum structure state_t;
    Osip_transaction_t is the definition of the transaction in RFC, it represents a message sending and its complete response between a dialog of a session, such as invite-100-180-200-ack is a complete transaction, bye-200 is also a complete transaction. It is reflected in the SIP message, that is, the same branch value in Via indicates that the message belongs to a transaction (of course, the transaction is in the dialog, therefore, the from and to tags and call-ID values are the same.) transactions have different terminal types and messages for UAC and UAS, which are divided into four categories, the invite transactions mentioned above will be associated with an ICT transaction in the UAC, And the called UAS will be associated with an ist transaction. Besides invite, they are classified and defined as NICT and NIST, in Osip, it relies on finite state machines to implement the above four transactions (defined in osip_fsm_type_t). Its main attribute values include callid and transactionid to identify dialog and transaction, respectively, there is also a timestamp birth_time that identifies the transaction creation time. The timeout processing function can be used to determine and determine the transaction to be executed and destroyed in the case of timeout, and its state attribute is very important, the values vary according to the above transaction types. It is the "State" of the state machine mentioned above and is a key value in the logical execution of the actual state machine;
  • Osip Initialization
    When it comes to Osip initialization, you may have read the code on the first page in the official document. First, osip_init (& Osip) initializes the global osip_t struct and then sets its callback function, many people think that the call_back setting on this dense page is scared. However, based on the meaning of the three structures analyzed above, the meaning here is very clear:
    Osip_t hasCb_send_messageFunction pointer, which is the interface that Osip finally interacts with the external network. Its parameters include (osip_transaction_t * TRN,/* transaction of the Message */
    Osip_message_t * sipmsg,/* message structure to be sent */
    Char * dest_socket_str,/* target address */
    Int32_t dest_port,/* Target Port */
    Int32_t send_sock)/* socket used to send messages */
    TRN is passed in to obtain the context data of the transaction. It has a void pointer your_instance, which can be used to pass in more data for reference when sending messages, for example, input the dialog pointer of the firm;
    Sipmsg is the C structure of the SIP message to be sent. It is converted to a string in RFC format using osip_message_to_str (the main function of the parser module in Osip ), use send_sock to send data to the target specified by dest_socket_str and dest_port through any network data sending function. Of course, remember to use osip_free to release the memory occupied by the sent string, in Osip, many message parsing and processing functions provided by osipparser are dynamically allocated in memory and need to be released in time after use;
    When the callback function is successfully set using osip_set_cb_send_message, our SIP Message has been exported, and the following analysis continues (of course, you can also manually specify the above process ).

    The following callback functions are divided into three types: Processing callback functions and transaction destruction events for common transaction messages (defined in osip_message_callback_type_t) (defined in osip_kill_callback_type_t) the cleanup callback function and the error events during transaction execution (defined in osip_transport_error_callback_type_t:
    To put it simple, the transaction destruction event, the normal completion of the transaction (successful completion of the state machine process) or the forced termination of the timeout processing function call these callback functions, which are generally called to release the transaction structure, for ICT, NICT, ist, and NIST, you can set or share a callback function, as long as the memory that is no longer in use is correctly released;
    The error handling function is the exit of any errors that occur during the execution of the state machine. It is generally used to install the log function for debugging and can be directly set as an empty function;
    The most important thing is the processing callback function for normal messages. The number of callback functions is very large. However, the callback function is divided into four categories, just like the callback function above, we can set it based on actual program needs. For example, the SIP Phone does not need to process the register message events that need to be processed only by the SIP registration server osip_nist_register_received, if you only want to create a demo soft-phone program that only implements the calling function and does not consider the error, you only need to set the callback functions for the following events:
    Osip_ict_invite_sent sends invite start call
    Osip_ict_status_1xx_received receives 180
    Osip_ict_status_2xx_received received 200
    Osip_ict_ack_sent sends an ACK confirmation call
    Osip_nict_bye_sent sends a bye end call
    Osip_nict_status_2xx_received receives the 200 confirm end call
    Osip_nist_bye_received receives the bye end call.
    Osip_nist_status_2xx_sent sends a 200 confirm end call
    To add the called UAS function for receiving calls, you only need to add the following events:
    Osip_ist_invite_received receives the invite start call
    Osip_ist_status_1xx_sent issue 180
    Osip_ist_status_2xx_sent issue 200
    Osip_ist_ack_received receives an ACK confirmation call.
    For specific function definitions, see osip_message_cb_t, osip_kill_transaction_cb_t, callback. You can set the callback function manually or use the osip_set_xxx_callback function provided by Osip;

  • Send SIP messages
      
    To send a SIP message, we can see from the above analysis that there are several necessary conditions: the message to be sent in the osip_messag_t structure, the dialog of the osip_dialog_t structure, and the transaction of osip_transaction_t;
    First, osip_malloc allocates a new dialog, and uses parser functions such as osip_to_init, osip_to_parse, and osip_to_free to set call-ID, from, to, local_cseq and other necessary fields according to RFC (principles: you need to set the fields used to generate the actual SIP Message struct later.) Use osip_message_init to initialize a sipmsg and fill the struct according to the dip_( the data filled by different messages is different, there is no shortcut. You can only enter fields based on RFC.) to add a body such as SDP segment to a SIP Message, use the osip_message_set_body and osip_message_set_content_type functions. The set value is plain text, for SDP, Osip provides simple parsing and convenient functions to generate, such as sdp_message_to_str, sdp_message_a_attribute_add, but only For simple character operations, to fill in valid fields, you need to refer to the RFC document of SDP. There is no shortcut.
    Now we have two necessary conditions, and the last and most critical component is the creation and triggering of transactions,
    Int osip_transaction_init (
    Osip_transaction_t ** transaction,/* returned transaction structure pointer */
    Osip_fsm_type_t ctx_type,/* transaction type ICT/NICT/IST/NIST */
    Osip_t * Osip,/* global variable mentioned above */
    Osip_message_t * request)/* the previously generated sipmsg */
    A new transaction is created and automatically initialized Based on the transaction type, dialog, and sipmsg. Most importantly, it uses functions such as _ osip_add_ict, insert this transaction into the global FIFO linked list of the global osip_t struct. Different transaction types correspond to different FIFO lists. As we can see from the previous article, there are four functions and four FIFO functions, corresponding to ICT, NICT, ist, NIST. Note that osip_transaction_set_out_socket is used to allocate the socket interface for sending the SIP message to this transaction, it is convenient to automatically call the previously set message sending callback function to use it to automatically send messages;
    As mentioned above, the state in transaction is used as the "State" of the state machine. To execute the state machine, an "Event" is required for triggering. The event structure osip_event_t needs to use osip_new_outgoing_sipmessage to detect and generate sipmsg, setting the correct event value does not require manual setup. It calls evt_set_type_outgoing_sipmessage to set the "event" type_t and mounts sipmsg to the SIP attribute value of the event struct, use osip_incluo_add (TRN-> transactionff,
    Ev) inserts the event into the event FIFO of the transaction, that is, the transactionff attribute;
      
    With the necessary conditions for sending the message above, how does the message actually start? As mentioned above, sending and responding to a SIP message is a transaction and cannot be isolated. That is, sending a message requires the control of the transaction state machine. We have set the state and event of the state machine above, to trigger it, you need to execute the state machine:
    Osip_ict_execute
    Osip_nict_execute
    Osip_ist_execute
    Osip_nist_execute
    It is used to traverse the four transactions mentioned above in FIFO, fetch the transactions, and then extract the events in the first FIFO of the transactions in sequence, and execute the tasks in sequence using osip_transaction_execute (if you are interested, you can go further to view them, we can see that it finally calls the message callback function we set up earlier. As for the specific call, this is a lot of work done internally by the Osip protocol stack. ^_^ );
    What if a transaction cannot be terminated normally? For example, if an invite is sent and no response is received, as defined in RFC, different transactions have different time-out periods, osip_timers_ict [NICT | ist | NIST] _ execute these functions are used to compare the acquired transaction timestamp with the specified Timeout time based on the difference between the current Timestamp and the specified Timeout time, the timeout "Event" is automatically set and the "State" of the transaction is set to the end. You can use the previously set message timeout Event Callback Function to process the transaction (if set );
    If the network quality is unstable and messages are often lost, use the osip_retransmissions_execute function to automatically resend messages instead of waiting for timeout;
    In order to instantly respond to the processing of the SIP message and promote the state machine, the preceding nine functions need to be executed continuously and can be put into a separate thread.
  • Receive SIP Message
      
    With the previous understanding of sending a SIP message, the processing of the received message is easy to understand. After receiving the SIP Message, use osip_parse for parsing to obtain a sipmsg of osip_message_t, use evt_set_type_incoming_sipmessage to get the "event" of the transaction, and mount sipmsg to the SIP field of the event struct as above. Then, use osip_find_transaction_and_add_event to locate the transaction based on the "event, transaction search is performed by using branch in the SIP Message via). Otherwise, a new transaction is created and the state machine is promoted for execution.
  • Internal logic of the state machine
    After figuring out the general logic of the above state machine and setting correct and complete callback functions, you can use Osip to perform work correctly. If you want to further explore Osip, for example, to extend the Osip state machine to process custom message fields and implement new transaction logic to generate new services, you need to have a certain understanding of the internal logic of the state machine;
    It has been repeatedly stressed that there are several important data structures in Osip: osip_message_t, osip_dialog_t, and osip_transaction_t. Users are mainly oriented to the first and second data structures, the dialog in the middle is often used inside the state machine. For example, when a message is received and parsed to sipmsg, the transaction is searched and driven, then find the associated Dialog (or newly generated) parsing to fill in the message structure sipmsg to be sent, and then find or generate transaction based on the dialog and sipmsg.
    To expand Osip, you need to do the following:
    Expand osip_message_t, add the field or message header to be parsed, and generate the corresponding sip string generation and resolution function according to the original Osip function;
    Extended osip_dialog_t, added new attributes, corresponding to the added content of osip_message_t;
    Extend the event and State types of the state machine, set the corresponding callback function, and associate the newly added event and State types with the parsing function of osip_message_t or the initialization function of osip_dialog_t, osip_transaction_t does not need to be extended most of the time, as long as it is in the processing logic of the corresponding transaction type (most of the time it is NICT, NIST, you can add a new event and status type judgment and call the callback function logic.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.