Exemple #1
0
/* Calculate new target for the request */
static pj_status_t proxy_calculate_target(pjsip_rx_data *rdata,
        pjsip_tx_data *tdata)
{
    pjsip_sip_uri *target;

    /* RFC 3261 Section 16.5 Determining Request Targets */

    target = (pjsip_sip_uri*) tdata->msg->line.req.uri;

    /* If the Request-URI of the request contains an maddr parameter, the
     * Request-URI MUST be placed into the target set as the only target
     * URI, and the proxy MUST proceed to Section 16.6.
     */
    if (target->maddr_param.slen) {
        proxy_postprocess(tdata);
        return PJ_SUCCESS;
    }


    /* If the domain of the Request-URI indicates a domain this element is
     * not responsible for, the Request-URI MUST be placed into the target
     * set as the only target, and the element MUST proceed to the task of
     * Request Forwarding (Section 16.6).
     */
    if (!is_uri_local(target)) {
        proxy_postprocess(tdata);
        return PJ_SUCCESS;
    }

    /* If the target set for the request has not been predetermined as
     * described above, this implies that the element is responsible for the
     * domain in the Request-URI, and the element MAY use whatever mechanism
     * it desires to determine where to send the request.
     */

    /* We're not interested to receive request destined to us, so
     * respond with 404/Not Found (only if request is not ACK!).
     */
    if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
        pjsip_endpt_respond_stateless(global.endpt, rdata,
                                      PJSIP_SC_NOT_FOUND, NULL,
                                      NULL, NULL);
    }

    /* Delete the request since we're not forwarding it */
    pjsip_tx_data_dec_ref(tdata);

    return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_FOUND);
}
Exemple #2
0
/*
 * Create server subscription.
 */
PJ_DEF(pj_status_t) pjsip_pres_create_uas( pjsip_dialog *dlg,
					   const pjsip_evsub_user *user_cb,
					   pjsip_rx_data *rdata,
					   pjsip_evsub **p_evsub )
{
    pjsip_accept_hdr *accept;
    pjsip_event_hdr *event;
    content_type_e content_type = CONTENT_TYPE_NONE;
    pjsip_evsub *sub;
    pjsip_pres *pres;
    char obj_name[PJ_MAX_OBJ_NAME];
    pj_status_t status;

    /* Check arguments */
    PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);

    /* Must be request message */
    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
		     PJSIP_ENOTREQUESTMSG);

    /* Check that request is SUBSCRIBE */
    PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
				      &pjsip_subscribe_method)==0,
		     PJSIP_SIMPLE_ENOTSUBSCRIBE);

    /* Check that Event header contains "presence" */
    event = (pjsip_event_hdr*)
    	    pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_EVENT, NULL);
    if (!event) {
	return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);
    }
    if (pj_stricmp(&event->event_type, &STR_PRESENCE) != 0) {
	return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_EVENT);
    }

    /* Check that request contains compatible Accept header. */
    accept = (pjsip_accept_hdr*)
    	     pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);
    if (accept) {
	unsigned i;
	for (i=0; i<accept->count; ++i) {
	    if (pj_stricmp(&accept->values[i], &STR_APP_PIDF_XML)==0) {
		content_type = CONTENT_TYPE_PIDF;
		break;
	    } else
	    if (pj_stricmp(&accept->values[i], &STR_APP_XPIDF_XML)==0) {
		content_type = CONTENT_TYPE_XPIDF;
		break;
	    }
	}

	if (i==accept->count) {
	    /* Nothing is acceptable */
	    return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE);
	}

    } else {
	/* No Accept header.
	 * Treat as "application/pidf+xml"
	 */
	content_type = CONTENT_TYPE_PIDF;
    }

    /* Lock dialog */
    pjsip_dlg_inc_lock(dlg);


    /* Create server subscription */
    status = pjsip_evsub_create_uas( dlg, &pres_user, rdata, 0, &sub);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Create server presence subscription */
    pres = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_pres);
    pres->dlg = dlg;
    pres->sub = sub;
    pres->content_type = content_type;
    if (user_cb)
	pj_memcpy(&pres->user_cb, user_cb, sizeof(pjsip_evsub_user));

    pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "pres%p", dlg->pool);
    pres->status_pool = pj_pool_create(dlg->pool->factory, obj_name, 
				       512, 512, NULL);
    pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "tmpres%p", dlg->pool);
    pres->tmp_pool = pj_pool_create(dlg->pool->factory, obj_name, 
				    512, 512, NULL);

    /* Attach to evsub */
    pjsip_evsub_set_mod_data(sub, mod_presence.id, pres);

    /* Done: */
    *p_evsub = sub;

on_return:
    pjsip_dlg_dec_lock(dlg);
    return status;
}
/*
 * Create server subscription.
 */
