Changeset 1469


Ignore:
Timestamp:
Oct 3, 2007 6:28:49 PM (11 years ago)
Author:
bennylp
Message:

Ticket 5: Support for SIP UPDATE (RFC 3311) and fix the offer/answer negotiation

Location:
pjproject/trunk
Files:
1 added
16 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/build.symbian/pjsip_uaU.def

    r1463 r1469  
    11EXPORTS 
    22        pjsip_100rel_attach                      @ 1 NONAME 
    3         pjsip_100rel_init_module                 @ 2 NONAME 
    4         pjsip_100rel_tx_response                 @ 3 NONAME 
    5         pjsip_create_sdp_body                    @ 4 NONAME 
    6         pjsip_dlg_get_inv_session                @ 5 NONAME 
    7         pjsip_get_refer_method                   @ 6 NONAME 
    8         pjsip_inv_answer                         @ 7 NONAME 
    9         pjsip_inv_create_uac                     @ 8 NONAME 
    10         pjsip_inv_create_uas                     @ 9 NONAME 
    11         pjsip_inv_end_session                    @ 10 NONAME 
    12         pjsip_inv_initial_answer                 @ 11 NONAME 
    13         pjsip_inv_invite                         @ 12 NONAME 
    14         pjsip_inv_reinvite                       @ 13 NONAME 
    15         pjsip_inv_send_msg                       @ 14 NONAME 
    16         pjsip_inv_set_sdp_answer                 @ 15 NONAME 
    17         pjsip_inv_state_name                     @ 16 NONAME 
    18         pjsip_inv_terminate                      @ 17 NONAME 
    19         pjsip_inv_update                         @ 18 NONAME 
    20         pjsip_inv_usage_init                     @ 19 NONAME 
    21         pjsip_inv_usage_instance                 @ 20 NONAME 
    22         pjsip_inv_verify_request                 @ 21 NONAME 
    23         pjsip_refer_method                       @ 22 NONAME 
    24         pjsip_regc_add_headers                   @ 23 NONAME 
    25         pjsip_regc_create                        @ 24 NONAME 
    26         pjsip_regc_destroy                       @ 25 NONAME 
    27         pjsip_regc_get_info                      @ 26 NONAME 
    28         pjsip_regc_get_pool                      @ 27 NONAME 
    29         pjsip_regc_init                          @ 28 NONAME 
    30         pjsip_regc_register                      @ 29 NONAME 
    31         pjsip_regc_send                          @ 30 NONAME 
    32         pjsip_regc_set_credentials               @ 31 NONAME 
    33         pjsip_regc_set_route_set                 @ 32 NONAME 
    34         pjsip_regc_set_transport                 @ 33 NONAME 
    35         pjsip_regc_unregister                    @ 34 NONAME 
    36         pjsip_regc_unregister_all                @ 35 NONAME 
    37         pjsip_regc_update_contact                @ 36 NONAME 
    38         pjsip_regc_update_expires                @ 37 NONAME 
    39         pjsip_replaces_hdr_create                @ 38 NONAME 
    40         pjsip_replaces_init_module               @ 39 NONAME 
    41         pjsip_replaces_verify_request            @ 40 NONAME 
    42         pjsip_xfer_accept                        @ 41 NONAME 
    43         pjsip_xfer_create_uac                    @ 42 NONAME 
    44         pjsip_xfer_create_uas                    @ 43 NONAME 
    45         pjsip_xfer_current_notify                @ 44 NONAME 
    46         pjsip_xfer_init_module                   @ 45 NONAME 
    47         pjsip_xfer_initiate                      @ 46 NONAME 
    48         pjsip_xfer_notify                        @ 47 NONAME 
    49         pjsip_xfer_send_request                  @ 48 NONAME 
     3        pjsip_100rel_create_prack                @ 2 NONAME 
     4        pjsip_100rel_end_session                 @ 3 NONAME 
     5        pjsip_100rel_init_module                 @ 4 NONAME 
     6        pjsip_100rel_is_reliable                 @ 5 NONAME 
     7        pjsip_100rel_on_rx_prack                 @ 6 NONAME 
     8        pjsip_100rel_send_prack                  @ 7 NONAME 
     9        pjsip_100rel_tx_response                 @ 8 NONAME 
     10        pjsip_create_sdp_body                    @ 9 NONAME 
     11        pjsip_dlg_get_inv_session                @ 10 NONAME 
     12        pjsip_get_prack_method                   @ 11 NONAME 
     13        pjsip_get_refer_method                   @ 12 NONAME 
     14        pjsip_inv_answer                         @ 13 NONAME 
     15        pjsip_inv_create_uac                     @ 14 NONAME 
     16        pjsip_inv_create_uas                     @ 15 NONAME 
     17        pjsip_inv_end_session                    @ 16 NONAME 
     18        pjsip_inv_initial_answer                 @ 17 NONAME 
     19        pjsip_inv_invite                         @ 18 NONAME 
     20        pjsip_inv_reinvite                       @ 19 NONAME 
     21        pjsip_inv_send_msg                       @ 20 NONAME 
     22        pjsip_inv_set_sdp_answer                 @ 21 NONAME 
     23        pjsip_inv_state_name                     @ 22 NONAME 
     24        pjsip_inv_terminate                      @ 23 NONAME 
     25        pjsip_inv_update                         @ 24 NONAME 
     26        pjsip_inv_usage_init                     @ 25 NONAME 
     27        pjsip_inv_usage_instance                 @ 26 NONAME 
     28        pjsip_inv_verify_request                 @ 27 NONAME 
     29        pjsip_prack_method                       @ 28 NONAME 
     30        pjsip_refer_method                       @ 29 NONAME 
     31        pjsip_regc_add_headers                   @ 30 NONAME 
     32        pjsip_regc_create                        @ 31 NONAME 
     33        pjsip_regc_destroy                       @ 32 NONAME 
     34        pjsip_regc_get_info                      @ 33 NONAME 
     35        pjsip_regc_get_pool                      @ 34 NONAME 
     36        pjsip_regc_init                          @ 35 NONAME 
     37        pjsip_regc_register                      @ 36 NONAME 
     38        pjsip_regc_send                          @ 37 NONAME 
     39        pjsip_regc_set_credentials               @ 38 NONAME 
     40        pjsip_regc_set_route_set                 @ 39 NONAME 
     41        pjsip_regc_set_transport                 @ 40 NONAME 
     42        pjsip_regc_unregister                    @ 41 NONAME 
     43        pjsip_regc_unregister_all                @ 42 NONAME 
     44        pjsip_regc_update_contact                @ 43 NONAME 
     45        pjsip_regc_update_expires                @ 44 NONAME 
     46        pjsip_replaces_hdr_create                @ 45 NONAME 
     47        pjsip_replaces_init_module               @ 46 NONAME 
     48        pjsip_replaces_verify_request            @ 47 NONAME 
     49        pjsip_xfer_accept                        @ 48 NONAME 
     50        pjsip_xfer_create_uac                    @ 49 NONAME 
     51        pjsip_xfer_create_uas                    @ 50 NONAME 
     52        pjsip_xfer_current_notify                @ 51 NONAME 
     53        pjsip_xfer_init_module                   @ 52 NONAME 
     54        pjsip_xfer_initiate                      @ 53 NONAME 
     55        pjsip_xfer_notify                        @ 54 NONAME 
     56        pjsip_xfer_send_request                  @ 55 NONAME 
  • pjproject/trunk/pjlib/include/pj/errno.h

    r1405 r1469  
    305305 */ 
    306306#define PJ_ETOOSMALL        (PJ_ERRNO_START_STATUS + 19)/* 70019 */ 
    307  
     307/** 
     308 * @hideinitializer 
     309 * Ignored 
     310 */ 
     311#define PJ_EIGNORED         (PJ_ERRNO_START_STATUS + 20)/* 70020 */ 
    308312 
    309313/** @} */   /* pj_errnum */ 
  • pjproject/trunk/pjlib/src/pj/errno.c

    r1405 r1469  
    7171    PJ_BUILD_ERR(PJ_ERESOLVE,      "gethostbyname() has returned error"), 
    7272    PJ_BUILD_ERR(PJ_ETOOSMALL,     "Size is too short"), 
     73    PJ_BUILD_ERR(PJ_EIGNORED,      "Ignored"), 
    7374}; 
    7475#endif  /* PJ_HAS_ERROR_STRING */ 
  • pjproject/trunk/pjsip/build/Makefile

    r1463 r1469  
    8989                    transport_test.o transport_udp_test.o \ 
    9090                    tsx_basic_test.o tsx_bench.o tsx_uac_test.o \ 
    91                     tsx_uas_test.o txdata_test.o uri_test.o 
     91                    tsx_uas_test.o txdata_test.o uri_test.o \ 
     92                    inv_offer_answer_test.o 
    9293export TEST_CFLAGS += $(_CFLAGS) 
    9394export TEST_LDFLAGS += $(PJ_LDFLAGS) $(PJ_LDLIBS) $(LDFLAGS) 
  • pjproject/trunk/pjsip/build/test_pjsip.dsp

    r1102 r1469  
    9898# Begin Source File 
    9999 
     100SOURCE="..\src\test-pjsip\inv_offer_answer_test.c" 
     101# End Source File 
     102# Begin Source File 
     103 
    100104SOURCE="..\src\test-pjsip\main.c" 
    101105# End Source File 
  • pjproject/trunk/pjsip/build/test_pjsip.vcproj

    r1177 r1469  
    4545                                Optimization="2" 
    4646                                InlineFunctionExpansion="2" 
    47                                 AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include" 
     47                                AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include" 
    4848                                PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;PJ_WIN32;PJ_M_I386" 
    4949                                StringPooling="true" 
     
    140140                                Name="VCCLCompilerTool" 
    141141                                Optimization="0" 
    142                                 AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include" 
     142                                AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjmedia/include" 
    143143                                PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;PJ_WIN32;PJ_M_I386" 
    144144                                MinimalRebuild="true" 
     
    256256                        </File> 
    257257                        <File 
     258                                RelativePath="..\src\test-pjsip\inv_offer_answer_test.c" 
     259                                > 
     260                        </File> 
     261                        <File 
    258262                                RelativePath="..\src\test-pjsip\main.c" 
    259263                                > 
  • pjproject/trunk/pjsip/include/pjsip-ua/sip_100rel.h

    r1463 r1469  
    4646 * \subsection pjsip_100rel_init Initializing 100rel Module 
    4747 * 
    48  * \a PRACK and \a 100rel extension support is built into the library when 
    49  * #PJSIP_HAS_100REL macro is enabled. The default is yes. Application can 
    50  * set this macro to zero if it does not wish to support reliable provisional 
    51  * response extension. 
    52  * 
    53  * Application must also explicitly initialize 100rel module by calling 
     48 * Application must explicitly initialize 100rel module by calling 
    5449 * #pjsip_100rel_init_module() in application initialization function. 
    5550 * 
     
    6055 * 
    6156 * For UAC, \a 100rel support will be enabled in the session if \a 100rel 
    62  * support is enabled in the library (with #PJSIP_HAS_100REL macro).  
     57 * support is enabled in the library (default is yes).  
    6358 * Outgoing INVITE request will include \a 100rel tag in \a Supported 
    6459 * header and \a PRACK method in \a Allow header. When callee endpoint 
     
    8782    unsigned options = 0; 
    8883 
    89 #if PJSIP_HAS_100REL 
    9084    options |= PJSIP_INV_SUPPORT_100REL; 
    91 #endif 
    9285 
    9386    status = pjsip_inv_verify_request(rdata, &options, answer, NULL, 
     
    130123PJ_BEGIN_DECL 
    131124 
     125 
     126/**  
     127 * PRACK method constant.  
     128 * @see pjsip_get_prack_method()  
     129  */ 
     130PJ_DECL_DATA(const pjsip_method) pjsip_prack_method; 
     131 
     132 
     133/**  
     134 * Get #pjsip_invite_method constant.  
     135 */ 
     136PJ_DECL(const pjsip_method*) pjsip_get_prack_method(void); 
     137 
     138 
    132139/** 
    133140 * Initialize 100rel module. This function must be called once during 
     
    139146 */ 
    140147PJ_DECL(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt); 
     148 
    141149 
    142150/** 
     
    150158 */ 
    151159PJ_DECL(pj_status_t) pjsip_100rel_attach(pjsip_inv_session *inv); 
     160 
     161 
     162/** 
     163 * Check if incoming response has reliable provisional response feature. 
     164 * 
     165 * @param rdata         Receive data buffer containing the response. 
     166 * 
     167 * @return              PJ_TRUE if the provisional response is reliable. 
     168 */ 
     169PJ_DECL(pj_bool_t) pjsip_100rel_is_reliable(pjsip_rx_data *rdata); 
     170 
     171 
     172/** 
     173 * Create PRACK request for the incoming reliable provisional response. 
     174 * Note that PRACK request MUST be sent using #pjsip_100rel_send_prack(). 
     175 * 
     176 * @param inv           The invite session. 
     177 * @param rdata         The incoming reliable provisional response. 
     178 * @param p_tdata       Upon return, it will be initialized with the 
     179 *                      PRACK request. 
     180 * 
     181 * @return              PJ_SUCCESS on successful. 
     182 */ 
     183PJ_DECL(pj_status_t) pjsip_100rel_create_prack(pjsip_inv_session *inv, 
     184                                               pjsip_rx_data *rdata, 
     185                                               pjsip_tx_data **p_tdata); 
     186 
     187/** 
     188 * Send PRACK request. 
     189 * 
     190 * @param inv           The invite session. 
     191 * @param tdata         The PRACK request. 
     192 * 
     193 * @return              PJ_SUCCESS on successful. 
     194 */ 
     195PJ_DECL(pj_status_t) pjsip_100rel_send_prack(pjsip_inv_session *inv, 
     196                                             pjsip_tx_data *tdata); 
     197 
     198 
     199/** 
     200 * Handle incoming PRACK request. 
     201 * 
     202 * @param inv           The invite session. 
     203 * @param rdata         Incoming PRACK request. 
     204 * 
     205 * @return              PJ_SUCCESS on successful. 
     206 */ 
     207PJ_DECL(pj_status_t) pjsip_100rel_on_rx_prack(pjsip_inv_session *inv, 
     208                                              pjsip_rx_data *rdata); 
     209 
    152210 
    153211/** 
     
    167225 
    168226 
     227/** 
     228 * Notify 100rel module that the invite session has been disconnected. 
     229 * 
     230 * @param inv           The invite session. 
     231 * 
     232 * @return              PJ_SUCCESS on successful. 
     233 */ 
     234PJ_DECL(pj_status_t) pjsip_100rel_end_session(pjsip_inv_session *inv); 
     235 
     236 
    169237PJ_END_DECL 
    170238 
  • pjproject/trunk/pjsip/include/pjsip-ua/sip_inv.h

    r1463 r1469  
    254254    pjsip_transaction   *invite_tsx;                /**< 1st invite tsx.    */ 
    255255    pjsip_tx_data       *last_answer;               /**< Last INVITE resp.  */ 
     256    pjsip_tx_data       *last_ack;                  /**< Last ACK request   */ 
     257    pj_int32_t           last_ack_cseq;             /**< CSeq of last ACK   */ 
    256258    void                *mod_data[PJSIP_MAX_MODULE];/**< Modules data.      */ 
    257259}; 
     
    562564 
    563565/** 
    564  * Create an UPDATE request.  
     566 * Create an UPDATE request to initiate new SDP offer. 
    565567 * 
    566568 * @param inv           The invite session. 
     
    569571 *                      contact, it can specify the new contact in this  
    570572 *                      argument; otherwise this argument must be NULL. 
    571  * @param new_offer     Application MAY initiate a new SDP offer/answer  
    572  *                      session in the request when there is no pending answer 
    573  *                      to be sent or received. It can detect this condition 
    574  *                      by observing the state of the SDP negotiator of the  
    575  *                      invite session. If new offer should be sent to remote, 
    576  *                      the offer must be specified in this argument; otherwise 
    577  *                      this argument must be NULL. 
     573 * @param offer         Offer to be sent to remote. This argument is 
     574 *                      mandatory. 
    578575 * @param p_tdata       Pointer to receive the UPDATE request message to 
    579576 *                      be created. 
     
    585582PJ_DECL(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv, 
    586583                                        const pj_str_t *new_contact, 
    587                                         const pjmedia_sdp_session *new_offer, 
     584                                        const pjmedia_sdp_session *offer, 
    588585                                        pjsip_tx_data **p_tdata ); 
    589586 
  • pjproject/trunk/pjsip/include/pjsip/sip_config.h

    r1463 r1469  
    6666 
    6767/** 
    68  * Specify whether support for reliable provisional response (100rel, PRACK) 
    69  * should be built in the library. 
    70  * 
    71  * Default: 1 
    72  */ 
    73 #ifndef PJSIP_HAS_100REL 
    74 #    define PJSIP_HAS_100REL            1 
    75 #endif 
    76  
    77  
    78 /** 
    7968 * Specify maximum transaction count in transaction hash table. 
    8069 * Default value is 16*1024 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_100rel.c

    r1467 r1469  
    2929#include <pj/rand.h> 
    3030 
    31 #if defined(PJSIP_HAS_100REL) && PJSIP_HAS_100REL!=0 
    32  
    3331#define THIS_FILE       "sip_100rel.c" 
    3432 
     33/* PRACK method */ 
     34PJ_DEF_DATA(const pjsip_method) pjsip_prack_method = 
     35{ 
     36    PJSIP_OTHER_METHOD, 
     37    { "PRACK", 5 } 
     38}; 
     39 
    3540typedef struct dlg_data dlg_data; 
    3641 
     
    3944 */ 
    4045static pj_status_t mod_100rel_load(pjsip_endpoint *endpt); 
    41 static void        mod_100rel_on_tsx_state(pjsip_transaction*, pjsip_event*); 
    4246 
    4347static void handle_incoming_prack(dlg_data *dd, pjsip_transaction *tsx, 
     
    4852                          struct pj_timer_entry *entry); 
    4953 
    50  
    51 /* PRACK method */ 
    52 const pjsip_method pjsip_prack_method = 
    53 { 
    54         PJSIP_OTHER_METHOD, 
    55         { "PRACK", 5 } 
    56 }; 
    5754 
    5855const pj_str_t tag_100rel = { "100rel", 6 }; 
     
    8178        NULL,                               /* on_tx_request.           */ 
    8279        NULL,                               /* on_tx_response()         */ 
    83         &mod_100rel_on_tsx_state,           /* on_tsx_state()           */ 
     80        NULL,                               /* on_tsx_state()           */ 
    8481    } 
    8582 
     
    133130static pj_status_t mod_100rel_load(pjsip_endpoint *endpt) 
    134131{ 
    135         mod_100rel.endpt = endpt; 
    136         pjsip_endpt_add_capability(endpt, &mod_100rel.mod,  
    137                                    PJSIP_H_ALLOW, NULL, 
    138                                    1, &pjsip_prack_method.name); 
    139         pjsip_endpt_add_capability(endpt, &mod_100rel.mod,  
    140                                    PJSIP_H_SUPPORTED, NULL, 
    141                                    1, &tag_100rel); 
    142  
     132    mod_100rel.endpt = endpt; 
     133    pjsip_endpt_add_capability(endpt, &mod_100rel.mod,  
     134                               PJSIP_H_ALLOW, NULL, 
     135                               1, &pjsip_prack_method.name); 
     136    pjsip_endpt_add_capability(endpt, &mod_100rel.mod,  
     137                               PJSIP_H_SUPPORTED, NULL, 
     138                               1, &tag_100rel); 
     139 
     140    return PJ_SUCCESS; 
     141} 
     142 
     143static pjsip_require_hdr *find_req_hdr(pjsip_msg *msg) 
     144{ 
     145    pjsip_require_hdr *hreq; 
     146 
     147    hreq = (pjsip_require_hdr*) 
     148            pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL); 
     149 
     150    while (hreq) { 
     151        unsigned i; 
     152        for (i=0; i<hreq->count; ++i) { 
     153            if (!pj_stricmp(&hreq->values[i], &tag_100rel)) { 
     154                return hreq; 
     155            } 
     156        } 
     157 
     158        if ((void*)hreq->next == (void*)&msg->hdr) 
     159            return NULL; 
     160 
     161        hreq = (pjsip_require_hdr*) 
     162                pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, hreq->next); 
     163 
     164    } 
     165 
     166    return NULL; 
     167} 
     168 
     169 
     170/* 
     171 * Get PRACK method constant.  
     172 */ 
     173PJ_DEF(const pjsip_method*) pjsip_get_prack_method(void) 
     174{ 
     175    return &pjsip_prack_method; 
     176} 
     177 
     178 
     179/* 
     180 * init module 
     181 */ 
     182PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt) 
     183{ 
     184    if (mod_100rel.mod.id != -1) 
    143185        return PJ_SUCCESS; 
    144 } 
    145  
    146 static pjsip_require_hdr *find_req_hdr(pjsip_msg *msg) 
    147 { 
    148         pjsip_require_hdr *hreq; 
    149  
    150         hreq = (pjsip_require_hdr*) 
    151                 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL); 
    152  
    153         while (hreq) { 
    154                 unsigned i; 
    155                 for (i=0; i<hreq->count; ++i) { 
    156                         if (!pj_stricmp(&hreq->values[i], &tag_100rel)) { 
    157                                 return hreq; 
    158                         } 
    159                 } 
    160  
    161                 if ((void*)hreq->next == (void*)&msg->hdr) 
    162                         return NULL; 
    163  
    164                 hreq = (pjsip_require_hdr*) 
    165                         pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, hreq->next); 
    166  
    167         } 
    168  
    169         return NULL; 
    170 } 
    171  
    172 static void mod_100rel_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) 
    173 { 
    174         pjsip_dialog *dlg; 
    175         dlg_data *dd; 
    176  
    177         dlg = pjsip_tsx_get_dlg(tsx); 
    178         if (!dlg) 
    179                 return; 
    180  
    181         dd = (dlg_data*) dlg->mod_data[mod_100rel.mod.id]; 
    182         if (!dd) 
    183                 return; 
    184  
    185         if (tsx->role == PJSIP_ROLE_UAS && 
    186             tsx->state == PJSIP_TSX_STATE_TRYING && 
    187             pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0) 
    188         { 
    189                 /*  
    190                  * Handle incoming PRACK request. 
    191                  */ 
    192                 handle_incoming_prack(dd, tsx, e); 
    193  
    194         } else if (tsx->role == PJSIP_ROLE_UAC && 
    195                    tsx->method.id == PJSIP_INVITE_METHOD && 
    196                    e->type == PJSIP_EVENT_TSX_STATE && 
    197                    e->body.tsx_state.type == PJSIP_EVENT_RX_MSG &&  
    198                    e->body.tsx_state.src.rdata->msg_info.msg->line.status.code > 100 && 
    199                    e->body.tsx_state.src.rdata->msg_info.msg->line.status.code < 200 && 
    200                    e->body.tsx_state.src.rdata->msg_info.require != NULL) 
    201         { 
    202                 /* 
    203                  * Handle incoming provisional response which wants to  
    204                  * be PRACK-ed 
    205                  */ 
    206  
    207                 if (find_req_hdr(e->body.tsx_state.src.rdata->msg_info.msg)) { 
    208                         /* Received provisional response which needs to be  
    209                          * PRACK-ed. 
    210                          */ 
    211                         handle_incoming_response(dd, tsx, e); 
    212                 } 
    213  
    214         } else if (tsx->role == PJSIP_ROLE_UAC && 
    215                    tsx->state == PJSIP_TSX_STATE_COMPLETED && 
    216                    pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0) 
    217         { 
    218                 /* 
    219                  * Handle the status of outgoing PRACK request. 
    220                  */ 
    221                 if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST || 
    222                     tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT || 
    223                     tsx->status_code == PJSIP_SC_TSX_TIMEOUT || 
    224                     tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR) 
    225                 { 
    226                         /* These are fatal errors which should terminate 
    227                          * the session AND dialog! 
    228                          */ 
    229                         PJ_TODO(TERMINATE_SESSION_ON_481); 
    230                 } 
    231  
    232         } else if (tsx == dd->inv->invite_tsx && 
    233                    tsx->role == PJSIP_ROLE_UAS && 
    234                    tsx->state == PJSIP_TSX_STATE_TERMINATED) 
    235         { 
    236                 /* Make sure we don't have pending transmission */ 
    237                 if (dd->uas_state) { 
    238                         pj_assert(!dd->uas_state->retransmit_timer.id); 
    239                         pj_assert(pj_list_empty(&dd->uas_state->tx_data_list)); 
    240                 } 
    241         } 
    242 } 
     186 
     187    return pjsip_endpt_register_module(endpt, &mod_100rel.mod); 
     188} 
     189 
     190 
     191/* 
     192 * API: attach 100rel support in invite session. Called by 
     193 *      sip_inv.c 
     194 */ 
     195PJ_DEF(pj_status_t) pjsip_100rel_attach(pjsip_inv_session *inv) 
     196{ 
     197    dlg_data *dd; 
     198 
     199    /* Check that 100rel module has been initialized */ 
     200    PJ_ASSERT_RETURN(mod_100rel.mod.id >= 0, PJ_EINVALIDOP); 
     201 
     202    /* Create and attach as dialog usage */ 
     203    dd = PJ_POOL_ZALLOC_T(inv->dlg->pool, dlg_data); 
     204    dd->inv = inv; 
     205    pjsip_dlg_add_usage(inv->dlg, &mod_100rel.mod, (void*)dd); 
     206 
     207    PJ_LOG(5,(dd->inv->dlg->obj_name, "100rel module attached")); 
     208 
     209    return PJ_SUCCESS; 
     210} 
     211 
     212 
     213/* 
     214 * Check if incoming response has reliable provisional response feature. 
     215 */ 
     216PJ_DEF(pj_bool_t) pjsip_100rel_is_reliable(pjsip_rx_data *rdata) 
     217{ 
     218    pjsip_msg *msg = rdata->msg_info.msg; 
     219 
     220    PJ_ASSERT_RETURN(msg->type == PJSIP_RESPONSE_MSG, PJ_FALSE); 
     221 
     222    return msg->line.status.code > 100 && msg->line.status.code < 200 && 
     223           rdata->msg_info.require != NULL && 
     224           find_req_hdr(msg) != NULL; 
     225} 
     226 
     227 
     228/* 
     229 * Create PRACK request for the incoming reliable provisional response. 
     230 */ 
     231PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv, 
     232                                               pjsip_rx_data *rdata, 
     233                                               pjsip_tx_data **p_tdata) 
     234{ 
     235    dlg_data *dd; 
     236    pjsip_transaction *tsx; 
     237    pjsip_msg *msg; 
     238    pjsip_generic_string_hdr *rseq_hdr; 
     239    pjsip_generic_string_hdr *rack_hdr; 
     240    unsigned rseq; 
     241    pj_str_t rack; 
     242    char rack_buf[80]; 
     243    pjsip_tx_data *tdata; 
     244    pj_status_t status; 
     245 
     246    *p_tdata = NULL; 
     247 
     248    dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 
     249    PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED); 
     250 
     251    tsx = pjsip_rdata_get_tsx(rdata); 
     252    msg = rdata->msg_info.msg; 
     253 
     254    /* Check our assumptions */ 
     255    pj_assert( tsx->role == PJSIP_ROLE_UAC && 
     256               tsx->method.id == PJSIP_INVITE_METHOD && 
     257               msg->line.status.code > 100 && 
     258               msg->line.status.code < 200); 
     259 
     260 
     261    /* Get the RSeq header */ 
     262    rseq_hdr = (pjsip_generic_string_hdr*) 
     263               pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL); 
     264    if (rseq_hdr == NULL) { 
     265        PJ_LOG(4,(dd->inv->dlg->obj_name,  
     266                 "Ignoring provisional response with no RSeq header")); 
     267        return PJSIP_EMISSINGHDR; 
     268    } 
     269    rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue); 
     270 
     271    /* Create new UAC state if we don't have one */ 
     272    if (dd->uac_state == NULL) { 
     273        dd->uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool, 
     274                                         uac_state_t); 
     275        dd->uac_state->cseq = rdata->msg_info.cseq->cseq; 
     276        dd->uac_state->rseq = rseq - 1; 
     277    } 
     278 
     279    /* If this is from new INVITE transaction, reset UAC state */ 
     280    if (rdata->msg_info.cseq->cseq != dd->uac_state->cseq) { 
     281        dd->uac_state->cseq = rdata->msg_info.cseq->cseq; 
     282        dd->uac_state->rseq = rseq - 1; 
     283    } 
     284 
     285    /* Ignore provisional response retransmission */ 
     286    if (rseq <= dd->uac_state->rseq) { 
     287        /* This should have been handled before */ 
     288        return PJ_EIGNORED; 
     289 
     290    /* Ignore provisional response with out-of-order RSeq */ 
     291    } else if (rseq != dd->uac_state->rseq + 1) { 
     292        PJ_LOG(4,(dd->inv->dlg->obj_name,  
     293                 "Ignoring provisional response because RSeq jump " 
     294                 "(expecting %u, got %u)", 
     295                 dd->uac_state->rseq+1, rseq)); 
     296        return PJ_EIGNORED; 
     297    } 
     298 
     299    /* Update our RSeq */ 
     300    dd->uac_state->rseq = rseq; 
     301 
     302    /* Create PRACK */ 
     303    status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method, 
     304                                      -1, &tdata); 
     305    if (status != PJ_SUCCESS) 
     306        return status; 
     307 
     308    /* Create RAck header */ 
     309    rack.ptr = rack_buf; 
     310    rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf), 
     311                                 "%u %u %.*s", 
     312                                 rseq, rdata->msg_info.cseq->cseq, 
     313                                 (int)tsx->method.name.slen, 
     314                                 tsx->method.name.ptr); 
     315    rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack); 
     316    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr); 
     317 
     318    /* Done */ 
     319    *p_tdata = tdata; 
     320 
     321    return PJ_SUCCESS; 
     322} 
     323 
     324 
     325/* 
     326 * Send PRACK request. 
     327 */ 
     328PJ_DEF(pj_status_t) pjsip_100rel_send_prack( pjsip_inv_session *inv, 
     329                                             pjsip_tx_data *tdata) 
     330{ 
     331    dlg_data *dd; 
     332 
     333    dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 
     334    PJ_ASSERT_ON_FAIL(dd != NULL,  
     335    {pjsip_tx_data_dec_ref(tdata); return PJSIP_ENOTINITIALIZED; }); 
     336 
     337    return pjsip_dlg_send_request(inv->dlg, tdata,  
     338                                  mod_100rel.mod.id, (void*) dd); 
     339 
     340} 
     341 
     342 
     343/* 
     344 * Notify 100rel module that the invite session has been disconnected. 
     345 */ 
     346PJ_DEF(pj_status_t) pjsip_100rel_end_session(pjsip_inv_session *inv) 
     347{ 
     348    dlg_data *dd; 
     349 
     350    dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 
     351    if (!dd) 
     352        return PJ_SUCCESS; 
     353 
     354    /* Make sure we don't have pending transmission */ 
     355    if (dd->uas_state) { 
     356        pj_assert(!dd->uas_state->retransmit_timer.id); 
     357        pj_assert(pj_list_empty(&dd->uas_state->tx_data_list)); 
     358    } 
     359 
     360    return PJ_SUCCESS; 
     361} 
     362 
    243363 
    244364static void parse_rack(const pj_str_t *rack, 
     
    246366                       pj_str_t *p_method) 
    247367{ 
    248         const char *p = rack->ptr, *end = p + rack->slen; 
    249         pj_str_t token; 
    250  
    251         token.ptr = (char*)p; 
    252         while (p < end && pj_isdigit(*p)) 
    253                 ++p; 
    254         token.slen = p - token.ptr; 
    255         *p_rseq = pj_strtoul(&token); 
    256  
     368    const char *p = rack->ptr, *end = p + rack->slen; 
     369    pj_str_t token; 
     370 
     371    token.ptr = (char*)p; 
     372    while (p < end && pj_isdigit(*p)) 
    257373        ++p; 
    258         token.ptr = (char*)p; 
    259         while (p < end && pj_isdigit(*p)) 
    260                 ++p; 
    261         token.slen = p - token.ptr; 
    262         *p_seq = pj_strtoul(&token); 
    263  
     374    token.slen = p - token.ptr; 
     375    *p_rseq = pj_strtoul(&token); 
     376 
     377    ++p; 
     378    token.ptr = (char*)p; 
     379    while (p < end && pj_isdigit(*p)) 
    264380        ++p; 
    265         if (p < end) { 
    266                 p_method->ptr = (char*)p; 
    267                 p_method->slen = end - p; 
    268         } else { 
    269                 p_method->ptr = NULL; 
    270                 p_method->slen = 0; 
    271         } 
     381    token.slen = p - token.ptr; 
     382    *p_seq = pj_strtoul(&token); 
     383 
     384    ++p; 
     385    if (p < end) { 
     386        p_method->ptr = (char*)p; 
     387        p_method->slen = end - p; 
     388    } else { 
     389        p_method->ptr = NULL; 
     390        p_method->slen = 0; 
     391    } 
    272392} 
    273393 
     
    275395static void clear_all_responses(dlg_data *dd) 
    276396{ 
    277         tx_data_list_t *tl; 
    278  
    279         tl = dd->uas_state->tx_data_list.next; 
    280         while (tl != &dd->uas_state->tx_data_list) { 
    281                 pjsip_tx_data_dec_ref(tl->tdata); 
    282                 tl = tl->next; 
     397    tx_data_list_t *tl; 
     398 
     399    tl = dd->uas_state->tx_data_list.next; 
     400    while (tl != &dd->uas_state->tx_data_list) { 
     401        pjsip_tx_data_dec_ref(tl->tdata); 
     402        tl = tl->next; 
     403    } 
     404    pj_list_init(&dd->uas_state->tx_data_list); 
     405} 
     406 
     407 
     408/* 
     409 * Handle incoming PRACK request. 
     410 */ 
     411PJ_DEF(pj_status_t) pjsip_100rel_on_rx_prack( pjsip_inv_session *inv, 
     412                                              pjsip_rx_data *rdata) 
     413{ 
     414    dlg_data *dd; 
     415    pjsip_transaction *tsx; 
     416    pjsip_msg *msg; 
     417    pjsip_generic_string_hdr *rack_hdr; 
     418    pjsip_tx_data *tdata; 
     419    pj_uint32_t rseq; 
     420    pj_int32_t cseq; 
     421    pj_str_t method; 
     422    pj_status_t status; 
     423 
     424    dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 
     425    PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED); 
     426 
     427    tsx = pjsip_rdata_get_tsx(rdata); 
     428    pj_assert(tsx != NULL); 
     429 
     430    msg = rdata->msg_info.msg; 
     431 
     432    /* Always reply with 200/OK for PRACK */ 
     433    status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata); 
     434    if (status == PJ_SUCCESS) { 
     435        status = pjsip_dlg_send_response(inv->dlg, tsx, tdata); 
     436    } 
     437 
     438    /* Ignore if we don't have pending transmission */ 
     439    if (dd->uas_state == NULL || pj_list_empty(&dd->uas_state->tx_data_list)) { 
     440        PJ_LOG(4,(dd->inv->dlg->obj_name,  
     441                  "PRACK ignored - no pending response")); 
     442        return PJ_EIGNORED; 
     443    } 
     444 
     445    /* Find RAck header */ 
     446    rack_hdr = (pjsip_generic_string_hdr*) 
     447               pjsip_msg_find_hdr_by_name(msg, &RACK, NULL); 
     448    if (!rack_hdr) { 
     449        /* RAck header not found */ 
     450        PJ_LOG(4,(dd->inv->dlg->obj_name, "No RAck header")); 
     451        return PJSIP_EMISSINGHDR; 
     452    } 
     453 
     454    /* Parse RAck header */ 
     455    parse_rack(&rack_hdr->hvalue, &rseq, &cseq, &method); 
     456 
     457 
     458    /* Match RAck against outgoing transmission */ 
     459    if (rseq == dd->uas_state->tx_data_list.next->rseq && 
     460        cseq == dd->uas_state->cseq) 
     461    { 
     462        /*  
     463         * Yes this PRACK matches outgoing transmission. 
     464         */ 
     465        tx_data_list_t *tl = dd->uas_state->tx_data_list.next; 
     466 
     467        if (dd->uas_state->retransmit_timer.id) { 
     468            pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 
     469                                     &dd->uas_state->retransmit_timer); 
     470            dd->uas_state->retransmit_timer.id = PJ_FALSE; 
    283471        } 
    284         pj_list_init(&dd->uas_state->tx_data_list); 
    285 } 
    286  
    287  
    288 static void handle_incoming_prack(dlg_data *dd, pjsip_transaction *tsx, 
    289                                   pjsip_event *e) 
    290 { 
    291         pjsip_rx_data *rdata; 
    292         pjsip_msg *msg; 
    293         pjsip_generic_string_hdr *rack_hdr; 
    294         pjsip_tx_data *tdata; 
    295         pj_uint32_t rseq; 
    296         pj_int32_t cseq; 
    297         pj_str_t method; 
    298         pj_status_t status; 
    299  
    300  
    301         rdata = e->body.tsx_state.src.rdata; 
    302         msg = rdata->msg_info.msg; 
    303  
    304         /* Always reply with 200/OK for PRACK */ 
    305         status = pjsip_endpt_create_response(tsx->endpt, rdata,  
    306                                              200, NULL, &tdata); 
    307         if (status == PJ_SUCCESS) 
    308                 pjsip_tsx_send_msg(tsx, tdata); 
    309  
    310         /* Ignore if we don't have pending transmission */ 
    311         if (dd->uas_state == NULL || 
    312             pj_list_empty(&dd->uas_state->tx_data_list)) 
    313         { 
    314                 PJ_LOG(4,(dd->inv->dlg->obj_name,  
    315                           "PRACK ignored - no pending response")); 
    316                 return; 
     472 
     473        /* Remove from the list */ 
     474        if (tl != &dd->uas_state->tx_data_list) { 
     475            pj_list_erase(tl); 
     476 
     477            /* Destroy the response */ 
     478            pjsip_tx_data_dec_ref(tl->tdata); 
    317479        } 
    318480 
    319         /* Find RAck header */ 
    320         rack_hdr = (pjsip_generic_string_hdr*) 
    321                    pjsip_msg_find_hdr_by_name(msg, &RACK, NULL); 
    322         if (!rack_hdr) { 
    323                 /* RAck header not found */ 
    324                 PJ_LOG(4,(dd->inv->dlg->obj_name, "No RAck header")); 
    325                 return; 
     481        /* Schedule next packet */ 
     482        dd->uas_state->retransmit_count = 0; 
     483        if (!pj_list_empty(&dd->uas_state->tx_data_list)) { 
     484            on_retransmit(NULL, &dd->uas_state->retransmit_timer); 
    326485        } 
    327         parse_rack(&rack_hdr->hvalue, &rseq, &cseq, &method); 
    328  
    329         /* Match RAck against outgoing transmission */ 
    330         if (rseq == dd->uas_state->tx_data_list.next->rseq && 
    331             cseq == dd->uas_state->cseq) 
    332         { 
    333                 tx_data_list_t *tl = dd->uas_state->tx_data_list.next; 
    334  
    335                 /* Yes it match! */ 
    336                 if (dd->uas_state->retransmit_timer.id) { 
    337                         pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 
    338                                                  &dd->uas_state->retransmit_timer); 
    339                         dd->uas_state->retransmit_timer.id = PJ_FALSE; 
    340                 } 
    341  
    342                 /* Remove from the list */ 
    343                 if (tl != &dd->uas_state->tx_data_list) { 
    344                         pj_list_erase(tl); 
    345  
    346                         /* Destroy the response */ 
    347                         pjsip_tx_data_dec_ref(tl->tdata); 
    348                 } 
    349  
    350                 /* Schedule next packet */ 
    351                 dd->uas_state->retransmit_count = 0; 
    352                 if (!pj_list_empty(&dd->uas_state->tx_data_list)) { 
    353                         on_retransmit(NULL, &dd->uas_state->retransmit_timer); 
    354                 } 
    355  
    356         } else { 
    357                 /* No it doesn't match */ 
    358                 PJ_LOG(4,(dd->inv->dlg->obj_name,  
    359                          "Rx PRACK with no matching reliable response")); 
    360         } 
    361 } 
    362  
    363  
    364 /* 
    365  * Handle incoming provisional response with 100rel requirement. 
    366  * In this case we shall transmit PRACK request. 
    367  */ 
    368 static void handle_incoming_response(dlg_data *dd, pjsip_transaction *tsx, 
    369                                      pjsip_event *e) 
    370 { 
    371         pjsip_rx_data *rdata; 
    372         pjsip_msg *msg; 
    373         pjsip_generic_string_hdr *rseq_hdr; 
    374         pjsip_generic_string_hdr *rack_hdr; 
    375         unsigned rseq; 
    376         pj_str_t rack; 
    377         char rack_buf[80]; 
    378         pjsip_tx_data *tdata; 
    379         pj_status_t status; 
    380  
    381         rdata = e->body.tsx_state.src.rdata; 
    382         msg = rdata->msg_info.msg; 
    383  
    384         /* Check our assumptions */ 
    385         pj_assert( tsx->role == PJSIP_ROLE_UAC && 
    386                    tsx->method.id == PJSIP_INVITE_METHOD && 
    387                    e->type == PJSIP_EVENT_TSX_STATE && 
    388                    e->body.tsx_state.type == PJSIP_EVENT_RX_MSG &&  
    389                    msg->line.status.code > 100 && 
    390                    msg->line.status.code < 200); 
    391  
    392  
    393         /* Get the RSeq header */ 
    394         rseq_hdr = (pjsip_generic_string_hdr*) 
    395                    pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL); 
    396         if (rseq_hdr == NULL) { 
    397                 PJ_LOG(4,(dd->inv->dlg->obj_name,  
    398                          "Ignoring provisional response with no RSeq header")); 
    399                 return; 
    400         } 
    401         rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue); 
    402  
    403         /* Create new UAC state if we don't have one */ 
    404         if (dd->uac_state == NULL) { 
    405                 dd->uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool, 
    406                                                  uac_state_t); 
    407                 dd->uac_state->cseq = rdata->msg_info.cseq->cseq; 
    408                 dd->uac_state->rseq = rseq - 1; 
    409         } 
    410  
    411         /* If this is from new INVITE transaction, reset UAC state */ 
    412         if (rdata->msg_info.cseq->cseq != dd->uac_state->cseq) { 
    413                 dd->uac_state->cseq = rdata->msg_info.cseq->cseq; 
    414                 dd->uac_state->rseq = rseq - 1; 
    415         } 
    416  
    417         /* Ignore provisional response retransmission */ 
    418         if (rseq <= dd->uac_state->rseq) { 
    419                 /* This should have been handled before */ 
    420                 return; 
    421  
    422         /* Ignore provisional response with out-of-order RSeq */ 
    423         } else if (rseq != dd->uac_state->rseq + 1) { 
    424                 PJ_LOG(4,(dd->inv->dlg->obj_name,  
    425                          "Ignoring provisional response because RSeq jump " 
    426                          "(expecting %u, got %u)", 
    427                          dd->uac_state->rseq+1, rseq)); 
    428                 return; 
    429         } 
    430  
    431         /* Update our RSeq */ 
    432         dd->uac_state->rseq = rseq; 
    433  
    434         /* Create PRACK */ 
    435         status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method, 
    436                                           -1, &tdata); 
    437         if (status != PJ_SUCCESS) { 
    438                 PJ_LOG(4,(dd->inv->dlg->obj_name,  
    439                          "Error creating PRACK request (status=%d)", status)); 
    440                 return; 
    441         } 
    442  
    443         /* Create RAck header */ 
    444         rack.ptr = rack_buf; 
    445         rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf), 
    446                                      "%u %u %.*s", 
    447                                      rseq, rdata->msg_info.cseq->cseq, 
    448                                      (int)tsx->method.name.slen, 
    449                                      tsx->method.name.ptr); 
    450         PJ_ASSERT_ON_FAIL(rack.slen > 0 && rack.slen < (int)sizeof(rack_buf), 
    451                         { pjsip_tx_data_dec_ref(tdata); return; }); 
    452         rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack); 
    453         pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr); 
    454  
    455         /* Send PRACK */ 
    456         pjsip_dlg_send_request(dd->inv->dlg, tdata,  
    457                                mod_100rel.mod.id, (void*) dd); 
    458  
    459 } 
    460  
    461  
    462 /* 
    463  * API: init module 
    464  */ 
    465 PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt) 
    466 { 
    467         return pjsip_endpt_register_module(endpt, &mod_100rel.mod); 
    468 } 
    469  
    470  
    471 /* 
    472  * API: attach 100rel support in invite session. Called by 
    473  *      sip_inv.c 
    474  */ 
    475 PJ_DEF(pj_status_t) pjsip_100rel_attach(pjsip_inv_session *inv) 
    476 { 
    477         dlg_data *dd; 
    478  
    479         /* Check that 100rel module has been initialized */ 
    480         PJ_ASSERT_RETURN(mod_100rel.mod.id >= 0, PJ_EINVALIDOP); 
    481  
    482         /* Create and attach as dialog usage */ 
    483         dd = PJ_POOL_ZALLOC_T(inv->dlg->pool, dlg_data); 
    484         dd->inv = inv; 
    485         pjsip_dlg_add_usage(inv->dlg, &mod_100rel.mod, (void*)dd); 
    486  
    487         PJ_LOG(5,(dd->inv->dlg->obj_name, "100rel module attached")); 
    488  
    489         return PJ_SUCCESS; 
     486 
     487    } else { 
     488        /* No it doesn't match */ 
     489        PJ_LOG(4,(dd->inv->dlg->obj_name,  
     490                 "Rx PRACK with no matching reliable response")); 
     491        return PJ_EIGNORED; 
     492    } 
     493 
     494    return PJ_SUCCESS; 
    490495} 
    491496 
     
    498503                          struct pj_timer_entry *entry) 
    499504{ 
    500         dlg_data *dd; 
    501         tx_data_list_t *tl; 
    502         pjsip_tx_data *tdata; 
    503         pj_bool_t final; 
    504         pj_time_val delay; 
    505  
    506         PJ_UNUSED_ARG(timer_heap); 
    507  
    508         dd = (dlg_data*) entry->user_data; 
    509  
    510         entry->id = PJ_FALSE; 
    511  
    512         ++dd->uas_state->retransmit_count; 
    513         if (dd->uas_state->retransmit_count >= 7) { 
    514                 /* If a reliable provisional response is retransmitted for 
    515                    64*T1 seconds  without reception of a corresponding PRACK, 
    516                    the UAS SHOULD reject the original request with a 5xx  
    517                    response. 
    518                 */ 
    519                 pj_str_t reason = pj_str("Reliable response timed out"); 
    520                 pj_status_t status; 
    521  
    522                 /* Clear all pending responses */ 
    523                 clear_all_responses(dd); 
    524  
    525                 /* Send 500 response */ 
    526                 status = pjsip_inv_end_session(dd->inv, 500, &reason, &tdata); 
    527                 if (status == PJ_SUCCESS) { 
    528                         pjsip_dlg_send_response(dd->inv->dlg,  
    529                                                 dd->inv->invite_tsx, 
    530                                                 tdata); 
    531                 } 
    532                 return; 
     505    dlg_data *dd; 
     506    tx_data_list_t *tl; 
     507    pjsip_tx_data *tdata; 
     508    pj_bool_t final; 
     509    pj_time_val delay; 
     510 
     511    PJ_UNUSED_ARG(timer_heap); 
     512 
     513    dd = (dlg_data*) entry->user_data; 
     514 
     515    entry->id = PJ_FALSE; 
     516 
     517    ++dd->uas_state->retransmit_count; 
     518    if (dd->uas_state->retransmit_count >= 7) { 
     519        /* If a reliable provisional response is retransmitted for 
     520           64*T1 seconds  without reception of a corresponding PRACK, 
     521           the UAS SHOULD reject the original request with a 5xx  
     522           response. 
     523        */ 
     524        pj_str_t reason = pj_str("Reliable response timed out"); 
     525        pj_status_t status; 
     526 
     527        /* Clear all pending responses */ 
     528        clear_all_responses(dd); 
     529 
     530        /* Send 500 response */ 
     531        status = pjsip_inv_end_session(dd->inv, 500, &reason, &tdata); 
     532        if (status == PJ_SUCCESS) { 
     533            pjsip_dlg_send_response(dd->inv->dlg,  
     534                                    dd->inv->invite_tsx, 
     535                                    tdata); 
    533536        } 
    534  
    535         pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list)); 
    536         tl = dd->uas_state->tx_data_list.next; 
    537         tdata = tl->tdata; 
    538  
    539         pjsip_tx_data_add_ref(tdata); 
    540         final = tdata->msg->line.status.code >= 200; 
    541  
    542         if (dd->uas_state->retransmit_count == 1) { 
    543                 pjsip_tsx_send_msg(dd->inv->invite_tsx, tdata); 
    544         } else { 
    545                 pjsip_tsx_retransmit_no_state(dd->inv->invite_tsx, tdata); 
    546         } 
    547  
    548         if (final) { 
    549                 /* This is final response, which will be retransmitted by 
    550                  * UA layer. There's no more task to do, so clear the 
    551                  * transmission list and bail out. 
    552                  */ 
    553                 clear_all_responses(dd); 
    554                 return; 
    555         } 
    556  
    557         /* Schedule next retransmission */ 
    558         if (dd->uas_state->retransmit_count < 6) { 
    559                 delay.sec = 0; 
    560                 delay.msec = (1 << dd->uas_state->retransmit_count) *  
    561                              PJSIP_T1_TIMEOUT; 
    562                 pj_time_val_normalize(&delay); 
    563         } else { 
    564                 delay.sec = 1; 
    565                 delay.msec = 500; 
    566         } 
    567  
    568  
    569         pjsip_endpt_schedule_timer(dd->inv->dlg->endpt,  
    570                                    &dd->uas_state->retransmit_timer, 
    571                                    &delay); 
    572  
    573         entry->id = PJ_TRUE; 
    574 } 
     537        return; 
     538    } 
     539 
     540    pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list)); 
     541    tl = dd->uas_state->tx_data_list.next; 
     542    tdata = tl->tdata; 
     543 
     544    pjsip_tx_data_add_ref(tdata); 
     545    final = tdata->msg->line.status.code >= 200; 
     546 
     547    if (dd->uas_state->retransmit_count == 1) { 
     548        pjsip_tsx_send_msg(dd->inv->invite_tsx, tdata); 
     549    } else { 
     550        pjsip_tsx_retransmit_no_state(dd->inv->invite_tsx, tdata); 
     551    } 
     552 
     553    if (final) { 
     554        /* This is final response, which will be retransmitted by 
     555         * UA layer. There's no more task to do, so clear the 
     556         * transmission list and bail out. 
     557         */ 
     558        clear_all_responses(dd); 
     559        return; 
     560    } 
     561 
     562    /* Schedule next retransmission */ 
     563    if (dd->uas_state->retransmit_count < 6) { 
     564        delay.sec = 0; 
     565        delay.msec = (1 << dd->uas_state->retransmit_count) *  
     566                     PJSIP_T1_TIMEOUT; 
     567        pj_time_val_normalize(&delay); 
     568    } else { 
     569        delay.sec = 1; 
     570        delay.msec = 500; 
     571    } 
     572 
     573 
     574    pjsip_endpt_schedule_timer(dd->inv->dlg->endpt,  
     575                               &dd->uas_state->retransmit_timer, 
     576                               &delay); 
     577 
     578    entry->id = PJ_TRUE; 
     579} 
     580 
    575581 
    576582/* Clone response. */ 
     
    578584                                  const pjsip_tx_data *src) 
    579585{ 
    580         pjsip_tx_data *dst; 
    581         const pjsip_hdr *hsrc; 
    582         pjsip_msg *msg; 
    583         pj_status_t status; 
    584  
    585         status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst); 
    586         if (status != PJ_SUCCESS) 
    587                 return NULL; 
    588  
    589         msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG); 
    590         dst->msg = msg; 
    591         pjsip_tx_data_add_ref(dst); 
    592  
    593         /* Duplicate status line */ 
    594         msg->line.status.code = src->msg->line.status.code; 
    595         pj_strdup(dst->pool, &msg->line.status.reason,  
    596                   &src->msg->line.status.reason); 
    597  
    598         /* Duplicate all headers */ 
    599         hsrc = src->msg->hdr.next; 
    600         while (hsrc != &src->msg->hdr) { 
    601                 pjsip_hdr *h = (pjsip_hdr*) pjsip_hdr_clone(dst->pool, hsrc); 
    602                 pjsip_msg_add_hdr(msg, h); 
    603                 hsrc = hsrc->next; 
    604         } 
    605  
    606         /* Duplicate message body */ 
    607         if (src->msg->body) 
    608                 msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body); 
    609  
    610         PJ_LOG(5,(dd->inv->dlg->obj_name, 
    611                  "Reliable response %s created", 
    612                  pjsip_tx_data_get_info(dst))); 
    613  
    614         return dst; 
    615 } 
    616  
    617 /* Check if pending response has SDP */ 
     586    pjsip_tx_data *dst; 
     587    const pjsip_hdr *hsrc; 
     588    pjsip_msg *msg; 
     589    pj_status_t status; 
     590 
     591    status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst); 
     592    if (status != PJ_SUCCESS) 
     593        return NULL; 
     594 
     595    msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG); 
     596    dst->msg = msg; 
     597    pjsip_tx_data_add_ref(dst); 
     598 
     599    /* Duplicate status line */ 
     600    msg->line.status.code = src->msg->line.status.code; 
     601    pj_strdup(dst->pool, &msg->line.status.reason,  
     602              &src->msg->line.status.reason); 
     603 
     604    /* Duplicate all headers */ 
     605    hsrc = src->msg->hdr.next; 
     606    while (hsrc != &src->msg->hdr) { 
     607        pjsip_hdr *h = (pjsip_hdr*) pjsip_hdr_clone(dst->pool, hsrc); 
     608        pjsip_msg_add_hdr(msg, h); 
     609        hsrc = hsrc->next; 
     610    } 
     611 
     612    /* Duplicate message body */ 
     613    if (src->msg->body) 
     614        msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body); 
     615 
     616    PJ_LOG(5,(dd->inv->dlg->obj_name, 
     617             "Reliable response %s created", 
     618             pjsip_tx_data_get_info(dst))); 
     619 
     620    return dst; 
     621} 
     622 
     623 
     624/* Check if any pending response in transmission list has SDP */ 
    618625static pj_bool_t has_sdp(dlg_data *dd) 
    619626{ 
    620         tx_data_list_t *tl; 
    621  
    622         tl = dd->uas_state->tx_data_list.next; 
    623         while (tl != &dd->uas_state->tx_data_list) { 
    624                 if (tl->tdata->msg->body) 
    625                         return PJ_TRUE; 
    626                 tl = tl->next; 
    627         } 
    628  
    629         return PJ_FALSE; 
     627    tx_data_list_t *tl; 
     628 
     629    tl = dd->uas_state->tx_data_list.next; 
     630    while (tl != &dd->uas_state->tx_data_list) { 
     631            if (tl->tdata->msg->body) 
     632                    return PJ_TRUE; 
     633            tl = tl->next; 
     634    } 
     635 
     636    return PJ_FALSE; 
    630637} 
    631638 
     
    635642                                             pjsip_tx_data *tdata) 
    636643{ 
    637         pjsip_cseq_hdr *cseq_hdr; 
    638         pjsip_generic_string_hdr *rseq_hdr; 
    639         pjsip_require_hdr *req_hdr; 
    640         int status_code; 
    641         dlg_data *dd; 
    642         pjsip_tx_data *old_tdata; 
    643         pj_status_t status; 
    644  
    645         PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG, 
     644    pjsip_cseq_hdr *cseq_hdr; 
     645    pjsip_generic_string_hdr *rseq_hdr; 
     646    pjsip_require_hdr *req_hdr; 
     647    int status_code; 
     648    dlg_data *dd; 
     649    pjsip_tx_data *old_tdata; 
     650    pj_status_t status; 
     651     
     652    PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG, 
     653                     PJSIP_ENOTRESPONSEMSG); 
     654     
     655    status_code = tdata->msg->line.status.code; 
     656     
     657    /* 100 response doesn't need PRACK */ 
     658    if (status_code == 100) 
     659        return pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata); 
     660     
     661 
     662    /* Get the 100rel data attached to this dialog */ 
     663    dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 
     664    PJ_ASSERT_RETURN(dd != NULL, PJ_EINVALIDOP); 
     665     
     666     
     667    /* Clone tdata. 
     668     * We need to clone tdata because we may need to keep it in our 
     669     * retransmission list, while the original dialog may modify it 
     670     * if it wants to send another response. 
     671     */ 
     672    old_tdata = tdata; 
     673    tdata = clone_tdata(dd, old_tdata); 
     674    pjsip_tx_data_dec_ref(old_tdata); 
     675     
     676 
     677    /* Get CSeq header, and make sure this is INVITE response */ 
     678    cseq_hdr = (pjsip_cseq_hdr*) 
     679                pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); 
     680    PJ_ASSERT_RETURN(cseq_hdr != NULL, PJ_EBUG); 
     681    PJ_ASSERT_RETURN(cseq_hdr->method.id == PJSIP_INVITE_METHOD,  
     682        PJ_EINVALIDOP); 
     683     
     684    /* Remove existing Require header */ 
     685    req_hdr = find_req_hdr(tdata->msg); 
     686    if (req_hdr) { 
     687        pj_list_erase(req_hdr); 
     688    } 
     689     
     690    /* Remove existing RSeq header */ 
     691    rseq_hdr = (pjsip_generic_string_hdr*) 
     692        pjsip_msg_find_hdr_by_name(tdata->msg, &RSEQ, NULL); 
     693    if (rseq_hdr) 
     694        pj_list_erase(rseq_hdr); 
     695     
     696    /* Different treatment for provisional and final response */ 
     697    if (status_code/100 == 2) { 
     698         
     699        /* RFC 3262 Section 3: UAS Behavior: 
     700     
     701          The UAS MAY send a final response to the initial request  
     702          before having received PRACKs for all unacknowledged  
     703          reliable provisional responses, unless the final response  
     704          is 2xx and any of the unacknowledged reliable provisional  
     705          responses contained a session description.  In that case,  
     706          it MUST NOT send a final response until those provisional  
     707          responses are acknowledged. 
     708        */ 
     709         
     710        if (dd->uas_state && has_sdp(dd)) { 
     711            /* Yes we have transmitted 1xx with SDP reliably. 
     712             * In this case, must queue the 2xx response. 
     713             */ 
     714            tx_data_list_t *tl; 
     715             
     716            tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t); 
     717            tl->tdata = tdata; 
     718            tl->rseq = (pj_uint32_t)-1; 
     719            pj_list_push_back(&dd->uas_state->tx_data_list, tl); 
     720             
     721            /* Will send later */ 
     722            status = PJ_SUCCESS; 
     723             
     724            PJ_LOG(4,(dd->inv->dlg->obj_name,  
     725                      "2xx response will be sent after PRACK")); 
     726             
     727        } else if (dd->uas_state) { 
     728            /*  
     729            RFC 3262 Section 3: UAS Behavior: 
     730 
     731            If the UAS does send a final response when reliable 
     732            responses are still unacknowledged, it SHOULD NOT  
     733            continue to retransmit the unacknowledged reliable 
     734            provisional responses, but it MUST be prepared to  
     735            process PRACK requests for those outstanding  
     736            responses. 
     737            */ 
     738             
     739            PJ_LOG(4,(dd->inv->dlg->obj_name,  
     740                      "No SDP sent so far, sending 2xx now")); 
     741             
     742            /* Cancel the retransmit timer */ 
     743            if (dd->uas_state->retransmit_timer.id) { 
     744                pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 
     745                                         &dd->uas_state->retransmit_timer); 
     746                dd->uas_state->retransmit_timer.id = PJ_FALSE; 
     747            } 
     748             
     749            /* Clear all pending responses (drop 'em) */ 
     750            clear_all_responses(dd); 
     751             
     752            /* And transmit the 2xx response */ 
     753            status=pjsip_dlg_send_response(inv->dlg,  
     754                                           inv->invite_tsx, tdata); 
     755             
     756        } else { 
     757            /* We didn't send any reliable provisional response */ 
     758             
     759            /* Transmit the 2xx response */ 
     760            status=pjsip_dlg_send_response(inv->dlg,  
     761                                           inv->invite_tsx, tdata); 
     762        } 
     763         
     764    } else if (status_code >= 300) { 
     765         
     766        /*  
     767        RFC 3262 Section 3: UAS Behavior: 
     768 
     769        If the UAS does send a final response when reliable 
     770        responses are still unacknowledged, it SHOULD NOT  
     771        continue to retransmit the unacknowledged reliable 
     772        provisional responses, but it MUST be prepared to  
     773        process PRACK requests for those outstanding  
     774        responses. 
     775        */ 
     776         
     777        /* Cancel the retransmit timer */ 
     778        if (dd->uas_state && dd->uas_state->retransmit_timer.id) { 
     779            pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 
     780                                     &dd->uas_state->retransmit_timer); 
     781            dd->uas_state->retransmit_timer.id = PJ_FALSE; 
     782             
     783            /* Clear all pending responses (drop 'em) */ 
     784            clear_all_responses(dd); 
     785        } 
     786         
     787        /* And transmit the 2xx response */ 
     788        status=pjsip_dlg_send_response(inv->dlg,  
     789                                       inv->invite_tsx, tdata); 
     790         
     791    } else { 
     792        /* 
     793         * This is provisional response. 
     794         */ 
     795        char rseq_str[32]; 
     796        pj_str_t rseq; 
     797        tx_data_list_t *tl; 
     798         
     799        /* Create UAS state if we don't have one */ 
     800        if (dd->uas_state == NULL) { 
     801            dd->uas_state = PJ_POOL_ZALLOC_T(inv->dlg->pool, 
     802                                             uas_state_t); 
     803            dd->uas_state->cseq = cseq_hdr->cseq; 
     804            dd->uas_state->rseq = pj_rand() % 0x7FFF; 
     805            pj_list_init(&dd->uas_state->tx_data_list); 
     806            dd->uas_state->retransmit_timer.user_data = dd; 
     807            dd->uas_state->retransmit_timer.cb = &on_retransmit; 
     808        } 
     809         
     810        /* Check that CSeq match */ 
     811        PJ_ASSERT_RETURN(cseq_hdr->cseq == dd->uas_state->cseq, 
    646812                         PJ_EINVALIDOP); 
    647  
    648         status_code = tdata->msg->line.status.code; 
    649  
    650         /* 100 response doesn't need PRACK */ 
    651         if (status_code == 100) 
    652                 return pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata); 
    653  
    654         /* Get the dialog data */ 
    655         dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 
    656         PJ_ASSERT_RETURN(dd != NULL, PJ_EINVALIDOP); 
    657  
    658  
    659         /* Clone tdata */ 
    660         old_tdata = tdata; 
    661         tdata = clone_tdata(dd, old_tdata); 
    662         pjsip_tx_data_dec_ref(old_tdata); 
    663  
    664         /* Get CSeq header */ 
    665         cseq_hdr = (pjsip_cseq_hdr*) 
    666                    pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); 
    667         PJ_ASSERT_RETURN(cseq_hdr != NULL, PJ_EBUG); 
    668         PJ_ASSERT_RETURN(cseq_hdr->method.id == PJSIP_INVITE_METHOD,  
    669                          PJ_EINVALIDOP); 
    670  
    671         /* Remove existing Require header */ 
    672         req_hdr = find_req_hdr(tdata->msg); 
    673         if (req_hdr) { 
    674                 pj_list_erase(req_hdr); 
     813         
     814        /* Add Require header */ 
     815        req_hdr = pjsip_require_hdr_create(tdata->pool); 
     816        req_hdr->count = 1; 
     817        req_hdr->values[0] = tag_100rel; 
     818        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr); 
     819         
     820        /* Add RSeq header */ 
     821        pj_ansi_snprintf(rseq_str, sizeof(rseq_str), "%u", 
     822                         dd->uas_state->rseq); 
     823        rseq = pj_str(rseq_str); 
     824        rseq_hdr = pjsip_generic_string_hdr_create(tdata->pool,  
     825                                                   &RSEQ, &rseq); 
     826        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)rseq_hdr); 
     827         
     828        /* Create list entry for this response */ 
     829        tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t); 
     830        tl->tdata = tdata; 
     831        tl->rseq = dd->uas_state->rseq++; 
     832         
     833        /* Add to queue if there's pending response, otherwise 
     834         * transmit immediately. 
     835         */ 
     836        if (!pj_list_empty(&dd->uas_state->tx_data_list)) { 
     837             
     838            int code = tdata->msg->line.status.code; 
     839             
     840            /* Will send later */ 
     841            pj_list_push_back(&dd->uas_state->tx_data_list, tl); 
     842            status = PJ_SUCCESS; 
     843             
     844            PJ_LOG(4,(dd->inv->dlg->obj_name,  
     845                      "Reliable %d response enqueued (%d pending)",  
     846                      code, pj_list_size(&dd->uas_state->tx_data_list))); 
     847             
     848        } else { 
     849            pj_list_push_back(&dd->uas_state->tx_data_list, tl); 
     850             
     851            dd->uas_state->retransmit_count = 0; 
     852            on_retransmit(NULL, &dd->uas_state->retransmit_timer); 
     853            status = PJ_SUCCESS; 
    675854        } 
    676  
    677         /* Remove existing RSeq header */ 
    678         rseq_hdr = (pjsip_generic_string_hdr*) 
    679                    pjsip_msg_find_hdr_by_name(tdata->msg, &RSEQ, NULL); 
    680         if (rseq_hdr) 
    681                 pj_list_erase(rseq_hdr); 
    682  
    683         /* Different treatment for provisional and final response */ 
    684         if (status_code/100 == 2) { 
    685  
    686                 /* RFC 3262 Section 3: UAS Behavior: 
    687  
    688                 The UAS MAY send a final response to the initial request  
    689                 before having received PRACKs for all unacknowledged  
    690                 reliable provisional responses, unless the final response  
    691                 is 2xx and any of the unacknowledged reliable provisional  
    692                 responses contained a session description.  In that case,  
    693                 it MUST NOT send a final response until those provisional  
    694                 responses are acknowledged. 
    695                 */ 
    696  
    697                 if (dd->uas_state && has_sdp(dd)) { 
    698                         /* Yes we have transmitted 1xx with SDP reliably. 
    699                          * In this case, must queue the 2xx response. 
    700                          */ 
    701                         tx_data_list_t *tl; 
    702  
    703                         tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t); 
    704                         tl->tdata = tdata; 
    705                         tl->rseq = (pj_uint32_t)-1; 
    706                         pj_list_push_back(&dd->uas_state->tx_data_list, tl); 
    707  
    708                         /* Will send later */ 
    709                         status = PJ_SUCCESS; 
    710  
    711                         PJ_LOG(4,(dd->inv->dlg->obj_name,  
    712                                   "2xx response will be sent after PRACK")); 
    713  
    714                 } else if (dd->uas_state) { 
    715                         /*  
    716                         If the UAS does send a final response when reliable 
    717                         responses are still unacknowledged, it SHOULD NOT  
    718                         continue to retransmit the unacknowledged reliable 
    719                         provisional responses, but it MUST be prepared to  
    720                         process PRACK requests for those outstanding  
    721                         responses. 
    722                         */ 
    723                          
    724                         PJ_LOG(4,(dd->inv->dlg->obj_name,  
    725                                   "No SDP sent so far, sending 2xx now")); 
    726  
    727                         /* Cancel the retransmit timer */ 
    728                         if (dd->uas_state->retransmit_timer.id) { 
    729                                 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 
    730                                                          &dd->uas_state->retransmit_timer); 
    731                                 dd->uas_state->retransmit_timer.id = PJ_FALSE; 
    732                         } 
    733  
    734                         /* Clear all pending responses (drop 'em) */ 
    735                         clear_all_responses(dd); 
    736  
    737                         /* And transmit the 2xx response */ 
    738                         status=pjsip_dlg_send_response(inv->dlg,  
    739                                                        inv->invite_tsx, tdata); 
    740  
    741                 } else { 
    742                         /* We didn't send any reliable provisional response */ 
    743  
    744                         /* Transmit the 2xx response */ 
    745                         status=pjsip_dlg_send_response(inv->dlg,  
    746                                                        inv->invite_tsx, tdata); 
    747                 } 
    748  
    749         } else if (status_code >= 300) { 
    750  
    751                 /*  
    752                 If the UAS does send a final response when reliable 
    753                 responses are still unacknowledged, it SHOULD NOT  
    754                 continue to retransmit the unacknowledged reliable 
    755                 provisional responses, but it MUST be prepared to  
    756                 process PRACK requests for those outstanding  
    757                 responses. 
    758                 */ 
    759  
    760                 /* Cancel the retransmit timer */ 
    761                 if (dd->uas_state && dd->uas_state->retransmit_timer.id) { 
    762                         pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 
    763                                                  &dd->uas_state->retransmit_timer); 
    764                         dd->uas_state->retransmit_timer.id = PJ_FALSE; 
    765  
    766                         /* Clear all pending responses (drop 'em) */ 
    767                         clear_all_responses(dd); 
    768                 } 
    769  
    770                 /* And transmit the 2xx response */ 
    771                 status=pjsip_dlg_send_response(inv->dlg,  
    772                                                inv->invite_tsx, tdata); 
    773  
    774         } else { 
    775                 /* 
    776                  * This is provisional response. 
    777                  */ 
    778                 char rseq_str[32]; 
    779                 pj_str_t rseq; 
    780                 tx_data_list_t *tl; 
    781  
    782                 /* Create UAS state if we don't have one */ 
    783                 if (dd->uas_state == NULL) { 
    784                         dd->uas_state = PJ_POOL_ZALLOC_T(inv->dlg->pool, 
    785                                                          uas_state_t); 
    786                         dd->uas_state->cseq = cseq_hdr->cseq; 
    787                         dd->uas_state->rseq = pj_rand() % 0x7FFF; 
    788                         pj_list_init(&dd->uas_state->tx_data_list); 
    789                         dd->uas_state->retransmit_timer.user_data = dd; 
    790                         dd->uas_state->retransmit_timer.cb = &on_retransmit; 
    791                 } 
    792  
    793                 /* Check that CSeq match */ 
    794                 PJ_ASSERT_RETURN(cseq_hdr->cseq == dd->uas_state->cseq, 
    795                                  PJ_EINVALIDOP); 
    796  
    797                 /* Add Require header */ 
    798                 req_hdr = pjsip_require_hdr_create(tdata->pool); 
    799                 req_hdr->count = 1; 
    800                 req_hdr->values[0] = tag_100rel; 
    801                 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr); 
    802  
    803                 /* Add RSeq header */ 
    804                 pj_ansi_snprintf(rseq_str, sizeof(rseq_str), "%u", 
    805                                  dd->uas_state->rseq); 
    806                 rseq = pj_str(rseq_str); 
    807                 rseq_hdr = pjsip_generic_string_hdr_create(tdata->pool,  
    808                                                            &RSEQ, &rseq); 
    809                 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)rseq_hdr); 
    810  
    811                 /* Create list entry for this response */ 
    812                 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t); 
    813                 tl->tdata = tdata; 
    814                 tl->rseq = dd->uas_state->rseq++; 
    815  
    816                 /* Add to queue if there's pending response, otherwise 
    817                  * transmit immediately. 
    818                  */ 
    819                 if (!pj_list_empty(&dd->uas_state->tx_data_list)) { 
    820                          
    821                         int code = tdata->msg->line.status.code; 
    822  
    823                         /* Will send later */ 
    824                         pj_list_push_back(&dd->uas_state->tx_data_list, tl); 
    825                         status = PJ_SUCCESS; 
    826  
    827                         PJ_LOG(4,(dd->inv->dlg->obj_name,  
    828                                   "Reliable %d response enqueued (%d pending)",  
    829                                   code, pj_list_size(&dd->uas_state->tx_data_list))); 
    830  
    831                 } else { 
    832                         pj_list_push_back(&dd->uas_state->tx_data_list, tl); 
    833  
    834                         dd->uas_state->retransmit_count = 0; 
    835                         on_retransmit(NULL, &dd->uas_state->retransmit_timer); 
    836                         status = PJ_SUCCESS; 
    837                 } 
    838  
    839         } 
    840  
    841         return status; 
    842 } 
    843  
    844  
    845 #endif  /* PJSIP_HAS_100REL */ 
     855         
     856    } 
     857     
     858    return status; 
     859} 
     860 
     861 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c

    r1463 r1469  
    3232#include <pj/log.h> 
    3333 
     34/*  
     35 * Note on offer/answer: 
     36 * 
     37 * The offer/answer framework in this implementation assumes the occurence 
     38 * of SDP in a particular request/response according to this table: 
     39 
     40                  offer   answer    Note: 
     41    ======================================================================== 
     42    INVITE          X               INVITE may contain offer 
     43    18x/INVITE      X       X       Response may contain offer or answer 
     44    2xx/INVITE      X       X       Response may contain offer or answer 
     45    ACK                     X       ACK may contain answer 
     46 
     47    PRACK                   X       PRACK can only contain answer 
     48    2xx/PRACK                       Response may not have offer nor answer 
     49 
     50    UPDATE          X               UPDATE may only contain offer 
     51    2xx/UPDATE              X       Response may only contain answer 
     52    ======================================================================== 
     53 
     54  * 
     55  */ 
    3456 
    3557#define THIS_FILE       "sip_inv.c" 
     
    4769}; 
    4870 
     71/* UPDATE method */ 
     72const pjsip_method pjsip_update_method = 
     73{ 
     74    PJSIP_OTHER_METHOD, 
     75    { "UPDATE", 6 } 
     76}; 
     77 
    4978/* 
    5079 * Static prototypes. 
     
    6796                                                  pjsip_transaction *tsx, 
    6897                                                  pjsip_rx_data *rdata); 
     98static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv ); 
     99static pjsip_msg_body *create_sdp_body(pj_pool_t *pool, 
     100                                       const pjmedia_sdp_session *c_sdp); 
    69101static pj_status_t process_answer( pjsip_inv_session *inv, 
    70102                                   int st_code, 
     
    120152static pj_status_t mod_inv_load(pjsip_endpoint *endpt) 
    121153{ 
    122     pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6}}; 
     154    pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6}, 
     155                            { "UPDATE", 6}}; 
    123156    pj_str_t accepted = { "application/sdp", 15 }; 
    124157 
    125     /* Register supported methods: INVITE, ACK, BYE, CANCEL */ 
     158    /* Register supported methods: INVITE, ACK, BYE, CANCEL, UPDATE */ 
    126159    pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ALLOW, NULL, 
    127160                               PJ_ARRAY_SIZE(allowed), allowed); 
     
    187220        prev_state != PJSIP_INV_STATE_DISCONNECTED)  
    188221    { 
     222        if (inv->last_ack) { 
     223            pjsip_tx_data_dec_ref(inv->last_ack); 
     224            inv->last_ack = NULL; 
     225        } 
     226        pjsip_100rel_end_session(inv); 
    189227        pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod); 
    190228    } 
     
    210248 
    211249 
     250/* 
     251 * Check if outgoing request needs to have SDP answer. 
     252 * This applies for both ACK and PRACK requests. 
     253 */ 
     254static pjmedia_sdp_session *inv_has_pending_answer(pjsip_inv_session *inv, 
     255                                                   pjsip_transaction *tsx) 
     256{ 
     257    pjmedia_sdp_neg_state neg_state; 
     258    pjmedia_sdp_session *sdp = NULL; 
     259    pj_status_t status; 
     260 
     261    /* If SDP negotiator is ready, start negotiation. */ 
     262 
     263    /* Start nego when appropriate. */ 
     264    neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) : 
     265                PJMEDIA_SDP_NEG_STATE_NULL; 
     266 
     267    if (neg_state == PJMEDIA_SDP_NEG_STATE_DONE) { 
     268 
     269        /* Nothing to do */ 
     270 
     271    } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO && 
     272               pjmedia_sdp_neg_has_local_answer(inv->neg) ) 
     273    { 
     274        struct tsx_inv_data *tsx_inv_data; 
     275 
     276        /* Get invite session's transaction data */ 
     277        tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id]; 
     278 
     279        status = inv_negotiate_sdp(inv); 
     280        if (status != PJ_SUCCESS) 
     281            return NULL; 
     282         
     283        /* Mark this transaction has having SDP offer/answer done. */ 
     284        tsx_inv_data->sdp_done = 1; 
     285 
     286        status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp); 
     287 
     288    } else { 
     289        /* This remark is only valid for ACK. 
     290        PJ_LOG(4,(inv->dlg->obj_name, 
     291                  "FYI, the SDP negotiator state (%s) is in a mess " 
     292                  "when sending this ACK/PRACK request", 
     293                  pjmedia_sdp_neg_state_str(neg_state))); 
     294         */ 
     295    } 
     296 
     297    return sdp; 
     298} 
     299 
    212300 
    213301/* 
     
    216304static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_rx_data *rdata) 
    217305{ 
    218     pjsip_tx_data *tdata; 
    219306    pj_status_t status; 
    220307 
     
    222309              pjsip_rx_data_get_info(rdata))); 
    223310 
    224     status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),  
    225                                       rdata->msg_info.cseq->cseq, &tdata); 
    226     if (status != PJ_SUCCESS) { 
    227         /* Better luck next time */ 
    228         pj_assert(!"Unable to create ACK!"); 
    229         return status; 
    230     } 
    231  
    232     status = pjsip_dlg_send_request(inv->dlg, tdata, -1, NULL); 
     311    /* Check if we have cached ACK request */ 
     312    if (inv->last_ack && rdata->msg_info.cseq->cseq == inv->last_ack_cseq) { 
     313        pjsip_tx_data_add_ref(inv->last_ack); 
     314    } else { 
     315        pjmedia_sdp_session *sdp = NULL; 
     316 
     317        /* Destroy last_ack */ 
     318        if (inv->last_ack) { 
     319            pjsip_tx_data_dec_ref(inv->last_ack); 
     320            inv->last_ack = NULL; 
     321        } 
     322 
     323        /* Create new ACK request */ 
     324        status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),  
     325                                          rdata->msg_info.cseq->cseq,  
     326                                          &inv->last_ack); 
     327        if (status != PJ_SUCCESS) { 
     328            /* Better luck next time */ 
     329            pj_assert(!"Unable to create ACK!"); 
     330            return status; 
     331        } 
     332 
     333        /* See if we have pending SDP answer to send */ 
     334        sdp = inv_has_pending_answer(inv, inv->invite_tsx); 
     335        if (sdp) { 
     336            inv->last_ack->msg->body=create_sdp_body(inv->last_ack->pool, sdp); 
     337        } 
     338 
     339 
     340        /* Keep this for subsequent response retransmission */ 
     341        inv->last_ack_cseq = rdata->msg_info.cseq->cseq; 
     342        pjsip_tx_data_add_ref(inv->last_ack); 
     343    } 
     344 
     345    /* Send ACK */ 
     346    status = pjsip_dlg_send_request(inv->dlg, inv->last_ack, -1, NULL); 
    233347    if (status != PJ_SUCCESS) { 
    234348        /* Better luck next time */ 
     
    493607        options |= PJSIP_INV_SUPPORT_100REL; 
    494608 
    495 #if !PJSIP_HAS_100REL 
    496     /* options cannot specify 100rel if 100rel is disabled */ 
    497     PJ_ASSERT_RETURN( 
    498         (options & (PJSIP_INV_REQUIRE_100REL | PJSIP_INV_SUPPORT_100REL))==0, 
    499         PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_EXTENSION)); 
    500      
    501 #endif 
    502  
    503609    if (options & PJSIP_INV_REQUIRE_TIMER) 
    504610        options |= PJSIP_INV_SUPPORT_TIMER; 
     
    539645    pjsip_dlg_inc_session(dlg, &mod_inv.mod); 
    540646 
    541 #if PJSIP_HAS_100REL 
    542647    /* Create 100rel handler */ 
    543648    pjsip_100rel_attach(inv); 
    544 #endif 
    545649 
    546650    /* Done */ 
     
    9441048        options |= PJSIP_INV_SUPPORT_100REL; 
    9451049 
    946 #if !PJSIP_HAS_100REL 
    947     /* options cannot specify 100rel if 100rel is disabled */ 
    948     PJ_ASSERT_RETURN( 
    949         (options & (PJSIP_INV_REQUIRE_100REL | PJSIP_INV_SUPPORT_100REL))==0, 
    950         PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_EXTENSION)); 
    951      
    952 #endif 
    953  
    9541050    if (options & PJSIP_INV_REQUIRE_TIMER) 
    9551051        options |= PJSIP_INV_SUPPORT_TIMER; 
     
    10211117    inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data; 
    10221118 
    1023 #if PJSIP_HAS_100REL 
    10241119    /* Create 100rel handler */ 
    10251120    if (inv->options & PJSIP_INV_REQUIRE_100REL) { 
    10261121            pjsip_100rel_attach(inv); 
    10271122    } 
    1028 #endif 
    10291123 
    10301124    /* Done */ 
     
    12401334 
    12411335/* 
    1242  * Negotiate SDP. 
     1336 * Initiate SDP negotiation in the SDP negotiator. 
    12431337 */ 
    12441338static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv ) 
     
    17821876PJ_DEF(pj_status_t) pjsip_inv_update (  pjsip_inv_session *inv, 
    17831877                                        const pj_str_t *new_contact, 
    1784                                         const pjmedia_sdp_session *new_offer, 
     1878                                        const pjmedia_sdp_session *offer, 
    17851879                                        pjsip_tx_data **p_tdata ) 
    17861880{ 
    1787     PJ_UNUSED_ARG(inv); 
    1788     PJ_UNUSED_ARG(new_contact); 
    1789     PJ_UNUSED_ARG(new_offer); 
    1790     PJ_UNUSED_ARG(p_tdata); 
    1791  
    1792     PJ_TODO(CREATE_UPDATE_REQUEST); 
    1793     return PJ_ENOTSUP; 
     1881    pjsip_contact_hdr *contact_hdr = NULL; 
     1882    pjsip_tx_data *tdata = NULL; 
     1883    pjmedia_sdp_session *sdp_copy; 
     1884    pj_status_t status = PJ_SUCCESS; 
     1885 
     1886    /* Verify arguments. */ 
     1887    PJ_ASSERT_RETURN(inv && p_tdata && offer, PJ_EINVAL); 
     1888 
     1889    /* Dialog must have been established */ 
     1890    PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED, 
     1891                     PJ_EINVALIDOP); 
     1892 
     1893    /* Invite session must not have been disconnected */ 
     1894    PJ_ASSERT_RETURN(inv->state < PJSIP_INV_STATE_DISCONNECTED, 
     1895                     PJ_EINVALIDOP); 
     1896 
     1897    /* Lock dialog. */ 
     1898    pjsip_dlg_inc_lock(inv->dlg); 
     1899 
     1900    /* Process offer */ 
     1901    if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) { 
     1902        PJ_LOG(4,(inv->dlg->obj_name,  
     1903                  "Invalid SDP offer/answer state for UPDATE")); 
     1904        status = PJ_EINVALIDOP; 
     1905        goto on_error; 
     1906    } 
     1907 
     1908    status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg, 
     1909                                                offer); 
     1910    if (status != PJ_SUCCESS) 
     1911        goto on_error; 
     1912 
     1913 
     1914    /* Update Contact if required */ 
     1915    if (new_contact) { 
     1916        pj_str_t tmp; 
     1917        const pj_str_t STR_CONTACT = { "Contact", 7 }; 
     1918 
     1919        pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact); 
     1920        contact_hdr = (pjsip_contact_hdr*) 
     1921                      pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,  
     1922                                      tmp.ptr, tmp.slen, NULL); 
     1923        if (!contact_hdr) { 
     1924            status = PJSIP_EINVALIDURI; 
     1925            goto on_error; 
     1926        } 
     1927 
     1928        inv->dlg->local.contact = contact_hdr; 
     1929    } 
     1930 
     1931    /* Create request */ 
     1932    status = pjsip_dlg_create_request(inv->dlg, &pjsip_update_method, 
     1933                                      -1, &tdata); 
     1934    if (status != PJ_SUCCESS) 
     1935            goto on_error; 
     1936 
     1937    /* Attach SDP body */ 
     1938    sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer); 
     1939    pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body); 
     1940 
     1941    /* Unlock dialog. */ 
     1942    pjsip_dlg_dec_lock(inv->dlg); 
     1943 
     1944    *p_tdata = tdata; 
     1945 
     1946    return PJ_SUCCESS; 
     1947 
     1948on_error: 
     1949    if (tdata) 
     1950        pjsip_tx_data_dec_ref(tdata); 
     1951 
     1952    /* Unlock dialog. */ 
     1953    pjsip_dlg_dec_lock(inv->dlg); 
     1954 
     1955    return status; 
    17941956} 
    17951957 
     
    18331995                         PJ_EINVALIDOP); 
    18341996 
    1835 #if PJSIP_HAS_100REL 
    18361997        if (inv->options & PJSIP_INV_REQUIRE_100REL) { 
    1837                 status = pjsip_100rel_tx_response(inv, tdata); 
     1998            status = pjsip_100rel_tx_response(inv, tdata); 
    18381999        } else  
    1839 #endif 
    18402000        { 
    1841                 status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata); 
     2001            status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata); 
    18422002        } 
    18432003 
     
    19882148 
    19892149/* 
     2150 * Respond to incoming UPDATE request. 
     2151 */ 
     2152static void inv_respond_incoming_update(pjsip_inv_session *inv, 
     2153                                        pjsip_rx_data *rdata) 
     2154{ 
     2155    pjmedia_sdp_neg_state neg_state; 
     2156    pj_status_t status; 
     2157    pjsip_tx_data *tdata = NULL; 
     2158 
     2159    neg_state = pjmedia_sdp_neg_get_state(inv->neg); 
     2160 
     2161    /* Send 491 if we receive UPDATE while we're waiting for an answer */ 
     2162    if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) { 
     2163        status = pjsip_dlg_create_response(inv->dlg, rdata,  
     2164                                           PJSIP_SC_REQUEST_PENDING, NULL, 
     2165                                           &tdata); 
     2166    } 
     2167    /* Send 500 with Retry-After header set randomly between 0 and 10 if we  
     2168     * receive UPDATE while we haven't sent answer. 
     2169     */ 
     2170    else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER || 
     2171             neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) { 
     2172        status = pjsip_dlg_create_response(inv->dlg, rdata,  
     2173                                           PJSIP_SC_INTERNAL_SERVER_ERROR, 
     2174                                           NULL, &tdata); 
     2175 
     2176    } else { 
     2177        /* We receive new offer from remote */ 
     2178        inv_check_sdp_in_incoming_msg(inv, pjsip_rdata_get_tsx(rdata), rdata); 
     2179 
     2180        /* Application MUST have supplied the answer by now. 
     2181         * If so, negotiate the SDP. 
     2182         */ 
     2183        neg_state = pjmedia_sdp_neg_get_state(inv->neg); 
     2184        if (neg_state != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO || 
     2185            (status=inv_negotiate_sdp(inv)) != PJ_SUCCESS) 
     2186        { 
     2187            /* Negotiation has failed */ 
     2188            status = pjsip_dlg_create_response(inv->dlg, rdata,  
     2189                                               PJSIP_SC_NOT_ACCEPTABLE_HERE, 
     2190                                               NULL, &tdata); 
     2191        } else { 
     2192            /* New media has been negotiated successfully, send 200/OK */ 
     2193            status = pjsip_dlg_create_response(inv->dlg, rdata,  
     2194                                               PJSIP_SC_OK, NULL, &tdata); 
     2195            if (status == PJ_SUCCESS) { 
     2196                pjmedia_sdp_session *sdp; 
     2197                status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp); 
     2198                if (status == PJ_SUCCESS) 
     2199                    tdata->msg->body = create_sdp_body(tdata->pool, sdp); 
     2200            } 
     2201        } 
     2202    } 
     2203 
     2204    if (status != PJ_SUCCESS) { 
     2205        if (tdata != NULL) { 
     2206            pjsip_tx_data_dec_ref(tdata); 
     2207            tdata = NULL; 
     2208        } 
     2209        return; 
     2210    } 
     2211 
     2212    pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata), tdata); 
     2213} 
     2214 
     2215 
     2216/* 
     2217 * Handle incoming response to UAC UPDATE request. 
     2218 */ 
     2219static void inv_handle_update_response( pjsip_inv_session *inv, 
     2220                                        pjsip_event *e) 
     2221{ 
     2222    pjsip_transaction *tsx = e->body.tsx_state.tsx; 
     2223    struct tsx_inv_data *tsx_inv_data = NULL; 
     2224    pj_status_t status = -1; 
     2225 
     2226    /* Process 2xx response */ 
     2227    if (tsx->state == PJSIP_TSX_STATE_COMPLETED && 
     2228        tsx->status_code/100 == 2 && 
     2229        e->body.tsx_state.src.rdata->msg_info.msg->body) 
     2230    { 
     2231        status = inv_check_sdp_in_incoming_msg(inv, tsx,  
     2232                                            e->body.tsx_state.src.rdata); 
     2233 
     2234    } else { 
     2235        /* Get/attach invite session's transaction data */ 
     2236        tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id]; 
     2237        if (tsx_inv_data == NULL) { 
     2238            tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data); 
     2239            tsx_inv_data->inv = inv; 
     2240            tsx->mod_data[mod_inv.mod.id] = tsx_inv_data; 
     2241        } 
     2242    } 
     2243 
     2244    /* Otherwise if we don't get successful response, cancel 
     2245     * our negotiator. 
     2246     */ 
     2247    if (status != PJ_SUCCESS && 
     2248        pjmedia_sdp_neg_get_state(inv->neg)==PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER && 
     2249        tsx_inv_data && tsx_inv_data->sdp_done == PJ_FALSE)  
     2250    { 
     2251        pjmedia_sdp_neg_cancel_offer(inv->neg); 
     2252 
     2253        /* Prevent from us cancelling different offer! */ 
     2254        tsx_inv_data->sdp_done = PJ_TRUE; 
     2255    } 
     2256} 
     2257 
     2258 
     2259/* 
     2260 * Handle incoming reliable response. 
     2261 */ 
     2262static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv, 
     2263                                                  pjsip_rx_data *rdata) 
     2264{ 
     2265    pjsip_tx_data *tdata; 
     2266    pjmedia_sdp_session *sdp; 
     2267    pj_status_t status; 
     2268 
     2269    /* Create PRACK */ 
     2270    status = pjsip_100rel_create_prack(inv, rdata, &tdata); 
     2271    if (status != PJ_SUCCESS) 
     2272        return; 
     2273 
     2274    /* See if we need to attach SDP answer on the PRACK request */ 
     2275    sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata)); 
     2276    if (sdp) { 
     2277        tdata->msg->body = create_sdp_body(tdata->pool, sdp); 
     2278    } 
     2279 
     2280    /* Send PRACK (must be using 100rel module!) */ 
     2281    pjsip_100rel_send_prack(inv, tdata); 
     2282} 
     2283 
     2284 
     2285/* 
     2286 * Handle incoming PRACK. 
     2287 */ 
     2288static void inv_respond_incoming_prack(pjsip_inv_session *inv, 
     2289                                       pjsip_rx_data *rdata) 
     2290{ 
     2291    pj_status_t status; 
     2292 
     2293    /* Run through 100rel module to see if we can accept this 
     2294     * PRACK request. The 100rel will send 200/OK to PRACK request. 
     2295     */ 
     2296    status = pjsip_100rel_on_rx_prack(inv, rdata); 
     2297    if (status != PJ_SUCCESS) 
     2298        return; 
     2299 
     2300    /* Now check for SDP answer in the PRACK request */ 
     2301    if (rdata->msg_info.msg->body) { 
     2302        status = inv_check_sdp_in_incoming_msg(inv,  
     2303                                        pjsip_rdata_get_tsx(rdata), rdata); 
     2304    } else { 
     2305        /* No SDP body */ 
     2306        status = -1; 
     2307    } 
     2308 
     2309    /* If SDP negotiation has been successful, also mark the 
     2310     * SDP negotiation flag in the invite transaction to be 
     2311     * done too. 
     2312     */ 
     2313    if (status == PJ_SUCCESS && inv->invite_tsx) { 
     2314        struct tsx_inv_data *tsx_inv_data; 
     2315 
     2316        /* Get/attach invite session's transaction data */ 
     2317        tsx_inv_data = (struct tsx_inv_data*)  
     2318                       inv->invite_tsx->mod_data[mod_inv.mod.id]; 
     2319        if (tsx_inv_data == NULL) { 
     2320            tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool,  
     2321                                            struct tsx_inv_data); 
     2322            tsx_inv_data->inv = inv; 
     2323            inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data; 
     2324        } 
     2325         
     2326        tsx_inv_data->sdp_done = PJ_TRUE; 
     2327    } 
     2328} 
     2329 
     2330 
     2331/* 
    19902332 * State NULL is before anything is sent/received. 
    19912333 */ 
     
    20732415                                              e->body.tsx_state.src.rdata); 
    20742416 
     2417                if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) { 
     2418                    inv_handle_incoming_reliable_response( 
     2419                        inv, e->body.tsx_state.src.rdata); 
     2420                } 
     2421 
    20752422            } else { 
    20762423                /* Ignore 100 (Trying) response, as it doesn't change 
     
    21672514        } 
    21682515 
    2169     } else if (inv->role == PJSIP_ROLE_UAC && 
    2170                tsx->role == PJSIP_ROLE_UAC && 
    2171                tsx->method.id == PJSIP_CANCEL_METHOD) 
    2172     { 
     2516    } else if (tsx->role == PJSIP_ROLE_UAC) { 
    21732517        /* 
    2174          * Handle case when outgoing CANCEL is answered with 481 (Call/ 
     2518         * Handle case when outgoing request is answered with 481 (Call/ 
    21752519         * Transaction Does Not Exist), 408, or when it's timed out. In these 
    21762520         * cases, disconnect session (i.e. dialog usage only). 
     
    22852629                inv_check_sdp_in_incoming_msg(inv, tsx,  
    22862630                                              e->body.tsx_state.src.rdata); 
     2631 
     2632                if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) { 
     2633                    inv_handle_incoming_reliable_response( 
     2634                        inv, e->body.tsx_state.src.rdata); 
     2635                } 
    22872636            } 
    22882637            break; 
     
    23542703        inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata); 
    23552704 
    2356     } else if (inv->role == PJSIP_ROLE_UAC && 
    2357                tsx->role == PJSIP_ROLE_UAC && 
    2358                tsx->method.id == PJSIP_CANCEL_METHOD) 
     2705    } else if (tsx->role == PJSIP_ROLE_UAS && 
     2706               tsx->state == PJSIP_TSX_STATE_TRYING && 
     2707               pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0) 
    23592708    { 
    23602709        /* 
    2361          * Handle case when outgoing CANCEL is answered with 481 (Call/ 
     2710         * Handle incoming UPDATE 
     2711         */ 
     2712        inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata); 
     2713 
     2714 
     2715    } else if (tsx->role == PJSIP_ROLE_UAC && 
     2716               (tsx->state == PJSIP_TSX_STATE_COMPLETED || 
     2717                tsx->state == PJSIP_TSX_STATE_TERMINATED) && 
     2718               pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0) 
     2719    { 
     2720        /* 
     2721         * Handle response to outgoing UPDATE request. 
     2722         */ 
     2723        inv_handle_update_response(inv, e); 
     2724 
     2725    } else if (tsx->role == PJSIP_ROLE_UAS && 
     2726               tsx->state == PJSIP_TSX_STATE_TRYING && 
     2727               pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0) 
     2728    { 
     2729        /* 
     2730         * Handle incoming PRACK 
     2731         */ 
     2732        inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata); 
     2733 
     2734    } else if (tsx->role == PJSIP_ROLE_UAC) { 
     2735        /* 
     2736         * Handle case when outgoing request is answered with 481 (Call/ 
    23622737         * Transaction Does Not Exist), 408, or when it's timed out. In these 
    23632738         * cases, disconnect session (i.e. dialog usage only). 
     
    24672842        if (status != PJ_SUCCESS) return; 
    24682843 
    2469     } 
     2844    } else if (tsx->role == PJSIP_ROLE_UAS && 
     2845               tsx->state == PJSIP_TSX_STATE_TRYING && 
     2846               pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0) 
     2847    { 
     2848        /* 
     2849         * Handle incoming UPDATE 
     2850         */ 
     2851        inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata); 
     2852 
     2853 
     2854    } else if (tsx->role == PJSIP_ROLE_UAC && 
     2855               (tsx->state == PJSIP_TSX_STATE_COMPLETED || 
     2856                tsx->state == PJSIP_TSX_STATE_TERMINATED) && 
     2857               pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0) 
     2858    { 
     2859        /* 
     2860         * Handle response to outgoing UPDATE request. 
     2861         */ 
     2862        inv_handle_update_response(inv, e); 
     2863 
     2864    } else if (tsx->role == PJSIP_ROLE_UAS && 
     2865               tsx->state == PJSIP_TSX_STATE_TRYING && 
     2866               pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0) 
     2867    { 
     2868        /* 
     2869         * Handle incoming PRACK 
     2870         */ 
     2871        inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata); 
     2872 
     2873    } else if (tsx->role == PJSIP_ROLE_UAC) { 
     2874        /* 
     2875         * Handle case when outgoing request is answered with 481 (Call/ 
     2876         * Transaction Does Not Exist), 408, or when it's timed out. In these 
     2877         * cases, disconnect session (i.e. dialog usage only). 
     2878         */ 
     2879        if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST || 
     2880            tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT || 
     2881            tsx->status_code == PJSIP_SC_TSX_TIMEOUT || 
     2882            tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR) 
     2883        { 
     2884            inv_set_cause(inv, tsx->status_code, &tsx->status_text); 
     2885            inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
     2886        } 
     2887    } 
     2888 
    24702889} 
    24712890 
     
    27313150            } 
    27323151        } 
    2733     } 
     3152 
     3153    } else if (tsx->role == PJSIP_ROLE_UAS && 
     3154               tsx->state == PJSIP_TSX_STATE_TRYING && 
     3155               pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0) 
     3156    { 
     3157        /* 
     3158         * Handle incoming UPDATE 
     3159         */ 
     3160        inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata); 
     3161 
     3162    } else if (tsx->role == PJSIP_ROLE_UAC && 
     3163               (tsx->state == PJSIP_TSX_STATE_COMPLETED || 
     3164                tsx->state == PJSIP_TSX_STATE_TERMINATED) && 
     3165               pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0) 
     3166    { 
     3167        /* 
     3168         * Handle response to outgoing UPDATE request. 
     3169         */ 
     3170        inv_handle_update_response(inv, e); 
     3171 
     3172    } else if (tsx->role == PJSIP_ROLE_UAS && 
     3173               tsx->state == PJSIP_TSX_STATE_TRYING && 
     3174               pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0) 
     3175    { 
     3176        /* 
     3177         * Handle strandled incoming PRACK 
     3178         */ 
     3179        inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata); 
     3180 
     3181    } else if (tsx->role == PJSIP_ROLE_UAC) { 
     3182        /* 
     3183         * Handle case when outgoing request is answered with 481 (Call/ 
     3184         * Transaction Does Not Exist), 408, or when it's timed out. In these 
     3185         * cases, disconnect session (i.e. dialog usage only). 
     3186         */ 
     3187        if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST || 
     3188            tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT || 
     3189            tsx->status_code == PJSIP_SC_TSX_TIMEOUT || 
     3190            tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR) 
     3191        { 
     3192            inv_set_cause(inv, tsx->status_code, &tsx->status_text); 
     3193            inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e); 
     3194        } 
     3195    } 
     3196 
    27343197} 
    27353198 
  • pjproject/trunk/pjsip/src/pjsip/sip_dialog.c

    r1466 r1469  
    12011201        } 
    12021202 
    1203         /* Add Allow header in 2xx and 405 response. */ 
    1204         if (((st_class==2 && dlg->add_allow) 
     1203        /* Add Allow header in 18x, 2xx and 405 response. */ 
     1204        if ((((st_code/10==18 || st_class==2) && dlg->add_allow) 
    12051205             || st_code==405) && 
    12061206            pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ALLOW, NULL)==NULL)  
  • pjproject/trunk/pjsip/src/pjsip/sip_transaction.c

    r1463 r1469  
    905905    pj_ansi_snprintf(tsx->obj_name, sizeof(tsx->obj_name),  
    906906                     "tsx%p", tsx); 
     907    pj_memcpy(pool->obj_name, tsx->obj_name, sizeof(pool->obj_name)); 
    907908 
    908909    tsx->handle_200resp = 1; 
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c

    r1463 r1469  
    196196 
    197197 
     198#define LATE_SDP    0 
     199 
    198200/* 
    199201 * Make outgoing call to the specified URI using the specified account. 
     
    313315 
    314316    /* Create SDP offer */ 
     317#if LATE_SDP 
     318    offer = NULL; 
     319#else 
    315320    status = pjsua_media_channel_create_sdp(call->index, dlg->pool, &offer); 
    316321    if (status != PJ_SUCCESS) { 
     
    318323        goto on_error; 
    319324    } 
     325#endif 
    320326 
    321327    /* Create the INVITE session: */ 
  • pjproject/trunk/pjsip/src/test-pjsip/test.c

    r1159 r1469  
    356356#endif 
    357357 
     358#if INCLUDE_INV_OA_TEST 
     359    DO_TEST(inv_offer_answer_test()); 
     360#endif 
     361 
    358362 
    359363on_return: 
  • pjproject/trunk/pjsip/src/test-pjsip/test.h

    r974 r1469  
    4040#define INCLUDE_TRANSPORT_GROUP     1 
    4141#define INCLUDE_TSX_GROUP           1 
     42#define INCLUDE_INV_GROUP           1 
    4243 
    4344/* 
     
    5960#define INCLUDE_RESOLVE_TEST    INCLUDE_TRANSPORT_GROUP 
    6061#define INCLUDE_TSX_TEST        INCLUDE_TSX_GROUP 
    61  
     62#define INCLUDE_INV_OA_TEST     INCLUDE_INV_GROUP 
    6263 
    6364 
     
    9596                       int *pkt_lost); 
    9697 
     98/* Invite session */ 
     99int inv_offer_answer_test(void); 
     100 
    97101/* Test main entry */ 
    98102int  test_main(void); 
Note: See TracChangeset for help on using the changeset viewer.