| 100 | |
| 101 | == Issues with iPhone/TCP == #iphone |
| 102 | |
| 103 | [Update 2011/01/26] |
| 104 | |
| 105 | TCP is preferred on iPhone because of the background feature, but it has been reported that simply re-registering after an IP address change is detected may not work, presumably because the TCP socket itself is already in bad state and is unable to communicate anymore. The following steps can be used to perform re-registration with a new TCP transport: |
| 106 | |
| 107 | 1. We need to keep track of which transport is being used by the registration, by implementing the {{{on_reg_state2()}}} callback. Add reference counter to it to prevent other from deleting the transport while we're referencing it (it shouldn't happen while the registration is active, but just in case). Sample code: |
| 108 | {{{ |
| 109 | static pjsua_acc_id the_acc_id; |
| 110 | static pjsip_transport *the_transport; |
| 111 | |
| 112 | static void on_reg_state2(pjsua_acc_id acc_id, pjsua_reg_info *info) |
| 113 | { |
| 114 | struct pjsip_regc_cbparam *rp = info->cbparam; |
| 115 | |
| 116 | |
| 117 | ... |
| 118 | if (acc_id != the_acc_id) |
| 119 | return; |
| 120 | |
| 121 | if (rp->code/100 == 2 && rp->expiration > 0 && rp->contact_cnt > 0) { |
| 122 | /* Registration success */ |
| 123 | if (the_transport) { |
| 124 | PJ_LOG(3,(THIS_FILE, "xxx: Releasing transport..")); |
| 125 | pjsip_transport_dec_ref(the_transport); |
| 126 | the_transport = NULL; |
| 127 | } |
| 128 | /* Save transport instance so that we can close it later when |
| 129 | * new IP address is detected. |
| 130 | */ |
| 131 | PJ_LOG(3,(THIS_FILE, "xxx: Saving transport..")); |
| 132 | the_transport = rp->rdata->tp_info.transport; |
| 133 | pjsip_transport_add_ref(the_transport); |
| 134 | } else { |
| 135 | if (the_transport) { |
| 136 | PJ_LOG(3,(THIS_FILE, "xxx: Releasing transport..")); |
| 137 | pjsip_transport_dec_ref(the_transport); |
| 138 | the_transport = NULL; |
| 139 | } |
| 140 | } |
| 141 | ... |
| 142 | } |
| 143 | }}} |
| 144 | |
| 145 | 2. When IP address change is detected: a) send unregistration, and b) close the TCP transport that we saved in step 1) above. Sample code: |
| 146 | {{{ |
| 147 | pj_status_t status; |
| 148 | |
| 149 | PJ_LOG(3,(THIS_FILE, "xxx: IP change..")); |
| 150 | |
| 151 | status = pjsua_acc_set_registration(the_acc_id, PJ_FALSE); |
| 152 | if (status != PJ_SUCCESS) |
| 153 | PJ_PERROR(1,(THIS_FILE, status, "xxx: pjsua_acc_set_registration(0) error")); |
| 154 | |
| 155 | if (the_transport) { |
| 156 | status = pjsip_transport_shutdown(the_transport); |
| 157 | if (status != PJ_SUCCESS) |
| 158 | PJ_PERROR(1,(THIS_FILE, status, "xxx: pjsip_transport_shutdown() error")); |
| 159 | pjsip_transport_dec_ref(the_transport); |
| 160 | the_transport = NULL; |
| 161 | } |
| 162 | |
| 163 | }}} |
| 164 | |
| 165 | 3. And finally, once unregistration in 2a) above is complete, re-register (with TCP). |
| 166 | |
| 167 | Note that ideally the closing the TCP transport is done in step 3 and not in step 2b. The drawback with doing it in 2b is, when the unregistration request is challenged (i.e. step 2a resulted in 401 response being received), a new TCP transport will be created, and the request retry will be sent with this new TCP transport. Your server may not like this, since it will see the unregistration request is coming from different TCP connection than the original request. But having said that, the existing TCP transport may not be in usable state anyway, so I suppose this is not a worse situation than that. But in general, you may need to tweak the timing of this closing the transport part (you may even want to put it before 2a). |