void pjsip_dlg_on_rx_request( pjsip_dialog *dlg, pjsip_rx_data *rdata )
{
    pj_status_t status;
    pjsip_transaction *tsx = NULL;
    pj_bool_t processed = PJ_FALSE;
    unsigned i;

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

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

    /* Check CSeq */
    if (rdata->msg_info.cseq->cseq <= dlg->remote.cseq &&
	rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD &&
	rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD)
    {
	/* Invalid CSeq.
	 * Respond statelessly with 500 (Internal Server Error)
	 */
	pj_str_t warn_text;

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

	pj_assert(pjsip_rdata_get_tsx(rdata) == NULL);
	warn_text = pj_str("Invalid CSeq");
	pjsip_endpt_respond_stateless(dlg->endpt,
				      rdata, 500, &warn_text, NULL, NULL);
	pj_log_pop_indent();
	return;
    }

    /* Update CSeq. */
    dlg->remote.cseq = rdata->msg_info.cseq->cseq;

    /* Update To tag if necessary.
     * This only happens if UAS sends a new request before answering
     * our request (e.g. UAS sends NOTIFY before answering our
     * SUBSCRIBE request).
     */
    if (dlg->remote.info->tag.slen == 0) {
	pj_strdup(dlg->pool, &dlg->remote.info->tag,
		  &rdata->msg_info.from->tag);
    }

    /* Create UAS transaction for this request. */
    if (pjsip_rdata_get_tsx(rdata) == NULL &&
	rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD)
    {
	status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx);
	if (status != PJ_SUCCESS) {
	    /* Once case for this is when re-INVITE contains same
	     * Via branch value as previous INVITE (ticket #965).
	     */
	    char errmsg[PJ_ERR_MSG_SIZE];
	    pj_str_t reason;

	    reason = pj_strerror(status, errmsg, sizeof(errmsg));
	    pjsip_endpt_respond_stateless(dlg->endpt, rdata, 500, &reason,
					  NULL, NULL);
	    goto on_return;
	}

	/* Put this dialog in the transaction data. */
	tsx->mod_data[dlg->ua->id] = dlg;

	/* Add transaction count. */
	++dlg->tsx_count;
    }

    /* Update the target URI if this is a target refresh request.
     * We have passed the basic checking for the request, I think we
     * should update the target URI regardless of whether the request
     * is accepted or not (e.g. when re-INVITE is answered with 488,
     * we would still need to update the target URI, otherwise our
     * target URI would be wrong, wouldn't it).
     */
    if (pjsip_method_creates_dialog(&rdata->msg_info.cseq->method)) {
	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;
	}
    }

    /* Report the request to dialog usages. */
    for (i=0; i<dlg->usage_cnt; ++i) {

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

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

	if (processed)
	    break;
    }

    /* Feed the first request to the transaction. */
    if (tsx)
	pjsip_tsx_recv_msg(tsx, rdata);

    /* If no dialog usages has claimed the processing of the transaction,
     * and if transaction has not sent final response, respond with
     * 500/Internal Server Error.
     */
    if (!processed && tsx && tsx->status_code < 200) {
	pjsip_tx_data *tdata;
	const pj_str_t reason = { "Unhandled by dialog usages", 26};

	PJ_LOG(4,(tsx->obj_name, "%s was unhandled by "
				 "dialog usages, sending 500 response",
				 pjsip_rx_data_get_info(rdata)));

	status = pjsip_dlg_create_response(dlg, rdata, 500, &reason, &tdata);
	if (status == PJ_SUCCESS) {
	    status = pjsip_dlg_send_response(dlg, tsx, tdata);
	}
    }

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