Esempio n. 1
0
struct ast_taskprocessor *ast_sip_get_distributor_serializer(pjsip_rx_data *rdata)
{
	int hash;
	pj_str_t *remote_tag;
	struct ast_taskprocessor *serializer;

	if (!rdata->msg_info.msg) {
		return NULL;
	}

	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
		remote_tag = &rdata->msg_info.from->tag;
	} else {
		remote_tag = &rdata->msg_info.to->tag;
	}

	/* Compute the hash from the SIP message call-id and remote-tag */
	hash = pjstr_hash(&rdata->msg_info.cid->id);
	hash = pjstr_hash_add(remote_tag, hash);
	hash = ast_str_hash_restrict(hash);

	serializer = ao2_bump(distributor_pool[hash % ARRAY_LEN(distributor_pool)]);
	if (serializer) {
		ast_debug(3, "Calculated serializer %s to use for %s\n",
			ast_taskprocessor_name(serializer), pjsip_rx_data_get_info(rdata));
	}
	return serializer;
}
Esempio n. 2
0
/*!
 * \internal
 * \brief Find the request tdata to get the serializer it used.
 * \since 14.0.0
 *
 * \param rdata The incoming message.
 *
 * \retval serializer on success.
 * \retval NULL on error or could not find the serializer.
 */
static struct ast_taskprocessor *find_request_serializer(pjsip_rx_data *rdata)
{
	struct ast_taskprocessor *serializer = NULL;
	pj_str_t tsx_key;
	pjsip_transaction *tsx;

	pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAC,
		&rdata->msg_info.cseq->method, rdata);

	tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
	if (!tsx) {
		ast_debug(1, "Could not find transaction for %s.\n",
			pjsip_rx_data_get_info(rdata));
		return NULL;
	}
	ast_debug(3, "Found transaction %s for %s.\n",
		tsx->obj_name, pjsip_rx_data_get_info(rdata));

	if (tsx->last_tx) {
		const char *serializer_name;

		serializer_name = tsx->last_tx->mod_data[distributor_mod.id];
		if (!ast_strlen_zero(serializer_name)) {
			serializer = ast_taskprocessor_get(serializer_name, TPS_REF_IF_EXISTS);
			if (serializer) {
				ast_debug(3, "Found serializer %s on transaction %s\n",
						serializer_name, tsx->obj_name);
			}
		}
	}

#ifdef HAVE_PJ_TRANSACTION_GRP_LOCK
	pj_grp_lock_release(tsx->grp_lock);
#else
	pj_mutex_unlock(tsx->mutex);
