/* Callback to be called to handle incoming response outside
 * any transactions. This happens for example when 2xx/OK
 * for INVITE is received and transaction will be destroyed
 * immediately, so we need to forward the subsequent 2xx/OK
 * retransmission statelessly.
 */
static pj_bool_t proxy_on_rx_response( pjsip_rx_data *rdata )
{
    pjsip_tx_data *tdata;
    pjsip_response_addr res_addr;
    pjsip_via_hdr *hvia;
    pj_status_t status;

    /* Create response to be forwarded upstream (Via will be stripped here) */
    status = pjsip_endpt_create_response_fwd(global.endpt, rdata, 0, &tdata);
    if (status != PJ_SUCCESS) {
	app_perror("Error creating response", status);
	return PJ_TRUE;
    }

    /* Get topmost Via header */
    hvia = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
    if (hvia == NULL) {
	/* Invalid response! Just drop it */
	pjsip_tx_data_dec_ref(tdata);
	return PJ_TRUE;
    }

    /* Calculate the address to forward the response */
    pj_bzero(&res_addr, sizeof(res_addr));
    res_addr.dst_host.type = PJSIP_TRANSPORT_UDP;
    res_addr.dst_host.flag = 
	pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP);

    /* Destination address is Via's received param */
    res_addr.dst_host.addr.host = hvia->recvd_param;
    if (res_addr.dst_host.addr.host.slen == 0) {
	/* Someone has messed up our Via header! */
	res_addr.dst_host.addr.host = hvia->sent_by.host;
    }

    /* Destination port is the rport */
    if (hvia->rport_param != 0 && hvia->rport_param != -1)
	res_addr.dst_host.addr.port = hvia->rport_param;

    if (res_addr.dst_host.addr.port == 0) {
	/* Ugh, original sender didn't put rport!
	 * At best, can only send the response to the port in Via.
	 */
	res_addr.dst_host.addr.port = hvia->sent_by.port;
    }

    /* Forward response */
    status = pjsip_endpt_send_response(global.endpt, &res_addr, tdata,
				       NULL, NULL);
    if (status != PJ_SUCCESS) {
	app_perror("Error forwarding response", status);
	return PJ_TRUE;
    }

    return PJ_TRUE;
}
Example #2
0
pj_status_t PJUtils::create_response_fwd(pjsip_endpoint* endpt,
                                         pjsip_rx_data* rdata,
                                         unsigned options,
                                         pjsip_tx_data** p_tdata)
{
  pj_status_t status = pjsip_endpt_create_response_fwd(endpt,
                       rdata,
                       options,
                       p_tdata);
  if (status == PJ_SUCCESS)
  {
    // Copy the SAS trail across from the request.
    set_trail(*p_tdata, get_trail(rdata));
  }
  return status;
}
/* Callback to be called to handle transaction state changed. */
static void tu_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event)
{
    struct uac_data *uac_data;
    pj_status_t status;

    if (tsx->role == PJSIP_ROLE_UAS) {
	if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
	    struct uas_data *uas_data;

	    uas_data = (struct uas_data*) tsx->mod_data[mod_tu.id];
	    if (uas_data->uac_tsx) {
		uac_data = (struct uac_data*)
			   uas_data->uac_tsx->mod_data[mod_tu.id];
		uac_data->uas_tsx = NULL;
	    }
		       
	}
	return;
    }

    /* Get the data that we attached to the UAC transaction previously */
    uac_data = (struct uac_data*) tsx->mod_data[mod_tu.id];


    /* Handle incoming response */
    if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {

	pjsip_rx_data *rdata;
	pjsip_response_addr res_addr;
        pjsip_via_hdr *hvia;
	pjsip_tx_data *tdata;

	rdata = event->body.tsx_state.src.rdata;

	/* Do not forward 100 response for INVITE (we already responded
	 * INVITE with 100)
	 */
	if (tsx->method.id == PJSIP_INVITE_METHOD && 
	    rdata->msg_info.msg->line.status.code == 100)
	{
	    return;
	}

	/* Create response to be forwarded upstream 
	 * (Via will be stripped here) 
	 */
	status = pjsip_endpt_create_response_fwd(global.endpt, rdata, 0, 
						 &tdata);
	if (status != PJ_SUCCESS) {
	    app_perror("Error creating response", status);
	    return;
	}

	/* Get topmost Via header of the new response */
	hvia = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, 
						   NULL);
	if (hvia == NULL) {
	    /* Invalid response! Just drop it */
	    pjsip_tx_data_dec_ref(tdata);
	    return;
	}

	/* Calculate the address to forward the response */
	pj_bzero(&res_addr, sizeof(res_addr));
	res_addr.dst_host.type = PJSIP_TRANSPORT_UDP;
	res_addr.dst_host.flag = 
	    pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP);

	/* Destination address is Via's received param */
	res_addr.dst_host.addr.host = hvia->recvd_param;
	if (res_addr.dst_host.addr.host.slen == 0) {
	    /* Someone has messed up our Via header! */
	    res_addr.dst_host.addr.host = hvia->sent_by.host;
	}

	/* Destination port is the rport */
	if (hvia->rport_param != 0 && hvia->rport_param != -1)
	    res_addr.dst_host.addr.port = hvia->rport_param;

	if (res_addr.dst_host.addr.port == 0) {
	    /* Ugh, original sender didn't put rport!
	     * At best, can only send the response to the port in Via.
	     */
	    res_addr.dst_host.addr.port = hvia->sent_by.port;
	}

	/* Forward response with the UAS transaction */
	pjsip_tsx_send_msg(uac_data->uas_tsx, tdata);

    }

    /* If UAC transaction is terminated, terminate the UAS as well.
     * This could happen because of:
     *	- timeout on the UAC side
     *  - receipt of 2xx response to INVITE
     */
    if (tsx->state == PJSIP_TSX_STATE_TERMINATED && uac_data &&
	uac_data->uas_tsx) 
    {

	pjsip_transaction *uas_tsx;
	struct uas_data *uas_data;

	uas_tsx = uac_data->uas_tsx;
	uas_data = (struct uas_data*) uas_tsx->mod_data[mod_tu.id];
	uas_data->uac_tsx = NULL;

	if (event->body.tsx_state.type == PJSIP_EVENT_TIMER) {

	    /* Send 408/Timeout if this is an INVITE transaction, since
	     * we must have sent provisional response before. For non
	     * INVITE transaction, just destroy it.
	     */
	    if (tsx->method.id == PJSIP_INVITE_METHOD) {

		pjsip_tx_data *tdata = uas_tsx->last_tx;

		tdata->msg->line.status.code = PJSIP_SC_REQUEST_TIMEOUT;
		tdata->msg->line.status.reason = pj_str("Request timed out");
		tdata->msg->body = NULL;

		pjsip_tx_data_add_ref(tdata);
		pjsip_tx_data_invalidate_msg(tdata);

		pjsip_tsx_send_msg(uas_tsx, tdata);

	    } else {
		/* For non-INVITE, just destroy the UAS transaction */
		pjsip_tsx_terminate(uas_tsx, PJSIP_SC_REQUEST_TIMEOUT);
	    }

	} else if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {

	    if (uas_tsx->state < PJSIP_TSX_STATE_TERMINATED) {
		pjsip_msg *msg;
		int code;

		msg = event->body.tsx_state.src.rdata->msg_info.msg;
		code = msg->line.status.code;

		uac_data->uas_tsx = NULL;
		pjsip_tsx_terminate(uas_tsx, code);
	    }
	}
    }
}