Changeset 4586


Ignore:
Timestamp:
Sep 4, 2013 10:07:45 AM (9 years ago)
Author:
ming
Message:

Closed #1696: IP change detection (Contact rewrite method) based on REGISTER final response

Location:
pjproject/trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/include/pjsip-ua/sip_regc.h

    r4173 r4586  
    8383/** Type declaration for callback to receive registration result. */ 
    8484typedef void pjsip_regc_cb(struct pjsip_regc_cbparam *param); 
     85 
     86/** 
     87 * Structure to hold parameters when calling application's callback 
     88 * specified in #pjsip_regc_set_reg_tsx_cb(). 
     89 * To update contact address, application can set the field contact_cnt 
     90 * and contact inside the callback. 
     91 */ 
     92struct pjsip_regc_tsx_cb_param 
     93{ 
     94    struct pjsip_regc_cbparam   cbparam; 
     95    int                         contact_cnt; 
     96    pj_str_t                    contact[PJSIP_REGC_MAX_CONTACT]; 
     97}; 
     98 
     99/** Type declaration for callback set in #pjsip_regc_set_reg_tsx_cb(). */ 
     100typedef void pjsip_regc_tsx_cb(struct pjsip_regc_tsx_cb_param *param); 
    85101 
    86102/** 
     
    192208 
    193209/** 
     210 * Set callback to be called when the registration received a final response. 
     211 * This callback is different with the one specified during creation via 
     212 * #pjsip_regc_create(). This callback will be called for any final response 
     213 * (including 401/407/423) and before any subsequent requests are sent. 
     214 * In case of unregistration, this callback will not be called. 
     215 * 
     216 * @param regc      The client registration structure. 
     217 * @param tsx_cb    Pointer to callback function to receive registration status. 
     218 * 
     219 * @return          PJ_SUCCESS on success. 
     220 */ 
     221PJ_DECL(pj_status_t) pjsip_regc_set_reg_tsx_cb(pjsip_regc *regc, 
     222                                               pjsip_regc_tsx_cb *tsx_cb); 
     223 
     224/** 
    194225 * Set the "sent-by" field of the Via header for outgoing requests. 
    195226 * 
  • pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h

    r4580 r4586  
    567567 
    568568} pjsua_create_media_transport_flag; 
     569 
     570 
     571/** 
     572 * This enumeration specifies the contact rewrite method. 
     573 */ 
     574typedef enum pjsua_contact_rewrite_method 
     575{ 
     576    /** 
     577      * The Contact update will be done by sending unregistration 
     578      * to the currently registered Contact, while simultaneously sending new 
     579      * registration (with different Call-ID) for the updated Contact. 
     580      */ 
     581    PJSUA_CONTACT_REWRITE_UNREGISTER = 1, 
     582 
     583    /** 
     584      * The Contact update will be done in a single, current 
     585      * registration session, by removing the current binding (by setting its 
     586      * Contact's expires parameter to zero) and adding a new Contact binding, 
     587      * all done in a single request. 
     588      */ 
     589    PJSUA_CONTACT_REWRITE_NO_UNREG = 2, 
     590 
     591    /** 
     592      * The Contact update will be done when receiving any registration final 
     593      * response. If this flag is not specified, contact update will only be 
     594      * done upon receiving 2xx response. This flag MUST be used with 
     595      * PJSUA_CONTACT_REWRITE_UNREGISTER or PJSUA_CONTACT_REWRITE_NO_UNREG 
     596      * above to specify how the Contact update should be performed when 
     597      * receiving 2xx response. 
     598      */ 
     599    PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE = 4 
     600 
     601} pjsua_contact_rewrite_method; 
    569602 
    570603 
     
    25412574/** 
    25422575 * This macro specifies the default value for \a contact_rewrite_method 
    2543  * field in pjsua_acc_config. I specifies how Contact update will be 
     2576 * field in pjsua_acc_config. It specifies how Contact update will be 
    25442577 * done with the registration, if \a allow_contact_rewrite is enabled in 
    2545  *  the account config. 
    2546  * 
    2547  * If set to 1, the Contact update will be done by sending unregistration 
    2548  * to the currently registered Contact, while simultaneously sending new 
    2549  * registration (with different Call-ID) for the updated Contact. 
    2550  * 
    2551  * If set to 2, the Contact update will be done in a single, current 
    2552  * registration session, by removing the current binding (by setting its 
    2553  * Contact's expires parameter to zero) and adding a new Contact binding, 
    2554  * all done in a single request. 
    2555  * 
    2556  * Value 1 is the legacy behavior. 
    2557  * 
    2558  * Default value: 2 
     2578 * the account config. See \a pjsua_contact_rewrite_method for the options. 
     2579 * 
     2580 * Value PJSUA_CONTACT_REWRITE_UNREGISTER(1) is the legacy behavior. 
     2581 * 
     2582 * Default value: PJSUA_CONTACT_REWRITE_NO_UNREG(2) | 
     2583 *                PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE(4) 
    25592584 */ 
    25602585#ifndef PJSUA_CONTACT_REWRITE_METHOD 
    2561 #   define PJSUA_CONTACT_REWRITE_METHOD         2 
     2586#   define PJSUA_CONTACT_REWRITE_METHOD    (PJSUA_CONTACT_REWRITE_NO_UNREG | \ 
     2587                                           PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE) 
    25622588#endif 
    25632589 
     
    30113037    /** 
    30123038     * Specify how Contact update will be done with the registration, if 
    3013      * \a allow_contact_rewrite is enabled. 
    3014      * 
    3015      * If set to 1, the Contact update will be done by sending unregistration 
    3016      * to the currently registered Contact, while simultaneously sending new 
    3017      * registration (with different Call-ID) for the updated Contact. 
    3018      * 
    3019      * If set to 2, the Contact update will be done in a single, current 
    3020      * registration session, by removing the current binding (by setting its 
    3021      * Contact's expires parameter to zero) and adding a new Contact binding, 
    3022      * all done in a single request. 
    3023      * 
    3024      * Value 1 is the legacy behavior. 
    3025      * 
    3026      * Default value: PJSUA_CONTACT_REWRITE_METHOD (2) 
     3039     * \a allow_contact_rewrite is enabled. The value is bitmask combination of 
     3040     * \a pjsua_contact_rewrite_method. See also pjsua_contact_rewrite_method. 
     3041     * 
     3042     * Value PJSUA_CONTACT_REWRITE_UNREGISTER(1) is the legacy behavior. 
     3043     * 
     3044     * Default value: PJSUA_CONTACT_REWRITE_METHOD 
     3045     * (PJSUA_CONTACT_REWRITE_NO_UNREG | PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE) 
    30273046     */ 
    30283047    int              contact_rewrite_method; 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c

    r4548 r4586  
    7676    void                        *token; 
    7777    pjsip_regc_cb               *cb; 
     78    pjsip_regc_tsx_cb           *tsx_cb; 
    7879 
    7980    pj_str_t                     str_srv_url; 
     
    728729} 
    729730 
     731static void cbparam_init( struct pjsip_regc_cbparam *cbparam, 
     732                          pjsip_regc *regc,  
     733                          pj_status_t status, int st_code,  
     734                          const pj_str_t *reason, 
     735                          pjsip_rx_data *rdata, pj_int32_t expiration, 
     736                          int contact_cnt, pjsip_contact_hdr *contact[]) 
     737{ 
     738    cbparam->regc = regc; 
     739    cbparam->token = regc->token; 
     740    cbparam->status = status; 
     741    cbparam->code = st_code; 
     742    cbparam->reason = *reason; 
     743    cbparam->rdata = rdata; 
     744    cbparam->contact_cnt = contact_cnt; 
     745    cbparam->expiration = expiration; 
     746    if (contact_cnt) { 
     747        pj_memcpy( cbparam->contact, contact,  
     748                   contact_cnt*sizeof(pjsip_contact_hdr*)); 
     749    } 
     750} 
    730751 
    731752static void call_callback(pjsip_regc *regc, pj_status_t status, int st_code,  
     
    736757    struct pjsip_regc_cbparam cbparam; 
    737758 
    738  
    739759    if (!regc->cb) 
    740760        return; 
    741761 
    742     cbparam.regc = regc; 
    743     cbparam.token = regc->token; 
    744     cbparam.status = status; 
    745     cbparam.code = st_code; 
    746     cbparam.reason = *reason; 
    747     cbparam.rdata = rdata; 
    748     cbparam.contact_cnt = contact_cnt; 
    749     cbparam.expiration = expiration; 
    750     if (contact_cnt) { 
    751         pj_memcpy( cbparam.contact, contact,  
    752                    contact_cnt*sizeof(pjsip_contact_hdr*)); 
    753     } 
    754  
     762    cbparam_init(&cbparam, regc, status, st_code, reason, rdata, expiration, 
     763                 contact_cnt, contact); 
    755764    (*regc->cb)(&cbparam); 
    756765} 
     
    813822    } 
    814823} 
     824 
     825PJ_DEF(pj_status_t) pjsip_regc_set_reg_tsx_cb( pjsip_regc *regc, 
     826                                               pjsip_regc_tsx_cb *tsx_cb) 
     827{ 
     828    PJ_ASSERT_RETURN(regc, PJ_EINVAL); 
     829    regc->tsx_cb = tsx_cb; 
     830    return PJ_SUCCESS; 
     831} 
     832 
    815833 
    816834PJ_DEF(pj_status_t) pjsip_regc_set_via_sent_by( pjsip_regc *regc, 
     
    10361054    pjsip_transaction *tsx = event->body.tsx_state.tsx; 
    10371055    pj_bool_t handled = PJ_TRUE; 
     1056    pj_bool_t update_contact = PJ_FALSE; 
    10381057 
    10391058    pj_atomic_inc(regc->busy_ctr); 
     
    10551074            pjsip_transport_add_ref(regc->last_transport); 
    10561075        } 
     1076    } 
     1077 
     1078    if (regc->_delete_flag == 0 && regc->tsx_cb && 
     1079        regc->current_op == REGC_REGISTERING) 
     1080    { 
     1081        struct pjsip_regc_tsx_cb_param param; 
     1082 
     1083        param.contact_cnt = -1; 
     1084        cbparam_init(&param.cbparam, regc, PJ_SUCCESS, tsx->status_code, 
     1085                     &tsx->status_text, 
     1086                     (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?  
     1087                      event->body.tsx_state.src.rdata : NULL, 
     1088                     -1, 0, NULL); 
     1089 
     1090        /* Call regc tsx callback before handling any response */ 
     1091        pj_lock_release(regc->lock); 
     1092        (*regc->tsx_cb)(&param); 
     1093        pj_lock_acquire(regc->lock); 
     1094 
     1095        if (param.contact_cnt >= 0) { 
     1096            /* Since we receive non-2xx response, it means that (some) contact 
     1097             * bindings haven't been established so we can safely remove these 
     1098             * contact headers. This is to avoid removing non-existent contact 
     1099             * bindings later. 
     1100             */ 
     1101            if (tsx->status_code/100 != 2) { 
     1102                pjsip_contact_hdr *h; 
     1103 
     1104                h = regc->contact_hdr_list.next; 
     1105                while (h != &regc->contact_hdr_list) { 
     1106                    pjsip_contact_hdr *next = h->next; 
     1107 
     1108                    if (h->expires == -1) { 
     1109                        pj_list_erase(h); 
     1110                    } 
     1111                    h = next; 
     1112                } 
     1113            } 
     1114 
     1115            /* Update contact address */ 
     1116            pjsip_regc_update_contact(regc, param.contact_cnt, param.contact); 
     1117            update_contact = PJ_TRUE; 
     1118        } 
    10571119    } 
    10581120 
     
    10671129        regc->current_op = REGC_IDLE; 
    10681130 
    1069         status = pjsip_auth_clt_reinit_req( &regc->auth_sess, 
     1131        if (update_contact) { 
     1132            pjsip_msg *msg; 
     1133            pjsip_hdr *hdr, *ins_hdr; 
     1134            pjsip_contact_hdr *chdr; 
     1135 
     1136            /* Delete Contact headers, but we shouldn't delete headers 
     1137             * which are supposed to remove contact bindings since 
     1138             * we cannot reconstruct those headers. 
     1139             */ 
     1140            msg = tsx->last_tx->msg; 
     1141            hdr = msg->hdr.next; 
     1142            ins_hdr = &msg->hdr; 
     1143            while (hdr != &msg->hdr) { 
     1144                pjsip_hdr *next = hdr->next; 
     1145 
     1146                if (hdr->type == PJSIP_H_CONTACT) { 
     1147                    chdr = (pjsip_contact_hdr *)hdr; 
     1148                    if (chdr->expires != 0) { 
     1149                        pj_list_erase(hdr); 
     1150                        ins_hdr = next; 
     1151                    } 
     1152                } 
     1153                hdr = next; 
     1154            } 
     1155 
     1156            /* Add Contact headers. */ 
     1157            chdr = regc->contact_hdr_list.next; 
     1158            while (chdr != &regc->contact_hdr_list) { 
     1159                pj_list_insert_before(ins_hdr, (pjsip_hdr*) 
     1160                    pjsip_hdr_shallow_clone(tsx->last_tx->pool, chdr)); 
     1161                chdr = chdr->next; 
     1162            } 
     1163 
     1164            /* Also add bindings which are to be removed */ 
     1165            while (!pj_list_empty(&regc->removed_contact_hdr_list)) { 
     1166                chdr = regc->removed_contact_hdr_list.next; 
     1167                pj_list_insert_before(ins_hdr, (pjsip_hdr*) 
     1168                    pjsip_hdr_clone(tsx->last_tx->pool, chdr)); 
     1169                pj_list_erase(chdr); 
     1170            } 
     1171        } 
     1172 
     1173        status = pjsip_auth_clt_reinit_req( &regc->auth_sess, 
    10701174                                            rdata,  
    10711175                                            tsx->last_tx,   
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c

    r4580 r4586  
    14951495/* Update NAT address from the REGISTER response */ 
    14961496static pj_bool_t acc_check_nat_addr(pjsua_acc *acc, 
     1497                                    int contact_rewrite_method, 
    14971498                                    struct pjsip_regc_cbparam *param) 
    14981499{ 
     
    16791680                         via_addr->ptr, 
    16801681                         rport, 
    1681                          acc->cfg.contact_rewrite_method)); 
    1682  
    1683     pj_assert(acc->cfg.contact_rewrite_method == 1 || 
    1684               acc->cfg.contact_rewrite_method == 2); 
    1685  
    1686     if (acc->cfg.contact_rewrite_method == 1) { 
     1682                         contact_rewrite_method)); 
     1683 
     1684    pj_assert(contact_rewrite_method == PJSUA_CONTACT_REWRITE_UNREGISTER || 
     1685              contact_rewrite_method == PJSUA_CONTACT_REWRITE_NO_UNREG || 
     1686              contact_rewrite_method == PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE); 
     1687 
     1688    if (contact_rewrite_method == PJSUA_CONTACT_REWRITE_UNREGISTER) { 
    16871689        /* Unregister current contact */ 
    16881690        pjsua_acc_set_registration(acc->index, PJ_FALSE); 
     
    17621764    } 
    17631765 
    1764     if (acc->cfg.contact_rewrite_method == 2 && acc->regc != NULL) { 
     1766    if (contact_rewrite_method == PJSUA_CONTACT_REWRITE_NO_UNREG && 
     1767        acc->regc != NULL) 
     1768    { 
    17651769        pjsip_regc_update_contact(acc->regc, 1, &acc->reg_contact); 
    17661770    } 
    17671771 
    17681772    /* Perform new registration */ 
    1769     pjsua_acc_set_registration(acc->index, PJ_TRUE); 
     1773    if (contact_rewrite_method < PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE) { 
     1774        pjsua_acc_set_registration(acc->index, PJ_TRUE); 
     1775    } 
    17701776 
    17711777    pj_pool_release(pool); 
     
    20592065} 
    20602066 
     2067static void regc_tsx_cb(struct pjsip_regc_tsx_cb_param *param) 
     2068{ 
     2069    pjsua_acc *acc = (pjsua_acc*) param->cbparam.token; 
     2070 
     2071    PJSUA_LOCK(); 
     2072 
     2073    if (param->cbparam.regc != acc->regc) { 
     2074        PJSUA_UNLOCK(); 
     2075        return; 
     2076    } 
     2077 
     2078    pj_log_push_indent(); 
     2079 
     2080    if ((acc->cfg.contact_rewrite_method & 
     2081         PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE) == 
     2082        PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE && 
     2083        param->cbparam.code >= 400 && 
     2084        param->cbparam.rdata) 
     2085    { 
     2086        if (acc_check_nat_addr(acc, PJSUA_CONTACT_REWRITE_ALWAYS_UPDATE, 
     2087                               &param->cbparam)) 
     2088        { 
     2089            param->contact_cnt = 1; 
     2090            param->contact[0] = acc->reg_contact; 
     2091        } 
     2092    } 
     2093 
     2094    PJSUA_UNLOCK(); 
     2095    pj_log_pop_indent(); 
     2096} 
     2097 
    20612098/* 
    20622099 * This callback is called by pjsip_regc when outgoing register 
     
    21272164 
    21282165            /* Check NAT bound address */ 
    2129             if (acc_check_nat_addr(acc, param)) { 
     2166            if (acc_check_nat_addr(acc, (acc->cfg.contact_rewrite_method & 3), 
     2167                                   param)) 
     2168            { 
    21302169                PJSUA_UNLOCK(); 
    21312170                pj_log_pop_indent(); 
     
    22712310        return status; 
    22722311    } 
     2312 
     2313    pjsip_regc_set_reg_tsx_cb(acc->regc, regc_tsx_cb); 
    22732314 
    22742315    /* If account is locked to specific transport, then set transport to 
  • pjproject/trunk/tests/pjsua/scripts-sipp/uas-register-ip-change.xml

    r4547 r4586  
    88  <send> 
    99    <![CDATA[ 
     10      SIP/2.0 100 Trying 
     11      [last_Via:];received=1.1.1.1;rport=1111 
     12      [last_From:] 
     13      [last_To:];tag=[call_number] 
     14      [last_Call-ID:] 
     15      [last_CSeq:] 
     16      WWW-Authenticate: digest realm="test" 
     17      Content-Length: 0 
     18    ]]> 
     19  </send> 
     20 
     21  <pause milliseconds="2000"/> 
     22 
     23  <send> 
     24    <![CDATA[ 
    1025      SIP/2.0 401 Unauthorized 
    11       [last_Via:];received=1.1.1.1;rport=1111 
     26      [last_Via:];received=2.2.2.2;rport=2222 
    1227      [last_From:] 
    1328      [last_To:];tag=[call_number] 
     
    2439  <send> 
    2540    <![CDATA[ 
     41      SIP/2.0 401 Unauthorized again 
     42      [last_Via:];received=3.3.3.3;rport=3333 
     43      [last_From:] 
     44      [last_To:];tag=[call_number] 
     45      [last_Call-ID:] 
     46      [last_CSeq:] 
     47      [last_Contact:] 
     48      WWW-Authenticate: digest realm="test", stale=true 
     49      Content-Length: 0 
     50    ]]> 
     51  </send> 
     52 
     53 
     54  <recv request="REGISTER" crlf="true"> 
     55  </recv> 
     56 
     57  <send> 
     58    <![CDATA[ 
    2659      SIP/2.0 200 OK 
    27       [last_Via:];received=1.1.1.1;rport=1111 
     60      [last_Via:];received=4.4.4.4;rport=4444 
    2861      [last_From:] 
    2962      [last_To:];tag=[call_number] 
     
    3568  </send> 
    3669 
    37   <!-- REREGISTER --> 
     70  <!-- IP CHANGE FOR 200/OK --> 
     71 
     72  <recv request="REGISTER" crlf="true"> 
     73  </recv> 
     74 
     75  <send> 
     76    <![CDATA[ 
     77      SIP/2.0 401 Unauthorized 
     78      [last_Via:];received=5.5.5.5;rport=5555 
     79      [last_From:] 
     80      [last_To:];tag=[call_number] 
     81      [last_Call-ID:] 
     82      [last_CSeq:] 
     83      [last_Contact:] 
     84      WWW-Authenticate: digest realm="test" 
     85      Content-Length: 0 
     86    ]]> 
     87  </send> 
     88 
     89  <recv request="REGISTER" crlf="true"> 
     90  </recv> 
     91 
     92  <send> 
     93    <![CDATA[ 
     94      SIP/2.0 401 Nasty Unauthorized 
     95      [last_Via:];received=6.6.6.6;rport=6666 
     96      [last_From:] 
     97      [last_To:];tag=[call_number] 
     98      [last_Call-ID:] 
     99      [last_CSeq:] 
     100      [last_Contact:] 
     101      WWW-Authenticate: digest realm="test", stale=true 
     102      Content-Length: 0 
     103    ]]> 
     104  </send> 
     105 
    38106  <recv request="REGISTER" crlf="true"> 
    39107  </recv> 
     
    42110    <![CDATA[ 
    43111      SIP/2.0 200 OK 
    44       [last_Via:];received=1.1.1.1;rport=1111 
     112      [last_Via:];received=8.8.8.8;rport=8888 
    45113      [last_From:] 
    46114      [last_To:];tag=[call_number] 
     
    48116      [last_CSeq:] 
    49117      [last_Contact:] 
    50       Subject: Reregister due to IP change, this has two Contacts 
    51118      Content-Length: 0 
    52119    ]]> 
    53120  </send> 
    54121 
    55  
    56   <!-- REFRESH, GOT IP CHANGE AGAIN --> 
    57122  <recv request="REGISTER" crlf="true"> 
    58123  </recv> 
     
    61126    <![CDATA[ 
    62127      SIP/2.0 200 OK 
    63       [last_Via:];received=2.2.2.2;rport=2222 
     128      [last_Via:];received=8.8.8.8;rport=8888 
    64129      [last_From:] 
    65130      [last_To:];tag=[call_number] 
     
    67132      [last_CSeq:] 
    68133      [last_Contact:] 
    69       Subject: Refresh, got IP change again 
    70       Content-Length: 0 
    71     ]]> 
    72   </send> 
    73  
    74  
    75   <!-- REREGISTER --> 
    76   <recv request="REGISTER" crlf="true"> 
    77   </recv> 
    78  
    79   <send> 
    80     <![CDATA[ 
    81       SIP/2.0 200 OK 
    82       [last_Via:];received=2.2.2.2;rport=2222 
    83       [last_From:] 
    84       [last_To:];tag=[call_number] 
    85       [last_Call-ID:] 
    86       [last_CSeq:] 
    87       [last_Contact:] 
    88       Subject: Reregister due to IP change to 2.2.2.2, this has two Contacts 
    89       Content-Length: 0 
    90     ]]> 
    91   </send> 
    92  
    93  
    94   <!-- WHATEVER --> 
    95   <recv request="REGISTER" crlf="true"> 
    96   </recv> 
    97  
    98   <send> 
    99     <![CDATA[ 
    100       SIP/2.0 200 OK 
    101       [last_Via:];received=2.2.2.2;rport=2222 
    102       [last_From:] 
    103       [last_To:];tag=[call_number] 
    104       [last_Call-ID:] 
    105       [last_CSeq:] 
    106       [last_Contact:] 
    107       Subject: Whatever 1 
    108       Content-Length: 0 
    109     ]]> 
    110   </send> 
    111  
    112   <!-- WHATEVER --> 
    113   <recv request="REGISTER" crlf="true"> 
    114   </recv> 
    115  
    116   <send> 
    117     <![CDATA[ 
    118       SIP/2.0 200 OK 
    119       [last_Via:];received=2.2.2.2;rport=2222 
    120       [last_From:] 
    121       [last_To:];tag=[call_number] 
    122       [last_Call-ID:] 
    123       [last_CSeq:] 
    124       [last_Contact:] 
    125       Subject: Whatever 2 
    126134      Content-Length: 0 
    127135    ]]> 
Note: See TracChangeset for help on using the changeset viewer.