void pjsip_dlg_on_rx_response( pjsip_dialog *dlg, pjsip_rx_data *rdata )
{
    unsigned i;
    int res_code;

    PJ_LOG(5,(dlg->obj_name, "Received %s",
	      pjsip_rx_data_get_info(rdata)));
    pj_log_push_indent();

    /* Lock the dialog and inc session. */
    pjsip_dlg_inc_lock(dlg);

    /* Check that rdata already has dialog in mod_data. */
    pj_assert(pjsip_rdata_get_dlg(rdata) == dlg);

    /* Keep the response's status code */
    res_code = rdata->msg_info.msg->line.status.code;

    /* When we receive response that establishes dialog, update To tag,
     * route set and dialog target.
     *
     * The second condition of the "if" is a workaround for forking.
     * Originally, the dialog takes the first To tag seen and set it as
     * the remote tag. If the tag in 2xx response is different than this
     * tag, ACK will be sent with wrong To tag and incoming request with
     * this tag will be rejected with 481.
     *
     * The workaround for this is to take the To tag received in the
     * 2xx response and set it as remote tag.
     *
     * New update:
     * We also need to update the dialog for 1xx responses, to handle the
     * case when 100rel is used, otherwise PRACK will be sent to the
     * wrong target.
     */
    if ((dlg->state == PJSIP_DIALOG_STATE_NULL &&
	 pjsip_method_creates_dialog(&rdata->msg_info.cseq->method) &&
	 (res_code > 100 && res_code < 300) &&
	 rdata->msg_info.to->tag.slen)
	 ||
	(dlg->role==PJSIP_ROLE_UAC &&
	 !dlg->uac_has_2xx &&
	 res_code > 100 &&
	 res_code/100 <= 2 &&
	 pjsip_method_creates_dialog(&rdata->msg_info.cseq->method) &&
	 pj_stricmp(&dlg->remote.info->tag, &rdata->msg_info.to->tag)))
    {
	pjsip_contact_hdr *contact;

	/* Update remote capability info, when To tags in the dialog remote
	 * info and the incoming response are different, e.g: first response
	 * with To-tag or forking, apply strict update.
	 */
	pjsip_dlg_update_remote_cap(dlg, rdata->msg_info.msg,
				    pj_stricmp(&dlg->remote.info->tag,
					      &rdata->msg_info.to->tag));

	/* Update To tag. */
	pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);
	/* No need to update remote's tag_hval since its never used. */

	/* RFC 3271 Section 12.1.2:
	 * The route set MUST be set to the list of URIs in the Record-Route
	 * header field from the response, taken in reverse order and
	 * preserving all URI parameters. If no Record-Route header field
	 * is present in the response, the route set MUST be set to the
	 * empty set. This route set, even if empty, overrides any pre-existing
	 * route set for future requests in this dialog.
	 */
	dlg_update_routeset(dlg, rdata);

	/* The remote target MUST be set to the URI from the Contact header
	 * field of the response.
	 */
	contact = (pjsip_contact_hdr*)
		  pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
				     NULL);
	if (contact && contact->uri &&
	    (dlg->remote.contact==NULL ||
	     pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI,
			   dlg->remote.contact->uri,
			   contact->uri)))
	{
	    dlg->remote.contact = (pjsip_contact_hdr*)
	    			  pjsip_hdr_clone(dlg->pool, contact);
	    dlg->target = dlg->remote.contact->uri;
	}

	dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED;

	/* Prevent dialog from being updated just in case more 2xx
	 * gets through this dialog (it shouldn't happen).
	 */
	if (dlg->role==PJSIP_ROLE_UAC && !dlg->uac_has_2xx &&
	    res_code/100==2)
	{
	    dlg->uac_has_2xx = PJ_TRUE;
	}
    }

    /* Update remote target (again) when receiving 2xx response messages
     * that's defined as target refresh.
     *
     * Also upon receiving 2xx response, recheck again the route set.
     * This is for compatibility with RFC 2543, as described in Section
     * 13.2.2.4 of RFC 3261:

	If the dialog identifier in the 2xx response matches the dialog
	identifier of an existing dialog, the dialog MUST be transitioned to
	the "confirmed" state, and the route set for the dialog MUST be
	recomputed based on the 2xx response using the procedures of Section
	12.2.1.2.

	Note that the only piece of state that is recomputed is the route
	set.  Other pieces of state such as the highest sequence numbers
	(remote and local) sent within the dialog are not recomputed.  The
	route set only is recomputed for backwards compatibility.  RFC
	2543 did not mandate mirroring of the Record-Route header field in
	a 1xx, only 2xx.
     */
    if (pjsip_method_creates_dialog(&rdata->msg_info.cseq->method) &&
	res_code/100 == 2)
    {
	pjsip_contact_hdr *contact;

	contact = (pjsip_contact_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
							  PJSIP_H_CONTACT,
				     			  NULL);
	if (contact && contact->uri &&
	    (dlg->remote.contact==NULL ||
	     pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI,
			   dlg->remote.contact->uri,
			   contact->uri)))
	{
	    dlg->remote.contact = (pjsip_contact_hdr*)
	    			  pjsip_hdr_clone(dlg->pool, contact);
	    dlg->target = dlg->remote.contact->uri;
	}

	dlg_update_routeset(dlg, rdata);

	/* Update remote capability info after the first 2xx response
	 * (ticket #1539). Note that the remote capability retrieved here
	 * will be assumed to remain unchanged for the duration of the dialog.
	 */
	if (dlg->role==PJSIP_ROLE_UAC && !dlg->uac_has_2xx) {
	    pjsip_dlg_update_remote_cap(dlg, rdata->msg_info.msg, PJ_FALSE);
	    dlg->uac_has_2xx = PJ_TRUE;
	}
    }

    /* Pass to dialog usages. */
    for (i=0; i<dlg->usage_cnt; ++i) {
	pj_bool_t processed;

	if (!dlg->usage[i]->on_rx_response)
	    continue;

	processed = (*dlg->usage[i]->on_rx_response)(rdata);

	if (processed)
	    break;
    }

    /* Handle the case of forked response, when the application creates
     * the forked dialog but not the invite session. In this case, the
     * forked 200/OK response will be unhandled, and we must send ACK
     * here.
     */
    if (dlg->usage_cnt==0) {
	pj_status_t status;

	if (rdata->msg_info.cseq->method.id==PJSIP_INVITE_METHOD &&
	    rdata->msg_info.msg->line.status.code/100 == 2)
	{
	    pjsip_tx_data *ack;

	    status = pjsip_dlg_create_request(dlg, &pjsip_ack_method,
					      rdata->msg_info.cseq->cseq,
					      &ack);
	    if (status == PJ_SUCCESS)
		status = pjsip_dlg_send_request(dlg, ack, -1, NULL);
	} else if (rdata->msg_info.msg->line.status.code==401 ||
		   rdata->msg_info.msg->line.status.code==407)
	{
	    pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);
	    pjsip_tx_data *tdata;

	    status = pjsip_auth_clt_reinit_req( &dlg->auth_sess,
						rdata, tsx->last_tx,
						&tdata);

	    if (status == PJ_SUCCESS) {
		/* Re-send request. */
		status = pjsip_dlg_send_request(dlg, tdata, -1, NULL);
	    }
	}
    }

    /* Unhandled response does not necessarily mean error because
       dialog usages may choose to process the transaction state instead.
    if (i==dlg->usage_cnt) {
	PJ_LOG(4,(dlg->obj_name, "%s was not claimed by any dialog usages",
		  pjsip_rx_data_get_info(rdata)));
    }
    */

    /* Unlock dialog and dec session, may destroy dialog. */
    pjsip_dlg_dec_lock(dlg);

    pj_log_pop_indent();
}