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

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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 
Note: See TracChangeset for help on using the changeset viewer.