PJ_DEF(pj_status_t) pjsip_mwi_create_uas( pjsip_dialog *dlg,
					  const pjsip_evsub_user *user_cb,
					  pjsip_rx_data *rdata,
					  pjsip_evsub **p_evsub )
{
    pjsip_accept_hdr *accept;
    pjsip_event_hdr *event;
    pjsip_evsub *sub;
    pjsip_mwi *mwi;
    char obj_name[PJ_MAX_OBJ_NAME];
    pj_status_t status;

    /* Check arguments */
    PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);

    /* Must be request message */
    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
		     PJSIP_ENOTREQUESTMSG);

    /* Check that request is SUBSCRIBE */
    PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
				      &pjsip_subscribe_method)==0,
		     PJSIP_SIMPLE_ENOTSUBSCRIBE);

    /* Check that Event header contains "mwi" */
    event = (pjsip_event_hdr*)
    	    pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_EVENT, NULL);
    if (!event) {
	return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_REQUEST);
    }
    if (pj_stricmp(&event->event_type, &STR_MWI) != 0) {
	return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_EVENT);
    }

    /* Check that request contains compatible Accept header. */
    accept = (pjsip_accept_hdr*)
    	     pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);
    if (accept) {
	unsigned i;
	for (i=0; i<accept->count; ++i) {
	    if (pj_stricmp(&accept->values[i], &STR_APP_SIMPLE_SMS)==0) {
		break;
	    }
	}

	if (i==accept->count) {
	    /* Nothing is acceptable */
	    return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE);
	}

    } else {
	/* No Accept header. 
	 * Assume client supports "application/simple-message-summary" 
	*/
    }

    /* Lock dialog */
    pjsip_dlg_inc_lock(dlg);


    /* Create server subscription */
    status = pjsip_evsub_create_uas( dlg, &mwi_user, rdata, 0, &sub);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Create server mwi subscription */
    mwi = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_mwi);
    mwi->dlg = dlg;
    mwi->sub = sub;
    if (user_cb)
	pj_memcpy(&mwi->user_cb, user_cb, sizeof(pjsip_evsub_user));

    pj_ansi_snprintf(obj_name, PJ_MAX_OBJ_NAME, "mwibd%p", dlg->pool);
    mwi->body_pool = pj_pool_create(dlg->pool->factory, obj_name, 
				    512, 512, NULL);

    /* Attach to evsub */
    pjsip_evsub_set_mod_data(sub, mod_mwi.id, mwi);

    /* Done: */
    *p_evsub = sub;

on_return:
    pjsip_dlg_dec_lock(dlg);
    return status;
}
Exemple #4
0
/* Proxy utility to verify incoming requests.
 * Return non-zero if verification failed.
 */
static pj_status_t proxy_verify_request(pjsip_rx_data *rdata)
{
    const pj_str_t STR_PROXY_REQUIRE = {"Proxy-Require", 13};

    /* RFC 3261 Section 16.3 Request Validation */

    /* Before an element can proxy a request, it MUST verify the message's
     * validity.  A valid message must pass the following checks:
     *
     * 1. Reasonable Syntax
     * 2. URI scheme
     * 3. Max-Forwards
     * 4. (Optional) Loop Detection
     * 5. Proxy-Require
     * 6. Proxy-Authorization
     */

    /* 1. Reasonable Syntax.
     * This would have been checked by transport layer.
     */

    /* 2. URI scheme.
     * We only want to support "sip:" URI scheme for this simple proxy.
     */
    if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.msg->line.req.uri)) {
        pjsip_endpt_respond_stateless(global.endpt, rdata,
                                      PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL,
                                      NULL, NULL);
        return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_UNSUPPORTED_URI_SCHEME);
    }

    /* 3. Max-Forwards.
     * Send error if Max-Forwards is 1 or lower.
     */
    if (rdata->msg_info.max_fwd && rdata->msg_info.max_fwd->ivalue <= 1) {
        pjsip_endpt_respond_stateless(global.endpt, rdata,
                                      PJSIP_SC_TOO_MANY_HOPS, NULL,
                                      NULL, NULL);
        return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_TOO_MANY_HOPS);
    }

    /* 4. (Optional) Loop Detection.
     * Nah, we don't do that with this simple proxy.
     */

    /* 5. Proxy-Require */
    if (pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_PROXY_REQUIRE,
                                   NULL) != NULL)
    {
        pjsip_endpt_respond_stateless(global.endpt, rdata,
                                      PJSIP_SC_BAD_EXTENSION, NULL,
                                      NULL, NULL);
        return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_BAD_EXTENSION);
    }

    /* 6. Proxy-Authorization.
     * Nah, we don't require any authorization with this sample.
     */

    return PJ_SUCCESS;
}
Exemple #5
0
/*
 * Verify that incoming request with Replaces header can be processed.
 */
