Changeset 1959 for pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c
- Timestamp:
- May 17, 2008 12:45:00 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c
r1946 r1959 36 36 37 37 #define REFRESH_TIMER 1 38 #define DELAY_BEFORE_REFRESH 538 #define DELAY_BEFORE_REFRESH PJSIP_REGISTER_CLIENT_DELAY_BEFORE_REFRESH 39 39 #define THIS_FILE "sip_reg.c" 40 40 … … 44 44 #define REGC_TSX_TIMEOUT 33000 45 45 46 enum { NOEXP = 0x1FFFFFFF }; 47 48 static const pj_str_t XUID_PARAM_NAME = { "x-uid", 5 }; 49 50 51 /* Current/pending operation */ 52 enum regc_op 53 { 54 REGC_IDLE, 55 REGC_REGISTERING, 56 REGC_UNREGISTERING 57 }; 46 58 47 59 /** … … 55 67 pj_bool_t has_tsx; 56 68 pj_int32_t busy; 69 enum regc_op current_op; 70 71 pj_bool_t add_xuid_param; 57 72 58 73 void *token; … … 66 81 pjsip_from_hdr *from_hdr; 67 82 pjsip_to_hdr *to_hdr; 68 pjsip_hdr contact_hdr_list; 83 pjsip_contact_hdr contact_hdr_list; 84 pjsip_contact_hdr removed_contact_hdr_list; 69 85 pjsip_expires_hdr *expires_hdr; 70 pjsip_contact_hdr *unreg_contact_hdr;71 pjsip_expires_hdr *unreg_expires_hdr;72 86 pj_uint32_t expires; 73 87 pjsip_route_hdr route_set; … … 93 107 94 108 95 96 109 PJ_DEF(pj_status_t) pjsip_regc_create( pjsip_endpoint *endpt, void *token, 97 110 pjsip_regc_cb *cb, … … 115 128 regc->cb = cb; 116 129 regc->expires = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED; 130 regc->add_xuid_param = pjsip_cfg()->regc.add_xuid_param; 117 131 118 132 status = pjsip_auth_clt_init(®c->auth_sess, endpt, regc->pool, 0); … … 123 137 pj_list_init(®c->hdr_list); 124 138 pj_list_init(®c->contact_hdr_list); 139 pj_list_init(®c->removed_contact_hdr_list); 125 140 126 141 /* Done */ … … 142 157 pjsip_transport_dec_ref(regc->last_transport); 143 158 regc->last_transport = NULL; 159 } 160 if (regc->timer.id != 0) { 161 pjsip_endpt_cancel_timer(regc->endpt, ®c->timer); 162 regc->timer.id = 0; 144 163 } 145 164 pjsip_endpt_release_pool(regc->endpt, regc->pool); … … 200 219 { 201 220 const pj_str_t CONTACT = { "Contact", 7 }; 221 pjsip_contact_hdr *h; 202 222 int i; 203 223 204 /* Clear existing contacts */ 205 pj_list_init(®c->contact_hdr_list); 206 224 /* Save existing contact list to removed_contact_hdr_list and 225 * clear contact_hdr_list. 226 */ 227 pj_list_merge_last(®c->removed_contact_hdr_list, 228 ®c->contact_hdr_list); 229 230 /* Set the expiration of Contacts in to removed_contact_hdr_list 231 * zero. 232 */ 233 h = regc->removed_contact_hdr_list.next; 234 while (h != ®c->removed_contact_hdr_list) { 235 h->expires = 0; 236 h = h->next; 237 } 238 239 /* Process new contacts */ 207 240 for (i=0; i<contact_cnt; ++i) { 208 pjsip_ hdr *hdr;241 pjsip_contact_hdr *hdr; 209 242 pj_str_t tmp; 210 243 211 244 pj_strdup_with_null(regc->pool, &tmp, &contact[i]); 212 hdr = (pjsip_ hdr*)245 hdr = (pjsip_contact_hdr*) 213 246 pjsip_parse_hdr(regc->pool, &CONTACT, tmp.ptr, tmp.slen, NULL); 214 247 if (hdr == NULL) { … … 216 249 (int)tmp.slen, tmp.ptr)); 217 250 return PJSIP_EINVALIDURI; 251 } 252 253 /* Find the new contact in old contact list. If found, remove 254 * the old header from the old header list. 255 */ 256 h = regc->removed_contact_hdr_list.next; 257 while (h != ®c->removed_contact_hdr_list) { 258 int rc; 259 260 rc = pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, 261 h->uri, hdr->uri); 262 if (rc == 0) { 263 /* Match */ 264 pj_list_erase(h); 265 break; 266 } 267 268 h = h->next; 269 } 270 271 /* If add_xuid_param option is enabled and Contact URI is sip/sips, 272 * add xuid parameter to assist matching the Contact URI in the 273 * REGISTER response later. 274 */ 275 if (regc->add_xuid_param && (PJSIP_URI_SCHEME_IS_SIP(hdr->uri) || 276 PJSIP_URI_SCHEME_IS_SIPS(hdr->uri))) 277 { 278 pjsip_param *xuid_param; 279 pjsip_sip_uri *sip_uri; 280 281 xuid_param = PJ_POOL_ZALLOC_T(regc->pool, pjsip_param); 282 xuid_param->name = XUID_PARAM_NAME; 283 pj_create_unique_string(regc->pool, &xuid_param->value); 284 285 sip_uri = pjsip_uri_get_uri(hdr->uri); 286 pj_list_push_back(&sip_uri->other_param, xuid_param); 218 287 } 219 288 … … 288 357 regc->cseq_hdr->cseq = pj_rand() % 0xFFFF; 289 358 pjsip_method_set( ®c->cseq_hdr->method, PJSIP_REGISTER_METHOD); 290 291 /* Create "Contact" header used in unregistration. */292 regc->unreg_contact_hdr = pjsip_contact_hdr_create(regc->pool);293 regc->unreg_contact_hdr->star = 1;294 295 /* Create "Expires" header used in unregistration. */296 regc->unreg_expires_hdr = pjsip_expires_hdr_create( regc->pool, 0);297 359 298 360 /* Done. */ … … 437 499 { 438 500 pjsip_msg *msg; 439 pjsip_ hdr *hdr;501 pjsip_contact_hdr *hdr; 440 502 pj_status_t status; 441 503 pjsip_tx_data *tdata; … … 457 519 } 458 520 521 /* Also add bindings which are to be removed */ 522 while (!pj_list_empty(®c->removed_contact_hdr_list)) { 523 hdr = regc->removed_contact_hdr_list.next; 524 pjsip_msg_add_hdr(msg, (pjsip_hdr*) 525 pjsip_hdr_clone(tdata->pool, hdr)); 526 pj_list_erase(hdr); 527 } 528 529 459 530 if (regc->expires_hdr) 460 531 pjsip_msg_add_hdr(msg, (pjsip_hdr*) … … 497 568 498 569 /* Add Contact headers. */ 499 hdr = regc->contact_hdr_list.next;500 while (hdr != ®c->contact_hdr_list) {570 hdr = (pjsip_hdr*)regc->contact_hdr_list.next; 571 while (hdr != (pjsip_hdr*)®c->contact_hdr_list) { 501 572 pjsip_msg_add_hdr(msg, (pjsip_hdr*) 502 573 pjsip_hdr_shallow_clone(tdata->pool, hdr)); … … 504 575 } 505 576 506 pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr); 577 /* Also add bindings which are to be removed */ 578 while (!pj_list_empty(®c->removed_contact_hdr_list)) { 579 hdr = (pjsip_hdr*)regc->removed_contact_hdr_list.next; 580 pjsip_msg_add_hdr(msg, (pjsip_hdr*) 581 pjsip_hdr_clone(tdata->pool, hdr)); 582 pj_list_erase(hdr); 583 } 584 585 /* Add Expires:0 header */ 586 hdr = (pjsip_hdr*) pjsip_expires_hdr_create(tdata->pool, 0); 587 pjsip_msg_add_hdr(msg, hdr); 507 588 508 589 *p_tdata = tdata; … … 514 595 { 515 596 pjsip_tx_data *tdata; 597 pjsip_contact_hdr *hcontact; 598 pjsip_hdr *hdr; 516 599 pjsip_msg *msg; 517 600 pj_status_t status; … … 529 612 530 613 msg = tdata->msg; 531 pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_contact_hdr); 532 pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr); 614 615 /* Clear removed_contact_hdr_list */ 616 pj_list_init(®c->removed_contact_hdr_list); 617 618 /* Add Contact:* header */ 619 hcontact = pjsip_contact_hdr_create(tdata->pool); 620 hcontact->star = 1; 621 pjsip_msg_add_hdr(msg, (pjsip_hdr*)hcontact); 622 623 /* Add Expires:0 header */ 624 hdr = (pjsip_hdr*) pjsip_expires_hdr_create(tdata->pool, 0); 625 pjsip_msg_add_hdr(msg, hdr); 533 626 534 627 *p_tdata = tdata; … … 616 709 } 617 710 711 static pj_int32_t calculate_response_expiration(const pjsip_regc *regc, 712 const pjsip_rx_data *rdata, 713 unsigned *contact_cnt, 714 unsigned max_contact, 715 pjsip_contact_hdr *contacts[]) 716 { 717 pj_int32_t expiration = NOEXP; 718 const pjsip_msg *msg = rdata->msg_info.msg; 719 const pjsip_hdr *hdr; 720 721 /* Enumerate all Contact headers in the response */ 722 *contact_cnt = 0; 723 for (hdr=msg->hdr.next; hdr!=&msg->hdr; hdr=hdr->next) { 724 if (hdr->type == PJSIP_H_CONTACT && 725 *contact_cnt < max_contact) 726 { 727 contacts[*contact_cnt] = (pjsip_contact_hdr*)hdr; 728 ++(*contact_cnt); 729 } 730 } 731 732 if (regc->current_op == REGC_REGISTERING) { 733 pj_bool_t has_our_contact = PJ_FALSE; 734 const pjsip_expires_hdr *expires; 735 736 /* Get Expires header */ 737 expires = (const pjsip_expires_hdr*) 738 pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL); 739 740 /* Try to find the Contact URIs that we register, in the response 741 * to get the expires value. We'll try both with comparing the URI 742 * and comparing the extension param only. 743 */ 744 if (pjsip_cfg()->regc.check_contact || regc->add_xuid_param) { 745 unsigned i; 746 for (i=0; i<*contact_cnt; ++i) { 747 const pjsip_contact_hdr *our_hdr; 748 749 our_hdr = (const pjsip_contact_hdr*) 750 regc->contact_hdr_list.next; 751 752 /* Match with our Contact header(s) */ 753 while ((void*)our_hdr != (void*)®c->contact_hdr_list) { 754 755 const pjsip_uri *uri1, *uri2; 756 pj_bool_t matched = PJ_FALSE; 757 758 /* Exclude the display name when comparing the URI 759 * since server may not return it. 760 */ 761 uri1 = (const pjsip_uri*) 762 pjsip_uri_get_uri(contacts[i]->uri); 763 uri2 = (const pjsip_uri*) 764 pjsip_uri_get_uri(our_hdr->uri); 765 766 /* First try with exact matching, according to RFC 3261 767 * Section 19.1.4 URI Comparison 768 */ 769 if (pjsip_cfg()->regc.check_contact) { 770 matched = pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, 771 uri1, uri2)==0; 772 } 773 774 /* If no match is found, try with matching the extension 775 * parameter only if extension parameter was added. 776 */ 777 if (!matched && regc->add_xuid_param && 778 (PJSIP_URI_SCHEME_IS_SIP(uri1) || 779 PJSIP_URI_SCHEME_IS_SIPS(uri1)) && 780 (PJSIP_URI_SCHEME_IS_SIP(uri2) || 781 PJSIP_URI_SCHEME_IS_SIPS(uri2))) 782 { 783 const pjsip_sip_uri *sip_uri1, *sip_uri2; 784 const pjsip_param *p1, *p2; 785 786 sip_uri1 = (const pjsip_sip_uri*)uri1; 787 sip_uri2 = (const pjsip_sip_uri*)uri2; 788 789 p1 = pjsip_param_cfind(&sip_uri1->other_param, 790 &XUID_PARAM_NAME); 791 p2 = pjsip_param_cfind(&sip_uri2->other_param, 792 &XUID_PARAM_NAME); 793 matched = p1 && p2 && 794 pj_strcmp(&p1->value, &p2->value)==0; 795 796 } 797 798 if (matched) { 799 has_our_contact = PJ_TRUE; 800 801 if (contacts[i]->expires >= 0 && 802 contacts[i]->expires < expiration) 803 { 804 /* Get the lowest expiration time. */ 805 expiration = contacts[i]->expires; 806 } 807 808 break; 809 } 810 811 our_hdr = our_hdr->next; 812 813 } /* while ((void.. */ 814 815 } /* for (i=.. */ 816 817 /* If matching Contact header(s) are found but the 818 * header doesn't contain expires parameter, get the 819 * expiration value from the Expires header. And 820 * if Expires header is not present, get the expiration 821 * value from the request. 822 */ 823 if (has_our_contact && expiration == NOEXP) { 824 if (expires) { 825 expiration = expires->ivalue; 826 } else if (regc->expires_hdr) { 827 expiration = regc->expires_hdr->ivalue; 828 } else { 829 /* We didn't request explicit expiration value, 830 * and server doesn't specify it either. This 831 * shouldn't happen unless we have a broken 832 * registrar. 833 */ 834 expiration = 3600; 835 } 836 } 837 838 } 839 840 /* If we still couldn't get matching Contact header(s), it means 841 * there must be something wrong with the registrar (e.g. it may 842 * have modified the URI's in the response, which is prohibited). 843 */ 844 if (expiration==NOEXP) { 845 /* If the number of Contact headers in the response matches 846 * ours, they're all probably ours. Get the expiration 847 * from there if this is the case, or from Expires header 848 * if we don't have exact Contact header count, or 849 * from the request as the last resort. 850 */ 851 unsigned our_contact_cnt; 852 853 our_contact_cnt = pj_list_size(®c->contact_hdr_list); 854 855 if (*contact_cnt == our_contact_cnt && *contact_cnt && 856 contacts[0]->expires >= 0) 857 { 858 expiration = contacts[0]->expires; 859 } else if (expires) 860 expiration = expires->ivalue; 861 else if (regc->expires_hdr) 862 expiration = regc->expires_hdr->ivalue; 863 else 864 expiration = 3600; 865 } 866 867 } else { 868 /* Just assume that the unregistration has been successful. */ 869 expiration = 0; 870 } 871 872 /* Must have expiration value by now */ 873 pj_assert(expiration != NOEXP); 874 875 return expiration; 876 } 877 618 878 static void tsx_callback(void *token, pjsip_event *event) 619 879 { … … 645 905 pjsip_rx_data *rdata = event->body.tsx_state.src.rdata; 646 906 pjsip_tx_data *tdata; 907 908 /* reset current op */ 909 regc->current_op = REGC_IDLE; 647 910 648 911 status = pjsip_auth_clt_reinit_req( ®c->auth_sess, … … 683 946 */ 684 947 685 /* Nothing to do*/686 ;948 /* Just reset current op */ 949 regc->current_op = REGC_IDLE; 687 950 688 951 } else { 689 int contact_cnt = 0; 952 pjsip_rx_data *rdata; 953 pj_int32_t expiration = NOEXP; 954 unsigned contact_cnt = 0; 690 955 pjsip_contact_hdr *contact[PJSIP_REGC_MAX_CONTACT]; 691 pjsip_rx_data *rdata;692 enum { NOEXP = 0x1FFFFFFF };693 pj_int32_t expiration = NOEXP;694 956 695 957 if (tsx->status_code/100 == 2) { 696 int i;697 pjsip_contact_hdr *hdr;698 pjsip_msg *msg;699 pj_bool_t has_our_contact = PJ_FALSE;700 pjsip_expires_hdr *expires;701 958 702 959 rdata = event->body.tsx_state.src.rdata; 703 msg = rdata->msg_info.msg; 704 705 /* Record all Contact headers in the response */ 706 hdr = (pjsip_contact_hdr*) 707 pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL); 708 while (hdr) { 709 contact[contact_cnt++] = hdr; 710 hdr = hdr->next; 711 if (hdr == (void*)&msg->hdr) 712 break; 713 hdr = (pjsip_contact_hdr*) 714 pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, hdr); 715 } 716 717 /* Set default expiration value to the value of Expires hdr */ 718 expires = (pjsip_expires_hdr*) 719 pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL); 720 721 if (expires) 722 expiration = expires->ivalue; 723 724 /* Enumerate all Contact headers found in the response and 725 * find the Contact(s) that we register. 726 * 727 * Note: 728 * by default we require that the exact same URI that we 729 * register is returned in the 200/OK response (by exact, 730 * meaning all URI components including transport param), 731 * otherwise if we don't detect that our URI is there, we 732 * treat registration as failed. 733 * 734 * If your registrar server couldn't do this, you can 735 * disable this exact URI checking. See the compile time 736 * setting PJSIP_REGISTER_CLIENT_CHECK_CONTACT or the 737 * corresponding run-time setting in pjsip_cfg(). 738 */ 739 for (i=0; i<contact_cnt && pjsip_cfg()->regc.check_contact; ++i) { 740 pjsip_contact_hdr *our_contact; 741 742 our_contact = (pjsip_contact_hdr*) 743 regc->contact_hdr_list.next; 744 745 while ((void*)our_contact != (void*)®c->contact_hdr_list) { 746 747 const pjsip_uri *uri1, *uri2; 748 749 /* Compare URIs. 750 * Exclude the display name when comparing the URI since 751 * server may not return it. 752 */ 753 754 uri1=(const pjsip_uri*)pjsip_uri_get_uri(contact[i]->uri); 755 uri2=(const pjsip_uri*)pjsip_uri_get_uri(our_contact->uri); 756 if (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, uri1, uri2)==0) 757 { 758 has_our_contact = PJ_TRUE; 759 760 if (contact[i]->expires >= 0 && 761 contact[i]->expires < expiration) 762 { 763 /* Get the lowest expiration time. */ 764 expiration = contact[i]->expires; 765 } 766 } 767 768 our_contact = our_contact->next; 769 } 770 } 771 772 /* If regc.check_contact is disabled, and no Expires header 773 * has been found, but the server does return one single 774 * Contact header, assumes that the server is broken/unable to 775 * return the correct Contact. In this case, get the expiration 776 * from the single Contact header in the response. 777 */ 778 if (expiration==NOEXP && !pjsip_cfg()->regc.check_contact && 779 contact_cnt==1) 780 { 781 if (contact[0]->expires >= 0) 782 expiration = contact[0]->expires; 783 } 784 785 /* When the response doesn't contain our Contact header, that 786 * means we have been unregistered. 787 */ 788 if (pjsip_cfg()->regc.check_contact && !has_our_contact) 789 expiration = 0; 960 961 /* Calculate expiration */ 962 expiration = calculate_response_expiration(regc, rdata, 963 &contact_cnt, 964 PJSIP_REGC_MAX_CONTACT, 965 contact); 966 967 /* Mark operation as complete */ 968 regc->current_op = REGC_IDLE; 790 969 791 970 /* Schedule next registration */ 792 if (regc->auto_reg && expiration != 0 && expiration != NOEXP) {971 if (regc->auto_reg && expiration > 0) { 793 972 pj_time_val delay = { 0, 0}; 794 973 … … 820 999 ++regc->busy; 821 1000 1001 /* Update registration */ 1002 if (expiration==NOEXP) expiration=-1; 1003 regc->expires = expiration; 1004 822 1005 /* Call callback. */ 823 if (expiration == NOEXP) expiration = -1;824 1006 call_callback(regc, PJ_SUCCESS, tsx->status_code, 825 1007 (rdata ? &rdata->msg_info.msg->line.status.reason … … 842 1024 pj_status_t status; 843 1025 pjsip_cseq_hdr *cseq_hdr; 1026 pjsip_expires_hdr *expires_hdr; 844 1027 pj_uint32_t cseq; 845 1028 … … 852 1035 } 853 1036 1037 pj_assert(regc->current_op == REGC_IDLE); 1038 854 1039 /* Invalidate message buffer. */ 855 1040 pjsip_tx_data_invalidate_msg(tdata); … … 861 1046 cseq_hdr->cseq = cseq; 862 1047 1048 /* Find Expires header */ 1049 expires_hdr = (pjsip_expires_hdr*) 1050 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_EXPIRES, NULL); 1051 863 1052 /* Bind to transport selector */ 864 1053 pjsip_tx_data_set_transport(tdata, ®c->tp_sel); … … 869 1058 regc->has_tsx = PJ_TRUE; 870 1059 ++regc->busy; 1060 1061 /* Set current operation based on the value of Expires header */ 1062 if (expires_hdr && expires_hdr->ivalue==0) 1063 regc->current_op = REGC_UNREGISTERING; 1064 else 1065 regc->current_op = REGC_REGISTERING; 1066 871 1067 status = pjsip_endpt_send_request(regc->endpt, tdata, REGC_TSX_TIMEOUT, 872 1068 regc, &tsx_callback);
Note: See TracChangeset
for help on using the changeset viewer.