2020国产成人精品视频,性做久久久久久久久,亚洲国产成人久久综合一区,亚洲影院天堂中文av色

分享

exosip,osip 學(xué)習(xí)篇(一)

 semo_zhang 2012-12-21

    最近簡(jiǎn)單粗略地看了下Osip,eXosip,ortp等要應(yīng)用Osip到我們的程序中去,首先要看官方文檔,文檔中對(duì)Osip協(xié)議棧提供的各個(gè)功能部件如何使用都有比較詳細(xì)的描述,但未進(jìn)行整體性的分析,某些中文的指導(dǎo)文檔也都停留在對(duì)其簡(jiǎn)單的翻譯,不能為不熟悉該協(xié)議棧使用的用戶(hù)快速參考使用,本文檔不按照Osip的代碼進(jìn)行按功能分塊說(shuō)明,而是根據(jù)實(shí)際使用時(shí)的代碼使用順序來(lái)對(duì)主要邏輯流程進(jìn)行分析,并適當(dāng)對(duì)流程中使用到的功能部件進(jìn)行說(shuō)明,具體更詳細(xì)的功能說(shuō)明或疑問(wèn)可直接查看官方文檔對(duì)應(yīng)部分的解釋或直接查看功能函數(shù)源代碼即可解決。

第一步:了解exosip ,osip中一些基本知識(shí) 
    先認(rèn)識(shí)幾個(gè)結(jié)構(gòu)體:osip_t,osip_message_t,osip_dialog_t,osip_transaction_t;
  osip_t是一個(gè)全局變量,所有要使用Osip協(xié)議棧的事務(wù)處理能力的程序都要第一步就初始化它(相對(duì)應(yīng)于只使用osipparser庫(kù)進(jìn)行SIP消息字段解析的應(yīng)用來(lái)說(shuō),如果只使用parser庫(kù)到自己的程序中,想必對(duì)SIP協(xié)議棧已經(jīng)很熟悉了,不需再往下看了^_^),它內(nèi)部主要是定義了Osip 協(xié)議棧的四個(gè)主要事務(wù)鏈表、消息實(shí)際發(fā)送函數(shù)及狀態(tài)機(jī)各狀態(tài)事件下的回調(diào)函數(shù)等;

在程序中osip_t被定義為:  struct osip
  {

    void *application_context;  /**< User defined Pointer */

    /* list of transactions for ict, ist, nict, nist */
    osip_list_t osip_ict_transactions;   /**< list of ict transactions */
    osip_list_t osip_ist_transactions;   /**< list of ist transactions */
    osip_list_t osip_nict_transactions;  /**< list of nict transactions */
    osip_list_t osip_nist_transactions;  /**< list of nist transactions */

    osip_list_t ixt_retransmissions;    /**< list of ixt elements */

    osip_message_cb_t msg_callbacks[OSIP_MESSAGE_CALLBACK_COUNT];        /**@internal */
    osip_kill_transaction_cb_t kill_callbacks[OSIP_KILL_CALLBACK_COUNT];
/**@internal */
    osip_transport_error_cb_t tp_error_callbacks[OSIP_TRANSPORT_ERROR_CALLBACK_COUNT]; 
/**@internal */

    int (*cb_send_message) (osip_transaction_t *, osip_message_t *, char *,
                            int, int);
                                       
/**@internal */

#if defined(HAVE_DICT_DICT_H)
    dict *osip_ict_hastable;              /**< htable of ict transactions */
    dict *osip_ist_hastable;              /**< htable of ist transactions */
    dict *osip_nict_hastable;             /**< htable of nict transactions */
    dict *osip_nist_hastable;             /**< htable of nist transactions */
#endif
  };

typedef struct osip osip_t;


  osip_message_t是SIP消息的C語(yǔ)言結(jié)構(gòu)體存儲(chǔ)空間,收到SIP消息解析后存在該結(jié)構(gòu)中方便程序使用接收到的消息中的指定的字段,發(fā)送消息前為方便設(shè)置要發(fā)送的字段值,將要發(fā)送的內(nèi)容存在該結(jié)構(gòu)中等發(fā)送時(shí)轉(zhuǎn)為字符串;在該文檔中提供了大量的API來(lái)對(duì)消息進(jìn)行處理。
