| 656 | |
| 657 | === I'm trying to register to a server, but PJSIP treats the 200/OK response as unregistration. Why? === #regc |
| 658 | |
| 659 | Since circa version 0.8, the registration client session (pjsip_regc.c) has stricter checks on the Contact header(s) sent by registrar in the 200/OK response to REGISTER request. This is necessary to support multiple registrations (the same AOR is registered more than once in the server by multiple user agents), and this is how it is supposed to be done in the first place according to RFC 3261. |
| 660 | |
| 661 | Unfortunately this breaks "compatibility" with some servers, because these servers incorrectly return different Contact header(s) in the response, causing PJSIP to fail to find it's registered Contact header. When this happens, PJSIP will treat the response as unregistration response, regardless whether it's a successful (200 class) response. |
| 662 | |
| 663 | The treatment of Contact header(s) in REGISTER response are specified in ''Section 10.2.4 Refreshing Bindings'' of RFC 3261: |
| 664 | ''"The 200 (OK) response from the registrar contains a list of Contact fields enumerating all current bindings. The UA compares each contact address to see if it created the contact address, using comparison rules in Section 19.1.4. If so, it updates the expiration time interval according to the expires parameter or, if absent, the Expires field value."'' |
| 665 | |
| 666 | |
| 667 | Some common mistakes by the server: |
| 668 | 1. Server modifies the Contact header when client is behind NAT. For example, client (PJSIP) sends this REGISTER request with private IP address in the Contact: |
| 669 | {{{ |
| 670 | REGISTER sip:pjsip.org SIP/2.0 |
| 671 | Contact: <sip:user@192.168.0.14> |
| 672 | .. |
| 673 | }}} |
| 674 | and server responds with this response which modifies the Contact header with the source (public) address of the request: |
| 675 | {{{ |
| 676 | SIP/2.0 200 OK |
| 677 | Contact: <sip:user@1.1.1.1:1234>;expires=300 |
| 678 | .. |
| 679 | }}} |
| 680 | This for example happens with wrong configuration in (Open)SER, where the configuration script uses '''fix_nated_contact()''' instead of '''fix_nated_register()''' in the registration handler. |
| 681 | 1. Server does not return the '''exact''' URI in the response, causing URI comparison (to find the registered Contact header in the response) to fail. The URI comparison rules are very strict, and they are described in ''Section 19.1.4 URI Comparison'' of RFC 3261. Particularly, one has to note the bullet 5 of Section 19.1.4: |
| 682 | ''"A URI omitting any component with a default value will not match a URI explicitly containing that component with its default value."'' |
| 683 | |
| 684 | This means these two URI's are '''not equivalent''' (port number is not specified, eventhough it's the default): |
| 685 | {{{<sip:user@192.168.0.1:5060>}}} [[BR]] |
| 686 | {{{<sip:user@192.168.0.1>}}} |
| 687 | |
| 688 | And neither are these (transport parameter is omitted, eventhough it's the default): |
| 689 | {{{<sip:user@192.168.0.1;transport=udp>}}} [[BR]] |
| 690 | {{{<sip:user@192.168.0.1>}}} |
| 691 | |
| 692 | ==== Solutions ==== |
| 693 | There are few solutions to handle this situation: |
| 694 | a. If the server is (Open)SER, use '''fix_nated_contact()''' instead of '''fix_nated_register()''' in the registration handler. |
| 695 | a. For other servers, fix the server because it violates the standard. |
| 696 | a. And finally as the last resort if you are unable to do the above, you can disable the strict registration Contact header checking in PJSIP. There are couple of new configuration options introduced in PJSIP v0.9 to control this: |
| 697 | - to disable the strict checks on compile time, declare this in your {{{config_site.h}}}: |
| 698 | {{{ |
| 699 | #define PJSIP_REGISTER_CLIENT_CHECK_CONTACT 0 |
| 700 | }}} |
| 701 | - to disable the check on run-time, add this statement anywhere before sending the REGISTER request (you may do this even before initializing PJSIP) to change the process wide setting: |
| 702 | {{{ |
| 703 | #include <pjsip/sip_config.h> |
| 704 | |
| 705 | pjsip_cfg()->regc.check_contact = PJ_FALSE; |
| 706 | }}} |
| 707 | When the strict check is disabled, the client registration session will calculate the expiration time (which determines whether it should treat the resposne as successful registration or unregistration) with the following rule instead: |
| 708 | - it will skip the Contact headers and get the expiration time from the ''Expires'' header instead. |
| 709 | - when ''Expires'' header is not present, it will get the value from the expires parameter of the Contact header, regardless of the URI specified in the Contact header |
| 710 | |
| 711 | |
| 712 | |