PJ_DEF(pj_status_t) pjsip_replaces_verify_request( pjsip_rx_data *rdata,
						   pjsip_dialog **p_dlg,
						   pj_bool_t lock_dlg,
						   pjsip_tx_data **p_tdata)
{
    const pj_str_t STR_REPLACES = { "Replaces", 8 };
    pjsip_replaces_hdr *rep_hdr;
    int code = 200;
    const char *warn_text = NULL;
    pjsip_hdr res_hdr_list;
    pjsip_dialog *dlg = NULL;
    pjsip_inv_session *inv;
    pj_status_t status = PJ_SUCCESS;

    PJ_ASSERT_RETURN(rdata && p_dlg, PJ_EINVAL);

    /* Check that pjsip_replaces_init_module() has been called. */
    PJ_ASSERT_RETURN(the_endpt != NULL, PJ_EINVALIDOP);


    /* Init output arguments */
    *p_dlg = NULL;
    if (p_tdata) *p_tdata = NULL;

    pj_list_init(&res_hdr_list);

    /* Find Replaces header */
    rep_hdr = (pjsip_replaces_hdr*) 
	      pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_REPLACES, 
					 NULL);
    if (!rep_hdr) {
	/* No Replaces header. No further processing is necessary. */
	return PJ_SUCCESS;
    }


    /* Check that there's no other Replaces header and return 400 Bad Request
     * if not. 
     */
    if (pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_REPLACES, 
				   rep_hdr->next)) {
	code = PJSIP_SC_BAD_REQUEST;
	warn_text = "Found multiple Replaces headers";
	goto on_return;
    }

    /* Find the dialog identified by Replaces header (and always lock the
     * dialog no matter what application wants).
     */
    dlg = pjsip_ua_find_dialog(&rep_hdr->call_id, &rep_hdr->to_tag,
			       &rep_hdr->from_tag, PJ_TRUE);

    /* Respond with 481 "Call/Transaction Does Not Exist" response if
     * no dialog is found.
     */
    if (dlg == NULL) {
	code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST;
	warn_text = "No dialog found for Replaces request";
	goto on_return;
    }

    /* Get the invite session within the dialog */
    inv = pjsip_dlg_get_inv_session(dlg);

    /* Return 481 if no invite session is present. */
    if (inv == NULL) {
	code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST;
	warn_text = "No INVITE session found for Replaces request";
	goto on_return;
    }

    /* Return 603 Declined response if invite session has already 
     * terminated 
     */
    if (inv->state >= PJSIP_INV_STATE_DISCONNECTED) {
	code = PJSIP_SC_DECLINE;
	warn_text = "INVITE session already terminated";
	goto on_return;
    }

    /* If "early-only" flag is present, check that the invite session
     * has not been confirmed yet. If the session has been confirmed, 
     * return 486 "Busy Here" response.
     */
    if (rep_hdr->early_only && inv->state >= PJSIP_INV_STATE_CONNECTING) {
	code = PJSIP_SC_BUSY_HERE;
	warn_text = "INVITE session already established";
	goto on_return;
    }

    /* If the Replaces header field matches an early dialog that was not
     * initiated by this UA, it returns a 481 (Call/Transaction Does Not
     * Exist) response to the new INVITE.
     */
    if (inv->state <= PJSIP_INV_STATE_EARLY && inv->role != PJSIP_ROLE_UAC) {
	code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST;
	warn_text = "Found early INVITE session but not initiated by this UA";
	goto on_return;
    }


    /*
     * Looks like everything is okay!!
     */
    *p_dlg = dlg;
    status = PJ_SUCCESS;
    code = 200;

on_return:

    /* Create response if necessary */
    if (code != 200) {
	/* If we have dialog we must unlock it */
	if (dlg)
	    pjsip_dlg_dec_lock(dlg);

	/* Create response */
	if (p_tdata) {
	    pjsip_tx_data *tdata;
	    const pjsip_hdr *h;

	    status = pjsip_endpt_create_response(the_endpt, rdata, code, 
						 NULL, &tdata);

	    if (status != PJ_SUCCESS)
		return status;

	    /* Add response headers. */
	    h = res_hdr_list.next;
	    while (h != &res_hdr_list) {
		pjsip_hdr *cloned;

		cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
		PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);

		pjsip_msg_add_hdr(tdata->msg, cloned);

		h = h->next;
	    }

	    /* Add warn text, if any */
	    if (warn_text) {
		pjsip_warning_hdr *warn_hdr;
		pj_str_t warn_value = pj_str((char*)warn_text);

		warn_hdr=pjsip_warning_hdr_create(tdata->pool, 399, 
						  pjsip_endpt_name(the_endpt),
						  &warn_value);
		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)warn_hdr);
	    }

	    *p_tdata = tdata;
	}

	/* Can not return PJ_SUCCESS when response message is produced.
	 * Ref: PROTOS test ~#2490
	 */
	if (status == PJ_SUCCESS)
	    status = PJSIP_ERRNO_FROM_SIP_STATUS(code);

    } else {
	/* If application doesn't want to lock the dialog, unlock it */
	if (!lock_dlg)
	    pjsip_dlg_dec_lock(dlg);
    }

    return status;
}