#endif

	return serializer;
}
Esempio n. 3
0
static void local_log_rx_msg(pjsip_rx_data* rdata)
{
  LOG_VERBOSE("RX %d bytes %s from %s %s:%d:\n"
              "--start msg--\n\n"
              "%.*s\n"
              "--end msg--",
              rdata->msg_info.len,
              pjsip_rx_data_get_info(rdata),
              rdata->tp_info.transport->type_name,
              rdata->pkt_info.src_name,
              rdata->pkt_info.src_port,
              (int)rdata->msg_info.len,
              rdata->msg_info.msg_buf);
}
Esempio n. 4
0
/* Notification on incoming messages */
static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
{
    PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n"
			 "%.*s\n"
			 "--end msg--",
			 rdata->msg_info.len,
			 pjsip_rx_data_get_info(rdata),
			 rdata->tp_info.transport->type_name,
			 rdata->pkt_info.src_name,
			 rdata->pkt_info.src_port,
			 (int)rdata->msg_info.len,
			 rdata->msg_info.msg_buf));
    
    /* Always return false, otherwise messages will not get processed! */
    return PJ_FALSE;
}
Esempio n. 5
0
/* Notification on incoming messages */
static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
{
    if (!app.enable_msg_logging)
	return PJ_FALSE;

    PJ_LOG(3,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n"
			 "%.*s\n"
			 "--end msg--",
			 rdata->msg_info.len,
			 pjsip_rx_data_get_info(rdata),
			 rdata->tp_info.transport->type_name,
			 rdata->pkt_info.src_name,
			 rdata->pkt_info.src_port,
			 (int)rdata->msg_info.len,
			 rdata->msg_info.msg_buf));
    return PJ_FALSE;
}
Esempio n. 6
0
static pj_bool_t on_rx_msg(pjsip_rx_data *rdata)
{
    if (msg_log_enabled) {
	PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%s:%d:\n"
			     "%.*s\n"
			     "--end msg--",
			     rdata->msg_info.len,
			     pjsip_rx_data_get_info(rdata),
			     rdata->tp_info.transport->type_name,
			     rdata->pkt_info.src_name,
			     rdata->pkt_info.src_port,
			     rdata->msg_info.len,
			     rdata->msg_info.msg_buf));
    }

    return PJ_FALSE;
}
Esempio n. 7
0
static void
transfer_client_cb(pjsip_evsub *sub, pjsip_event *event)
{
    auto link = getSIPVoIPLink();
    if (not link) {
        RING_ERR("no more VoIP link");
        return;
    }

    auto mod_ua_id = link->getModId();

    switch (pjsip_evsub_get_state(sub)) {
        case PJSIP_EVSUB_STATE_ACCEPTED:
            if (!event)
                return;

            pj_assert(event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
            break;

        case PJSIP_EVSUB_STATE_TERMINATED:
            pjsip_evsub_set_mod_data(sub, mod_ua_id, NULL);
            break;

        case PJSIP_EVSUB_STATE_ACTIVE: {
            if (!event)
                return;

            pjsip_rx_data* r_data = event->body.rx_msg.rdata;

            if (!r_data)
                return;

            std::string request(pjsip_rx_data_get_info(r_data));

            pjsip_status_line status_line = { 500, *pjsip_get_status_text(500) };

            if (!r_data->msg_info.msg)
                return;

            if (r_data->msg_info.msg->line.req.method.id == PJSIP_OTHER_METHOD and
                    request.find("NOTIFY") != std::string::npos) {
                pjsip_msg_body *body = r_data->msg_info.msg->body;

                if (!body)
                    return;

                if (pj_stricmp2(&body->content_type.type, "message") or
                        pj_stricmp2(&body->content_type.subtype, "sipfrag"))
                    return;

                if (pjsip_parse_status_line((char*) body->data, body->len, &status_line) != PJ_SUCCESS)
                    return;
            }

            if (!r_data->msg_info.cid)
                return;

            auto call = static_cast<SIPCall *>(pjsip_evsub_get_mod_data(sub, mod_ua_id));
            if (!call)
                return;

            if (status_line.code / 100 == 2) {
                if (call->inv)
                    call->terminateSipSession(PJSIP_SC_GONE);
                Manager::instance().hangupCall(call->getCallId());
                pjsip_evsub_set_mod_data(sub, mod_ua_id, NULL);
            }

            break;
        }

        case PJSIP_EVSUB_STATE_NULL:
        case PJSIP_EVSUB_STATE_SENT:
        case PJSIP_EVSUB_STATE_PENDING:
        case PJSIP_EVSUB_STATE_UNKNOWN:
        default:
            break;
    }
}
Esempio n. 8
0
/*
 * This is the handler to receive message for this test. It is used to
 * control and verify the behavior of the message transmitted by the
 * transaction.
 */
static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
{
    if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST1_BRANCH_ID) == 0) {
	/*
	 * The TEST1_BRANCH_ID test performs the verifications for transaction
	 * retransmission mechanism. It will not answer the incoming request
	 * with any response.
	 */
	pjsip_msg *msg = rdata->msg_info.msg;

	PJ_LOG(4,(THIS_FILE, "    received request"));

	/* Only wants to take INVITE or OPTIONS method. */
	if (msg->line.req.method.id != PJSIP_INVITE_METHOD &&
	    msg->line.req.method.id != PJSIP_OPTIONS_METHOD)
	{
	    PJ_LOG(3,(THIS_FILE, "    error: received unexpected method %.*s",
			  msg->line.req.method.name.slen,
			  msg->line.req.method.name.ptr));
	    test_complete = -600;
	    return PJ_TRUE;
	}

	if (recv_count == 0) {
	    recv_count++;
	    //pj_gettimeofday(&recv_last);
	    recv_last = rdata->pkt_info.timestamp;
	} else {
	    pj_time_val now;
	    unsigned msec_expected, msec_elapsed;
	    int max_received;

	    //pj_gettimeofday(&now);
	    now = rdata->pkt_info.timestamp;
	    PJ_TIME_VAL_SUB(now, recv_last);
	    msec_elapsed = now.sec*1000 + now.msec;

	    ++recv_count;
    	    msec_expected = (1<<(recv_count-2))*PJSIP_T1_TIMEOUT;

	    if (msg->line.req.method.id != PJSIP_INVITE_METHOD) {
		if (msec_expected > PJSIP_T2_TIMEOUT)
		    msec_expected = PJSIP_T2_TIMEOUT;
		max_received = 11;
	    } else {
		max_received = 7;
	    }

	    if (DIFF(msec_expected, msec_elapsed) > TEST1_ALLOWED_DIFF) {
		PJ_LOG(3,(THIS_FILE,
			  "    error: expecting retransmission no. %d in %d "
			  "ms, received in %d ms",
			  recv_count-1, msec_expected, msec_elapsed));
		test_complete = -610;
	    }

	    
	    if (recv_count > max_received) {
		PJ_LOG(3,(THIS_FILE, 
			  "    error: too many messages (%d) received",
			  recv_count));
		test_complete = -620;
	    }

	    //pj_gettimeofday(&recv_last);
	    recv_last = rdata->pkt_info.timestamp;
	}
	return PJ_TRUE;

    } else
    if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID) == 0) {
	/*
	 * The TEST4_BRANCH_ID test simulates transport failure after several
	 * retransmissions.
	 */
	recv_count++;

	if (recv_count == TEST4_RETRANSMIT_CNT) {
	    /* Simulate transport failure. */
	    pjsip_loop_set_failure(loop, 2, NULL);

	} else if (recv_count > TEST4_RETRANSMIT_CNT) {
	    PJ_LOG(3,(THIS_FILE,"   error: not expecting %d-th packet!",
		      recv_count));
	    test_complete = -631;
	}

	return PJ_TRUE;


    } else
    if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID) == 0) {
	/*
	 * The TEST5_BRANCH_ID test simulates user terminating the transaction
	 * after several retransmissions.
	 */
	recv_count++;

	if (recv_count == TEST5_RETRANSMIT_CNT+1) {
	    pj_str_t key;
	    pjsip_transaction *tsx;

	    pjsip_tsx_create_key( rdata->tp_info.pool, &key, PJSIP_ROLE_UAC,
				  &rdata->msg_info.msg->line.req.method, rdata);
	    tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
	    if (tsx) {
		pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
		pj_mutex_unlock(tsx->mutex);
	    } else {
		PJ_LOG(3,(THIS_FILE, "    error: uac transaction not found!"));
		test_complete = -633;
	    }

	} else if (recv_count > TEST5_RETRANSMIT_CNT+1) {
	    PJ_LOG(3,(THIS_FILE,"   error: not expecting %d-th packet!",
		      recv_count));
	    test_complete = -634;
	}

	return PJ_TRUE;

    } else
    if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID) == 0) {
	/*
	 * The TEST6_BRANCH_ID test successfull non-INVITE transaction.
	 */
	pj_status_t status;

	recv_count++;

	if (recv_count > 1) {
	    PJ_LOG(3,(THIS_FILE,"   error: not expecting %d-th packet!",
		      recv_count));
	    test_complete = -635;
	}

	status = pjsip_endpt_respond_stateless(endpt, rdata, 202, NULL,
					       NULL, NULL);
	if (status != PJ_SUCCESS) {
	    app_perror("    error: unable to send response", status);
	    test_complete = -636;
	}

	return PJ_TRUE;


    } else
    if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST7_BRANCH_ID) == 0) {
	/*
	 * The TEST7_BRANCH_ID test successfull non-INVITE transaction
	 * with provisional response.
	 */
	pj_status_t status;
	pjsip_response_addr res_addr;
	struct response *r;
	pjsip_tx_data *tdata;
	pj_time_val delay = { 2, 0 };

	recv_count++;

	if (recv_count > 1) {
	    PJ_LOG(3,(THIS_FILE,"   error: not expecting %d-th packet!",
		      recv_count));
	    test_complete = -640;
	    return PJ_TRUE;
	}

	/* Respond with provisional response */
	status = pjsip_endpt_create_response(endpt, rdata, 100, NULL, &tdata);
	pj_assert(status == PJ_SUCCESS);

	status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
	pj_assert(status == PJ_SUCCESS);

	status = pjsip_endpt_send_response(endpt, &res_addr, tdata, 
					   NULL, NULL);
	pj_assert(status == PJ_SUCCESS);

	/* Create the final response. */
	status = pjsip_endpt_create_response(endpt, rdata, 202, NULL, &tdata);
	pj_assert(status == PJ_SUCCESS);

	/* Schedule sending final response in couple of of secs. */
	r = pj_pool_alloc(tdata->pool, sizeof(*r));
	r->res_addr = res_addr;
	r->tdata = tdata;
	if (r->res_addr.transport)
	    pjsip_transport_add_ref(r->res_addr.transport);

	timer.entry.cb = &send_response_callback;
	timer.entry.user_data = r;
	pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);

	return PJ_TRUE;


    } else
    if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST8_BRANCH_ID) == 0) {
	/*
	 * The TEST8_BRANCH_ID test failed INVITE transaction.
	 */
	pjsip_method *method;
	pj_status_t status;

	method = &rdata->msg_info.msg->line.req.method;

	recv_count++;

	if (method->id == PJSIP_INVITE_METHOD) {

	    if (recv_count > 1) {
		PJ_LOG(3,(THIS_FILE,"   error: not expecting %d-th packet!",
			  recv_count));
		test_complete = -635;
	    }

	    status = pjsip_endpt_respond_stateless(endpt, rdata, 301, NULL,
						   NULL, NULL);
	    if (status != PJ_SUCCESS) {
		app_perror("    error: unable to send response", status);
		test_complete = -636;
	    }

	} else if (method->id == PJSIP_ACK_METHOD) {

	    if (recv_count == 2) {
		pj_str_t key;
		pj_time_val delay = { 5, 0 };
		
		/* Schedule timer to destroy transaction after 5 seconds.
		 * This is to make sure that transaction does not 
		 * retransmit ACK.
		 */
		pjsip_tsx_create_key(rdata->tp_info.pool, &key,
				     PJSIP_ROLE_UAC, &pjsip_invite_method,
				     rdata);

		pj_strcpy(&timer.tsx_key, &key);
		timer.entry.id = 301;
		timer.entry.cb = &terminate_tsx_callback;

		pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);
	    }

	    if (recv_count > 2) {
		PJ_LOG(3,(THIS_FILE,"   error: not expecting %d-th packet!",
			  recv_count));
		test_complete = -638;
	    }


	} else {
	    PJ_LOG(3,(THIS_FILE,"   error: not expecting %s",
		      pjsip_rx_data_get_info(rdata)));
	    test_complete = -639;

	}


    } else
    if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST9_BRANCH_ID) == 0) {
	/*
	 * The TEST9_BRANCH_ID test failed INVITE transaction with
	 * provisional response.
	 */
	pjsip_method *method;
	pj_status_t status;

	method = &rdata->msg_info.msg->line.req.method;

	recv_count++;

	if (method->id == PJSIP_INVITE_METHOD) {

	    pjsip_response_addr res_addr;
	    struct response *r;
	    pjsip_tx_data *tdata;
	    pj_time_val delay = { 2, 0 };

	    if (recv_count > 1) {
		PJ_LOG(3,(THIS_FILE,"   error: not expecting %d-th packet!",
			  recv_count));
		test_complete = -650;
		return PJ_TRUE;
	    }

	    /* Respond with provisional response */
	    status = pjsip_endpt_create_response(endpt, rdata, 100, NULL, 
						 &tdata);
	    pj_assert(status == PJ_SUCCESS);

	    status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
	    pj_assert(status == PJ_SUCCESS);

	    status = pjsip_endpt_send_response(endpt, &res_addr, tdata, 
					       NULL, NULL);
	    pj_assert(status == PJ_SUCCESS);

	    /* Create the final response. */
	    status = pjsip_endpt_create_response(endpt, rdata, 302, NULL, 
						 &tdata);
	    pj_assert(status == PJ_SUCCESS);

	    /* Schedule sending final response in couple of of secs. */
	    r = pj_pool_alloc(tdata->pool, sizeof(*r));
	    r->res_addr = res_addr;
	    r->tdata = tdata;
	    if (r->res_addr.transport)
		pjsip_transport_add_ref(r->res_addr.transport);

	    timer.entry.cb = &send_response_callback;
	    timer.entry.user_data = r;
	    pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);

	} else if (method->id == PJSIP_ACK_METHOD) {

	    if (recv_count == 2) {
		pj_str_t key;
		pj_time_val delay = { 5, 0 };
		
		/* Schedule timer to destroy transaction after 5 seconds.
		 * This is to make sure that transaction does not 
		 * retransmit ACK.
		 */
		pjsip_tsx_create_key(rdata->tp_info.pool, &key,
				     PJSIP_ROLE_UAC, &pjsip_invite_method,
				     rdata);

		pj_strcpy(&timer.tsx_key, &key);
		timer.entry.id = 302;
		timer.entry.cb = &terminate_tsx_callback;

		pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);
	    }

	    if (recv_count > 2) {
		PJ_LOG(3,(THIS_FILE,"   error: not expecting %d-th packet!",
			  recv_count));
		test_complete = -638;
	    }


	} else {
	    PJ_LOG(3,(THIS_FILE,"   error: not expecting %s",
		      pjsip_rx_data_get_info(rdata)));
	    test_complete = -639;

	}

	return PJ_TRUE;

    }

    return PJ_FALSE;
}
Esempio n. 9
0
static pj_bool_t distributor(pjsip_rx_data *rdata)
{
	pjsip_dialog *dlg;
	struct distributor_dialog_data *dist = NULL;
	struct ast_taskprocessor *serializer = NULL;
	pjsip_rx_data *clone;

	if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
		/*
		 * Ignore everything until we are fully booted.  Let the
		 * peer retransmit messages until we are ready.
		 */
		return PJ_TRUE;
	}

	dlg = find_dialog(rdata);
	if (dlg) {
		ast_debug(3, "Searching for serializer associated with dialog %s for %s\n",
			dlg->obj_name, pjsip_rx_data_get_info(rdata));
		dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY);
		if (dist) {
			ao2_lock(dist);
			serializer = ao2_bump(dist->serializer);
			ao2_unlock(dist);
			if (serializer) {
				ast_debug(3, "Found serializer %s associated with dialog %s\n",
					ast_taskprocessor_name(serializer), dlg->obj_name);
			}
		}
	}

	if (serializer) {
		/* We have a serializer so we know where to send the message. */
	} else if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) {
		ast_debug(3, "No dialog serializer for %s.  Using request transaction as basis.\n",
			pjsip_rx_data_get_info(rdata));
		serializer = find_request_serializer(rdata);
		if (!serializer) {
			/*
			 * Pick a serializer for the unmatched response.
			 * We couldn't determine what serializer originally
			 * sent the request or the serializer is gone.
			 */
			serializer = ast_sip_get_distributor_serializer(rdata);
		}
	} else if (!pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method)
		|| !pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_bye_method)) {
		/* We have a BYE or CANCEL request without a serializer. */
		pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata,
			PJSIP_SC_CALL_TSX_DOES_NOT_EXIST, NULL, NULL, NULL);
		ao2_cleanup(dist);
		return PJ_TRUE;
	} else {
		if (ast_taskprocessor_alert_get()) {
			/*
			 * When taskprocessors get backed up, there is a good chance that
			 * we are being overloaded and need to defer adding new work to
			 * the system.  To defer the work we will ignore the request and
			 * rely on the peer's transport layer to retransmit the message.
			 * We usually work off the overload within a few seconds.  The
			 * alternative is to send back a 503 response to these requests
			 * and be done with it.
			 */
			ast_debug(3, "Taskprocessor overload alert: Ignoring '%s'.\n",
				pjsip_rx_data_get_info(rdata));
			ao2_cleanup(dist);
			return PJ_TRUE;
		}

		/* Pick a serializer for the out-of-dialog request. */
		serializer = ast_sip_get_distributor_serializer(rdata);
	}

	if (pjsip_rx_data_clone(rdata, 0, &clone) != PJ_SUCCESS) {
		ast_taskprocessor_unreference(serializer);
		ao2_cleanup(dist);
		return PJ_TRUE;
	}

	if (dist) {
		ao2_lock(dist);
		clone->endpt_info.mod_data[endpoint_mod.id] = ao2_bump(dist->endpoint);
		ao2_unlock(dist);
		ao2_cleanup(dist);
	}

	if (ast_sip_push_task(serializer, distribute, clone)) {
		ao2_cleanup(clone->endpt_info.mod_data[endpoint_mod.id]);
		pjsip_rx_data_free_cloned(clone);
	}

	ast_taskprocessor_unreference(serializer);

	return PJ_TRUE;
}
Esempio n. 10
0
static pjsip_dialog *find_dialog(pjsip_rx_data *rdata)
{
	pj_str_t tsx_key;
	pjsip_transaction *tsx;
	pjsip_dialog *dlg;
	pj_str_t *local_tag;
	pj_str_t *remote_tag;

	if (!rdata->msg_info.msg) {
		return NULL;
	}

	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
		local_tag = &rdata->msg_info.to->tag;
		remote_tag = &rdata->msg_info.from->tag;
	} else {
		local_tag = &rdata->msg_info.from->tag;
		remote_tag = &rdata->msg_info.to->tag;
	}

	/* We can only call the convenient method for
	 *  1) responses
	 *  2) non-CANCEL requests
	 *  3) CANCEL requests with a to-tag
	 */
	if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG ||
			pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_cancel_method) ||
			rdata->msg_info.to->tag.slen != 0) {
		dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, local_tag,
				remote_tag, PJ_FALSE);
		if (dlg) {
			return dlg;
		}
	}

	/*
	 * There may still be a matching dialog if this is
	 * 1) an incoming CANCEL request without a to-tag
	 * 2) an incoming response to a dialog-creating request.
	 */
	if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
		/* CANCEL requests will need to match the INVITE we initially received. Any
		 * other request type will either have been matched already or is not in
		 * dialog
		 */
		pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAS,
				pjsip_get_invite_method(), rdata);
	} else {
		pjsip_tsx_create_key(rdata->tp_info.pool, &tsx_key, PJSIP_ROLE_UAC,
				&rdata->msg_info.cseq->method, rdata);
	}

	tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
	if (!tsx) {
		ast_debug(3, "Could not find matching transaction for %s\n",
			pjsip_rx_data_get_info(rdata));
		return NULL;
	}

	dlg = pjsip_tsx_get_dlg(tsx);

#ifdef HAVE_PJ_TRANSACTION_GRP_LOCK
	pj_grp_lock_release(tsx->grp_lock);
#else
	pj_mutex_unlock(tsx->mutex);
#endif

	return dlg;
}