該結(jié)構(gòu)體如下定義:
  typedef struct sdp_message sdp_message_t;
/**
 * SDP message definition.
 * @struct sdp_message
 */
  struct sdp_message
  {
    char *v_version;            /**< version header */
    char *o_username;           /**< Username */
    char *o_sess_id;            /**< Identifier for session */
    char *o_sess_version;       /**< Version of session */
    char *o_nettype;            /**< Network type */
    char *o_addrtype;           /**< Address type */
    char *o_addr;               /**< Address */
    char *s_name;               /**< Subject header */
    char *i_info;               /**< Information header */
    char *u_uri;                /**< Uri header */
    osip_list_t e_emails;      /**< list of mail address */
    osip_list_t p_phones;      /**< list of phone numbers * */
    sdp_connection_t *c_connection;   /**< Connection information */
    osip_list_t b_bandwidths;  /**< list of bandwidth info (sdp_bandwidth_t) */
    osip_list_t t_descrs;      /**< list of time description (sdp_time_descr_t) */
    char *z_adjustments;        /**< Time adjustment header */
    sdp_key_t *k_key;           /**< Key information header */
    osip_list_t a_attributes;  /**< list of global attributes (sdp_attribute_t) */
    osip_list_t m_medias;      /**< list of supported media (sdp_media_t) */
  };
  osip_dialog_t則是SIP RFC中的dialog或叫call leg的定義,它標(biāo)識(shí)了uac和uas的一對(duì)關(guān)系,并一直保持到會(huì)話(huà)(session)結(jié)束,一個(gè)完整的dialog主要包括from,to, callid,fromtag,totag,state等(可查看源碼),其中fromtag,totag,callid在一個(gè)dialog成功建立后才完整,體現(xiàn)在SIP消息中,就是From、To的tag,Call-id字段的值相同時(shí),這些消息是屬于它們對(duì)應(yīng)的一個(gè)Dialog的,例如將要發(fā)起 invite時(shí),只有fromtag,callid填充有值,在收到to遠(yuǎn)端的響應(yīng)時(shí),收到totag填充到dialog中,建立成功一個(gè)dialog,后繼的邏輯均是使用這個(gè)dialog進(jìn)行處理(如transaction事務(wù)處理),state表示本dialog的狀態(tài),與transaction的 state有很大的關(guān)聯(lián),共用由Enum結(jié)構(gòu)state_t定義;
    osip_transaction_t則是RFC中的事務(wù)的定義,它表示的是一個(gè)會(huì)話(huà)的某個(gè)Dialog之間的某一次消息發(fā)送及其完整的響應(yīng),例如 invite-100-180-200-ack這是一個(gè)完整的事務(wù),bye-200這也是一個(gè)完整的事務(wù),體現(xiàn)在SIP消息中,就是Via中的 branch的值相同表示屬于一個(gè)事務(wù)的消息(當(dāng)然,事務(wù)是在Dialog中的,所以From、To的tag,Call-id值也是相同的),事務(wù)對(duì)于 UAC,UAS的終端類(lèi)型不同及消息的不同,分為四類(lèi),前面說(shuō)的invite的事務(wù),主叫uac中會(huì)關(guān)聯(lián)一個(gè)ict事務(wù),被叫uas會(huì)關(guān)聯(lián)一個(gè)ist事務(wù),而除了invite之外,都?xì)w類(lèi)定義主叫nict,被叫nist,在Osip中,它是靠有限狀態(tài)機(jī)來(lái)實(shí)現(xiàn)的上述四種事務(wù)(osip_fsm_type_t中定義)的,它的主要屬性值有callid,transactionid,分別來(lái)標(biāo)識(shí)dialog和 transaction,其中還有一個(gè)時(shí)間戳birth_time標(biāo)識(shí)事務(wù)創(chuàng)建時(shí)間,可由超時(shí)處理函數(shù)用來(lái)判斷和決定超時(shí)情況下的事務(wù)的進(jìn)行和銷(xiāo)毀,而它的state屬性是非常重要的,根據(jù)上述的事務(wù)類(lèi)型不同,其值也不同,它是前面提到的狀態(tài)機(jī)的“狀態(tài)”,在實(shí)際狀態(tài)機(jī)的邏輯執(zhí)行中是一個(gè)關(guān)鍵值;
  • Osip初始化
      提到osip的初始化,可能大家都看過(guò)官方文檔里第一頁(yè)的代碼,首先就是osip_init(&osip)初始化了全局的osip_t結(jié)構(gòu)體,然后對(duì)它的回調(diào)函數(shù)進(jìn)行設(shè)置,很多人估計(jì)就是一看到這密密麻麻的一頁(yè)多的call_back設(shè)置被嚇到了,但結(jié)合前面分析的三個(gè)結(jié)構(gòu)體的含義,這里的含義就很清晰了:
      osip_t中有一個(gè)cb_send_message 函數(shù)指針,它是Osip最終與外界網(wǎng)絡(luò)交互的接口,它的參數(shù)有( osip_transaction_t * trn,    /*本消息所屬的事務(wù)*/
            osip_message_t * sipmsg, /*待發(fā)送的消息結(jié)構(gòu)體*/
            char *dest_socket_str,     /*目標(biāo)地址*/
            int32_t dest_port,            /*目標(biāo)端口*/
            int32_t send_sock)    /*用來(lái)發(fā)送消息的socket*/
      其中trn傳入主要是為了方便獲取事務(wù)的上下文數(shù)據(jù),它有一個(gè)void指針your_instance,可以用來(lái)傳入更多數(shù)據(jù)方便發(fā)送消息時(shí)參考,例如將該事務(wù)所屬的 dialog指針傳入;
      而sipmsg則是我們要發(fā)送的SIP消息的C結(jié)構(gòu)體,使用osip_message_to_str將其按RFC文檔格式轉(zhuǎn)換為一個(gè)字符串(osip中的parser模塊的主要功能),再通過(guò)任意你自己的網(wǎng)絡(luò)數(shù)據(jù)發(fā)送函數(shù)使用send_sock發(fā)送給dest_socket_str和dest_port 指定的目標(biāo),當(dāng)然,要記得使用osip_free釋放剛才發(fā)送出去的字符串占用的內(nèi)存,Osip中很多osipparser提供的消息解析處理函數(shù)都是動(dòng)態(tài)內(nèi)存分配的,使用完畢后需要及時(shí)釋放;
      使用osip_set_cb_send_message成功設(shè)置回調(diào)函數(shù),我們的SIP消息就有了出口了,下面繼續(xù)分析(當(dāng)然,了解到了上面的流程,也可以手工指定了)。

      下面的回調(diào)函數(shù)分為三類(lèi),分別是普通事務(wù)消息(osip_message_callback_type_t中定義)的處理回調(diào)函數(shù)、事務(wù)銷(xiāo)毀事件(osip_kill_callback_type_t中定義)的清理回調(diào)函數(shù)以及事務(wù)執(zhí)行過(guò)程中的錯(cuò)誤事件(osip_transport_error_callback_type_t中定義)處理回調(diào)函數(shù):
      先說(shuō)簡(jiǎn)單的,事務(wù)銷(xiāo)毀事件,事務(wù)正常結(jié)束(成功完成狀態(tài)機(jī)流程)或由超時(shí)處理函數(shù)強(qiáng)制終結(jié)等情況下均調(diào)用了這些回調(diào)函數(shù),一般就是釋放事務(wù)結(jié)構(gòu)體,為ICT,NICT,IST,NIST各設(shè)置或共用一個(gè)回調(diào)函數(shù)均可,只要正確釋放不再使用的內(nèi)存即可;
      錯(cuò)誤處理函數(shù)則是在整個(gè)狀態(tài)機(jī)執(zhí)行過(guò)程中發(fā)生的任何錯(cuò)誤的出口,一般用來(lái)安插 log函數(shù)方便調(diào)試,也可以直接設(shè)為空函數(shù);
      而最關(guān)鍵的就是正常消息的處理回調(diào)函數(shù)了,其量是非常大的,但仔細(xì)分下類(lèi),也和上面的回調(diào)函數(shù)一樣,也是分為四類(lèi),我們可有根據(jù)實(shí)際程序的需要來(lái)進(jìn)行設(shè)置,例如,SIP電話(huà)機(jī)就不需要處理OSIP_NIST_REGISTER_RECEIVED這個(gè)SIP注冊(cè)服務(wù)器才需要處理的Register消息事件了,精簡(jiǎn)一下,如果只是要做一個(gè)只需要實(shí)現(xiàn)主叫功能且不考慮錯(cuò)誤情況的UAC的Demo軟電話(huà)程序,則只需要設(shè)置如下幾個(gè)事件的回調(diào)函數(shù):
       OSIP_ICT_INVITE_SENT 發(fā)出Invite開(kāi)始呼叫
      OSIP_ICT_STATUS_1XX_RECEIVED 收到 180
      OSIP_ICT_STATUS_2XX_RECEIVED 收到200
      OSIP_ICT_ACK_SENT  發(fā)出 ack確定呼叫
      OSIP_NICT_BYE_SENT  發(fā)出bye結(jié)束呼叫
       OSIP_NICT_STATUS_2XX_RECEIVED 收到200確認(rèn)結(jié)束呼叫
      OSIP_NIST_BYE_RECEIVED 收到 bye結(jié)束呼叫
      OSIP_NIST_STATUS_2XX_SENT 發(fā)出 200確定結(jié)束呼叫
    而要增加接受呼叫的被叫UAS功能,則只需要增加如下事件:
      OSIP_IST_INVITE_RECEIVED 收到invite開(kāi)始呼叫
       OSIP_IST_STATUS_1XX_SENT 發(fā)出180
      OSIP_IST_STATUS_2XX_SENT 發(fā)出200
       OSIP_IST_ACK_RECEIVED  收到ack確認(rèn)呼叫
    具體的函數(shù)定義,則直接參考o(jì)sip_message_cb_t,osip_kill_transaction_cb_t, osip_transport_error_cb_t即可,回調(diào)函數(shù)的設(shè)置同上可以手工設(shè)置,也可以使用Osip提供的對(duì)應(yīng)的 osip_set_xxx_callback函數(shù);
  • 發(fā)出SIP消息
       要發(fā)送 SIP消息,從上面的分析可知有幾個(gè)必要的條件,osip_messag_t結(jié)構(gòu)的待發(fā)送消息,osip_dialog_t結(jié)構(gòu)體的dialog以及 osip_transaction_t的事務(wù);
      首先osip_malloc新分配一個(gè)dialog,使用osip_to_init,osip_to_parse,osip_to_free這類(lèi) parser函數(shù)功能函數(shù)按RFC設(shè)置call-id,from,to,local_cseq等必要字段(原則是:后面生成實(shí)際SIP消息結(jié)構(gòu)體要用到的字段就需要設(shè)置),使用osip_message_init初始化一個(gè)sipmsg,根據(jù)dialog來(lái)填充該結(jié)構(gòu)體(不同的消息填充的數(shù)據(jù)是不同的,沒(méi)有捷徑可走,只能看RFC根據(jù)需要填充字段),如果要給SIP消息添加Body例如SDP段,需要使用osip_message_set_body, osip_message_set_content_type函數(shù),設(shè)置的值是純文本,如果是SDP,Osip有提供簡(jiǎn)單的解析和生成便捷函數(shù)例如 sdp_message_to_str,sdp_message_a_attribute_add,但只是簡(jiǎn)單的字符操作,要填充合法的字段需要自己參考 SDP的RFC文檔,同樣沒(méi)捷徑可走。
      現(xiàn)在我們有了兩個(gè)必要條件了,還有最后一個(gè)也是最關(guān)鍵的部件,就是事務(wù)的創(chuàng)建和觸發(fā),
    int osip_transaction_init(
            osip_transaction_t ** transaction,  /*返回的事務(wù)結(jié)構(gòu)體指針*/
            osip_fsm_type_t ctx_type, /*事務(wù)類(lèi)型ICT/NICT/IST/NIST*/
            osip_t * osip,  /*前文說(shuō)的全局變量*/
            osip_message_t * request) /*前面生成的sipmsg*/
      創(chuàng)建了一個(gè)新的事務(wù),并自動(dòng)根據(jù)事務(wù)類(lèi)型、dialog和sipmsg進(jìn)行了初始化,最重要的是它使用了__osip_add_ict等函數(shù),將本事務(wù)插入到全局的osip_t結(jié)構(gòu)體的全局FIFO鏈表中去了,不同的事務(wù)類(lèi)型對(duì)應(yīng)不同的FIFO,由前文可知,本類(lèi)函數(shù)有四個(gè),F(xiàn)IFO也有四個(gè),對(duì)應(yīng) ICT,NICT,IST,NIST,注意這個(gè)這里使用osip_transaction_set_out_socket把發(fā)送sip消息的socket 接口配給該事務(wù),方便自動(dòng)調(diào)用前面設(shè)置的發(fā)送消息回調(diào)函數(shù)使用它自動(dòng)發(fā)送消息;
      前文提到了transaction里的state作為狀態(tài)機(jī)的 “狀態(tài)”,要執(zhí)行狀態(tài)機(jī),就需要有“事件”來(lái)觸發(fā),事件結(jié)構(gòu)體osip_event_t需要使用 osip_new_outgoing_sipmessage來(lái)對(duì)sipmsg進(jìn)行探測(cè)生成,設(shè)置正確的事件值,省卻了我們手工設(shè)置的工作,它調(diào)用 evt_set_type_outgoing_sipmessage來(lái)設(shè)置“事件”type_t,并將sipmsg掛到事件結(jié)構(gòu)體的sip屬性值上,有了根據(jù)消息分析出的事件后,使用osip_fifo_add(trn->transactionff, ev)將事件插入到事務(wù)的事件FIFO中,即transactionff屬性;
      
      有了上面的發(fā)送消息的必要條件了,消息是如何實(shí)際出發(fā)的呢?上面提到了,SIP消息的發(fā)送和響應(yīng)是一個(gè)事務(wù),不能隔離開(kāi)來(lái),即消息的發(fā)送需要事務(wù)狀態(tài)機(jī)來(lái)控制,我們上面設(shè)置了狀態(tài)機(jī)的狀態(tài)和事件,要觸發(fā)它,就是要執(zhí)行狀態(tài)機(jī)了:
      osip_ict_execute
      osip_nict_execute
       osip_ist_execute
      osip_nist_execute
      分別用來(lái)遍歷前面提到的四個(gè)事務(wù)FIFO,取出事務(wù),再依次取出事務(wù)內(nèi)的事件FIFO上的事件,使用osip_transaction_execute 依次執(zhí)行(有興趣的可以更深一步去查看,可以看到它最終就是調(diào)用了我們前面設(shè)置的消息回調(diào)函數(shù),至于具體調(diào)用哪個(gè),這就是OSIP協(xié)議棧內(nèi)部幫我們做的大量的工作了^_^);
      如果某個(gè)事務(wù)不能正常終結(jié)怎么辦呢?例如發(fā)出了Invite沒(méi)有收到任何響應(yīng),按RFC定義,不同的事務(wù)有不同的超時(shí)時(shí)間,osip_timers_ict[nict|ist|nist]_execute這些函數(shù)就是來(lái)根據(jù)取出的事務(wù)的時(shí)間戳與當(dāng)前時(shí)間取差后與規(guī)定的超時(shí)時(shí)間比對(duì),如果超時(shí),就自動(dòng)設(shè)置了超時(shí)“事件”并將事務(wù)“狀態(tài)”設(shè)為終結(jié),使用前面設(shè)定的消息超時(shí)事件回調(diào)函數(shù)處理即可(如果設(shè)置了);
      如果網(wǎng)絡(luò)質(zhì)量不穩(wěn)定,經(jīng)常丟失消息,需要使用osip_retransmissions_execute函數(shù)來(lái)自動(dòng)重發(fā)消息而不是等待超時(shí);
      為了即時(shí)響應(yīng)SIP消息的處理推動(dòng)狀態(tài)機(jī),上述的九個(gè)函數(shù)需要不停執(zhí)行,可以將它放入單獨(dú)線(xiàn)程中。
  • 收到SIP消息
       有了前面的發(fā)送SIP消息的理解,接收消息的處理就方便理解了,收到SIP消息,使用osip_parse進(jìn)行解析,得到一個(gè)osip_message_t 的sipmsg,使用evt_set_type_incoming_sipmessage得到事務(wù)的“事件”,并同上將sipmsg掛到事件結(jié)構(gòu)體的 sip字段,隨后立即使用osip_find_transaction_and_add_event來(lái)根據(jù)“事件”查找事務(wù)(有興趣可以深入看一下,事務(wù)的查找是通過(guò)SIP消息Via中的branch來(lái)匹配的),否則新建事務(wù),然后推動(dòng)狀態(tài)機(jī)執(zhí)行。
  • 狀態(tài)機(jī)內(nèi)部邏輯
      弄清了上面的狀態(tài)機(jī)的大概邏輯,設(shè)置正確完備的回調(diào)函數(shù),就可以正確使用Osip來(lái)進(jìn)行工作了,如果要進(jìn)一步深入 Osip,比如要擴(kuò)展Osip的狀態(tài)機(jī)處理自定義的消息字段和實(shí)現(xiàn)新的事務(wù)邏輯來(lái)生成新業(yè)務(wù)時(shí),就需要對(duì)狀態(tài)機(jī)的內(nèi)部邏輯有一定的了解;
      前面一再?gòu)?qiáng)調(diào),Osip內(nèi)部的幾個(gè)重要的數(shù)據(jù)結(jié)構(gòu)osip_message_t,osip_dialog_t,osip_transaction_t,其中面向用戶(hù)的主要是前后兩個(gè),而中間的dialog則很多時(shí)候是在狀態(tài)機(jī)內(nèi)部使用的,例如:收到消息,解析到sipmsg中,查找 transaction并進(jìn)行驅(qū)動(dòng),隨后找到它關(guān)聯(lián)的dialog(或者新生成)解析填充要發(fā)送的消息結(jié)構(gòu)體sipmsg,再次根據(jù)dialog和 sipmsg查找或生成transaction。
      如果要擴(kuò)展Osip,要做工作主要有:
      擴(kuò)展osip_message_t,增加要解析的字段或消息頭,并參考原Osip函數(shù)生成對(duì)應(yīng)的SIP字符串生成和解析函數(shù);
      擴(kuò)展osip_dialog_t,增加新的屬性,對(duì)應(yīng) osip_message_t的新增內(nèi)容;
      擴(kuò)展?fàn)顟B(tài)機(jī)的事件和狀態(tài)類(lèi)型,設(shè)置對(duì)應(yīng)的回調(diào)函數(shù),并關(guān)聯(lián)新增事件和狀態(tài)類(lèi)型到osip_message_t的解析函數(shù)或osip_dialog_t的初始化函數(shù)中,而osip_transaction_t大多數(shù)時(shí)候不需要擴(kuò)展,只要在對(duì)應(yīng)的事務(wù)類(lèi)型(大多數(shù)時(shí)候是NICT、NIST)處理邏輯中,增加對(duì)新增事件和狀態(tài)類(lèi)型的判斷和調(diào)用回調(diào)函數(shù)的邏輯即可

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多