Esempio n. 1
0
PJ_DEF(pj_status_t) pjsip_regc_unregister(pjsip_regc *regc,
					  pjsip_tx_data **p_tdata)
{
    pjsip_tx_data *tdata;
    pjsip_msg *msg;
    pjsip_hdr *hdr;
    pj_status_t status;

    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);

    pj_lock_acquire(regc->lock);

    if (regc->timer.id != 0) {
	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
	regc->timer.id = 0;
    }

    regc->expires_requested = 0;

    status = create_request(regc, &tdata);
    if (status != PJ_SUCCESS) {
	pj_lock_release(regc->lock);
	return status;
    }

    msg = tdata->msg;

    /* Add Contact headers. */
    hdr = (pjsip_hdr*)regc->contact_hdr_list.next;
    while ((void*)hdr != (void*)&regc->contact_hdr_list) {
	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
			       pjsip_hdr_clone(tdata->pool, hdr));
	hdr = hdr->next;
    }

    /* Also add bindings which are to be removed */
    while (!pj_list_empty(&regc->removed_contact_hdr_list)) {
	hdr = (pjsip_hdr*)regc->removed_contact_hdr_list.next;
	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
			       pjsip_hdr_clone(tdata->pool, hdr));
	pj_list_erase(hdr);
    }

    /* Add Expires:0 header */
    hdr = (pjsip_hdr*) pjsip_expires_hdr_create(tdata->pool, 0);
    pjsip_msg_add_hdr(msg, hdr);

    pj_lock_release(regc->lock);

    *p_tdata = tdata;
    return PJ_SUCCESS;
}
Esempio n. 2
0
static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
{
	pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
	pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
	pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata);
	pjsip_tx_data *tdata;
	const pjsip_hdr *hdr;
	pj_status_t status;

	/* Make the response object */
	status = ast_sip_create_response(rdata, code, NULL, &tdata);
	if (status != PJ_SUCCESS) {
		ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
		return status;
	}

	/* Add appropriate headers */
	if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) {
		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
	}
	if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) {
		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
	}
	if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) {
		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
	}

	/*
	 * XXX TODO: pjsip doesn't care a lot about either of these headers -
	 * while it provides specific methods to create them, they are defined
	 * to be the standard string header creation. We never did add them
	 * in chan_sip, although RFC 3261 says they SHOULD. Hard coded here.
	 */
	ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
	ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);

	if (dlg && trans) {
		status = pjsip_dlg_send_response(dlg, trans, tdata);
	} else {
		struct ast_sip_endpoint *endpoint;

		endpoint = ast_pjsip_rdata_get_endpoint(rdata);
		status = ast_sip_send_stateful_response(rdata, tdata, endpoint);
		ao2_cleanup(endpoint);
	}

	if (status != PJ_SUCCESS) {
		ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
	}

	return status;
}
Esempio n. 3
0
pjsip_route_hdr *
createRouteSet(const std::string &route, pj_pool_t *hdr_pool)
{
    pjsip_route_hdr *route_set = pjsip_route_hdr_create(hdr_pool);

    std::string host;
    int port = 0;
    size_t found = route.find(":");
    if (found != std::string::npos) {
        host = route.substr(0, found);
        port = atoi(route.substr(found + 1, route.length() - found).c_str());
    } else
        host = route;

    pjsip_route_hdr *routing = pjsip_route_hdr_create(hdr_pool);
    pjsip_sip_uri *url = pjsip_sip_uri_create(hdr_pool, 0);
    url->lr_param = 1;
    routing->name_addr.uri = (pjsip_uri*) url;
    pj_strdup2(hdr_pool, &url->host, host.c_str());
    url->port = port;

    RING_DBG("Adding route %s", host.c_str());
    pj_list_push_back(route_set, pjsip_hdr_clone(hdr_pool, routing));

    return route_set;
}
Esempio n. 4
0
void SIPPresence::fillDoc(pjsip_tx_data *tdata, const pres_msg_data *msg_data)
{

    if (tdata->msg->type == PJSIP_REQUEST_MSG) {
        const pj_str_t STR_USER_AGENT = CONST_PJ_STR("User-Agent");
        std::string useragent(acc_->getUserAgentName());
        pj_str_t pJuseragent = pj_str((char*) useragent.c_str());
        pjsip_hdr *h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool, &STR_USER_AGENT, &pJuseragent);
        pjsip_msg_add_hdr(tdata->msg, h);
    }

    if (msg_data == NULL)
        return;

    const pjsip_hdr *hdr;
    hdr = msg_data->hdr_list.next;

    while (hdr && hdr != &msg_data->hdr_list) {
        pjsip_hdr *new_hdr;
        new_hdr = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hdr);
        DEBUG("adding header", new_hdr->name.ptr);
        pjsip_msg_add_hdr(tdata->msg, new_hdr);
        hdr = hdr->next;
    }

    if (msg_data->content_type.slen && msg_data->msg_body.slen) {
        pjsip_msg_body *body;
        const pj_str_t type = CONST_PJ_STR("application");
        const pj_str_t subtype = CONST_PJ_STR("pidf+xml");
        body = pjsip_msg_body_create(tdata->pool, &type, &subtype, &msg_data->msg_body);
        tdata->msg->body = body;
    }
}
Esempio n. 5
0
/// This is a clone of the PJSIP pjsip_endpt_respond_stateless function,
/// with the addition of code to reflect the trail on the request on to the
/// response.  All sprout application code should use this method instead.
pj_status_t PJUtils::respond_stateless(pjsip_endpoint* endpt,
                                       pjsip_rx_data* rdata,
                                       int st_code,
                                       const pj_str_t* st_text,
                                       const pjsip_hdr* hdr_list,
                                       const pjsip_msg_body* body)
{
  pj_status_t status;
  pjsip_response_addr res_addr;
  pjsip_tx_data* tdata;

  // Create response message
  status = create_response(endpt, rdata, st_code, st_text, &tdata);
  if (status != PJ_SUCCESS)
  {
    return status;
  }

  // Add the message headers, if any
  if (hdr_list)
  {
    const pjsip_hdr* hdr = hdr_list->next;
    while (hdr != hdr_list)
    {
      pjsip_msg_add_hdr(tdata->msg,
                        (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hdr) );
      hdr = hdr->next;
    }
  }

  // Add the message body, if any.
  if (body)
  {
    tdata->msg->body = pjsip_msg_body_clone(tdata->pool, body);
    if (tdata->msg->body == NULL)
    {
      pjsip_tx_data_dec_ref(tdata);
      return status;
    }
  }

  // Get where to send request.
  status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
  if (status != PJ_SUCCESS)
  {
    pjsip_tx_data_dec_ref(tdata);
    return status;
  }

  // Send!
  status = pjsip_endpt_send_response(endpt, &res_addr, tdata, NULL, NULL);
  if (status != PJ_SUCCESS)
  {
    pjsip_tx_data_dec_ref(tdata);
    return status;
  }

  return PJ_SUCCESS;
}
Esempio n. 6
0
void PJUtils::clone_header(const pj_str_t* hdr_name, pjsip_msg* old_msg, pjsip_msg* new_msg, pj_pool_t* pool)
{
  pjsip_hdr* original_hdr = NULL;
  pjsip_hdr* last_hdr = NULL;
  while ((original_hdr = (pjsip_hdr*)pjsip_msg_find_hdr_by_name(old_msg, hdr_name, original_hdr)) && (last_hdr != original_hdr))
  {
    LOG_INFO("Cloning header! %ld", (long int)original_hdr);
    pjsip_hdr* new_hdr = (pjsip_hdr*)pjsip_hdr_clone(pool, original_hdr);
    pjsip_msg_add_hdr(new_msg, new_hdr);
    last_hdr = original_hdr;
  }
}
Esempio n. 7
0
static int options_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
{
    pjsip_tx_data *tdata;
    pj_status_t status;
    const pjsip_hdr *hdr;
    pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();

    status = pjsip_dlg_create_response(session->inv_session->dlg, rdata, 200, NULL,&tdata);
    if (status != PJ_SUCCESS) {
        ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
        return status;
    }

    /* Add appropriate headers */
    if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) {
        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
    }
    if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) {
        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
    }
    if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) {
        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr));
    }

    /*
     * XXX TODO: pjsip doesn't care a lot about either of these headers -
     * while it provides specific methods to create them, they are defined
     * to be the standard string header creation. We never did add them
     * in chan_sip, although RFC 3261 says they SHOULD. Hard coded here.
    */
    ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING);
    ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE);

    status = pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata);
    if (status != PJ_SUCCESS) {
        ast_log(LOG_ERROR, "Unable to send response (%d)\n", status);
    }

    return status;
}
Esempio n. 8
0
/*!
 * \internal
 * \brief Insert the header pointers into the linked list.
 *
 * For each header in the message, allocate a list entry,
 * clone the header, then insert the entry.
 */
static int insert_headers(pj_pool_t * pool, struct hdr_list *list, pjsip_msg * msg)
{
	pjsip_hdr *hdr = msg->hdr.next;
	struct hdr_list_entry *le;

	while (hdr && hdr != &msg->hdr) {
		le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
		le->hdr = pjsip_hdr_clone(pool, hdr);
		AST_LIST_INSERT_TAIL(list, le, nextptr);
		hdr = hdr->next;
	}

	return 0;
}
Esempio n. 9
0
/*
 * Update authentication session with a challenge.
 */
static void update_digest_session( pj_pool_t *ses_pool, 
				   pjsip_cached_auth *cached_auth,
				   const pjsip_www_authenticate_hdr *hdr )
{
    if (hdr->challenge.digest.qop.slen == 0)
	return;

    /* Initialize cnonce and qop if not present. */
    if (cached_auth->cnonce.slen == 0) {
	/* Save the whole challenge */
	cached_auth->last_chal = (pjsip_www_authenticate_hdr*)
				 pjsip_hdr_clone(ses_pool, hdr);

	/* Create cnonce */
	pj_create_unique_string( ses_pool, &cached_auth->cnonce );

	/* Initialize nonce-count */
	cached_auth->nc = 1;

	/* Save realm. */
	pj_assert(cached_auth->realm.slen != 0);
	if (cached_auth->realm.slen == 0) {
	    pj_strdup(ses_pool, &cached_auth->realm, 
		      &hdr->challenge.digest.realm);
	}

    } else {
	/* Update last_nonce and nonce-count */
	if (!pj_strcmp(&hdr->challenge.digest.nonce, 
		       &cached_auth->last_chal->challenge.digest.nonce)) 
	{
	    /* Same nonce, increment nonce-count */
	    ++cached_auth->nc;
	} else {
	    /* Server gives new nonce. */
	    pj_strdup(ses_pool, &cached_auth->last_chal->challenge.digest.nonce,
		      &hdr->challenge.digest.nonce);
	    /* Has the opaque changed? */
	    if (pj_strcmp(&cached_auth->last_chal->challenge.digest.opaque,
			  &hdr->challenge.digest.opaque)) 
	    {
		pj_strdup(ses_pool, 
			  &cached_auth->last_chal->challenge.digest.opaque,
			  &hdr->challenge.digest.opaque);
	    }
	    cached_auth->nc = 1;
	}
    }
}
Esempio n. 10
0
/*
 * A simple registrar, invoked by default_mod_on_rx_request()
 */
static void simple_registrar(pjsip_rx_data *rdata)
{
    pjsip_tx_data *tdata;
    const pjsip_expires_hdr *exp;
    const pjsip_hdr *h;
    unsigned cnt = 0;
    pjsip_generic_string_hdr *srv;
    pj_status_t status;

    status = pjsip_endpt_create_response(pjsua_get_pjsip_endpt(),
				 rdata, 200, NULL, &tdata);
    if (status != PJ_SUCCESS)
	return;

    exp = (pjsip_expires_hdr*)
	  pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);

    h = rdata->msg_info.msg->hdr.next;
    while (h != &rdata->msg_info.msg->hdr) {
	if (h->type == PJSIP_H_CONTACT) {
	    const pjsip_contact_hdr *c = (const pjsip_contact_hdr*)h;
	    int e = c->expires;

	    if (e < 0) {
		if (exp)
		    e = exp->ivalue;
		else
		    e = 3600;
	    }

	    if (e > 0) {
		pjsip_contact_hdr *nc = (pjsip_contact_hdr*)
					pjsip_hdr_clone(tdata->pool, h);
		nc->expires = e;
		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)nc);
		++cnt;
	    }
	}
	h = h->next;
    }

    srv = pjsip_generic_string_hdr_create(tdata->pool, NULL, NULL);
    srv->name = pj_str((char*)"Server");
    srv->hvalue = pj_str((char*)"pjsua simple registrar");
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)srv);

    pjsip_endpt_send_response2(pjsua_get_pjsip_endpt(),
                               rdata, tdata, NULL, NULL);
}
Esempio n. 11
0
PJ_DEF(pj_status_t) pjsip_publishc_set_headers( pjsip_publishc *pubc,
						const pjsip_hdr *hdr_list)
{
    const pjsip_hdr *h;

    PJ_ASSERT_RETURN(pubc && hdr_list, PJ_EINVAL);

    pj_list_init(&pubc->usr_hdr);
    h = hdr_list->next;
    while (h != hdr_list) {
	pj_list_push_back(&pubc->usr_hdr, pjsip_hdr_clone(pubc->pool, h));
	h = h->next;
    }

    return PJ_SUCCESS;
}
Esempio n. 12
0
PJ_DEF(pj_status_t) pjsip_regc_set_route_set( pjsip_regc *regc,
					      const pjsip_route_hdr *route_set)
{
    const pjsip_route_hdr *chdr;

    PJ_ASSERT_RETURN(regc && route_set, PJ_EINVAL);

    pj_list_init(&regc->route_set);

    chdr = route_set->next;
    while (chdr != route_set) {
	pj_list_push_back(&regc->route_set, pjsip_hdr_clone(regc->pool, chdr));
	chdr = chdr->next;
    }

    return PJ_SUCCESS;
}
Esempio n. 13
0
pjsip_multipart_clone_part(pj_pool_t *pool,
			   const pjsip_multipart_part *src)
{
    pjsip_multipart_part *dst;
    const pjsip_hdr *hdr;

    dst = pjsip_multipart_create_part(pool);

    hdr = src->hdr.next;
    while (hdr != &src->hdr) {
	pj_list_push_back(&dst->hdr, pjsip_hdr_clone(pool, hdr));
	hdr = hdr->next;
    }

    dst->body = pjsip_msg_body_clone(pool, src->body);

    return dst;
}
Esempio n. 14
0
PJ_DEF(pj_status_t) pjsip_regc_add_headers( pjsip_regc *regc,
					    const pjsip_hdr *hdr_list)
{
    const pjsip_hdr *hdr;

    PJ_ASSERT_RETURN(regc && hdr_list, PJ_EINVAL);

    //This is "add" operation, so don't remove headers.
    //pj_list_init(&regc->hdr_list);

    hdr = hdr_list->next;
    while (hdr != hdr_list) {
	pj_list_push_back(&regc->hdr_list, pjsip_hdr_clone(regc->pool, hdr));
	hdr = hdr->next;
    }

    return PJ_SUCCESS;
}
Esempio n. 15
0
/// Add the Via headers that we removed from the request back on the response.
/// We do this by looking at the original request.
void MangelwurzelTsx::add_via_hdrs(pjsip_msg* rsp, pj_pool_t* pool)
{
  // Copy all the via headers from the original request back onto the response
  // in the correct order.
  pjsip_via_hdr* via_hdr = (pjsip_via_hdr*)pjsip_msg_find_hdr(_unmodified_request,
                                                              PJSIP_H_VIA,
                                                              NULL);
  while (via_hdr != NULL)
  {
    pjsip_via_hdr* cloned_via_hdr = (pjsip_via_hdr*)pjsip_hdr_clone(pool,
                                                                    via_hdr);
    pjsip_msg_add_hdr(rsp, (pjsip_hdr*)cloned_via_hdr);

    via_hdr = (pjsip_via_hdr*)pjsip_msg_find_hdr(_unmodified_request,
                                                 PJSIP_H_VIA,
                                                 via_hdr->next);
  }
}
Esempio n. 16
0
/// This is analogous to respond_stateless, although in this case to
/// respond statefully on an existing transaction.  Strangely there is
/// no equivalent PJSIP API.
pj_status_t PJUtils::respond_stateful(pjsip_endpoint* endpt,
                                      pjsip_transaction* uas_tsx,
                                      pjsip_rx_data* rdata,
                                      int st_code,
                                      const pj_str_t* st_text,
                                      const pjsip_hdr* hdr_list,
                                      const pjsip_msg_body* body)
{
  pj_status_t status;
  pjsip_tx_data* tdata;

  status = create_response(stack_data.endpt, rdata, st_code, st_text, &tdata);
  if (status != PJ_SUCCESS)
  {
    return status;
  }

  // Add the message headers, if any
  if (hdr_list)
  {
    const pjsip_hdr* hdr = hdr_list->next;
    while (hdr != hdr_list)
    {
      pjsip_msg_add_hdr(tdata->msg,
                        (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hdr) );
      hdr = hdr->next;
    }
  }

  // Add the message body, if any.
  if (body)
  {
    tdata->msg->body = pjsip_msg_body_clone(tdata->pool, body);
    if (tdata->msg->body == NULL)
    {
      pjsip_tx_data_dec_ref(tdata);
      return status;
    }
  }

  status = pjsip_tsx_send_msg(uas_tsx, tdata);

  return status;
}
Esempio n. 17
0
static int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg)
{
	pjsip_contact_hdr *contact;

	contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
	if (contact && !contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
		pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);

		rewrite_uri(rdata, uri);

		if (dlg && pj_list_empty(&dlg->route_set) && (!dlg->remote.contact
			|| 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;
		}
		return 0;
	}

	return -1;
}
Esempio n. 18
0
/*
 * Set route-set.
 */
PJ_DEF(pj_status_t) pjsip_event_sub_set_route_set( pjsip_event_sub *sub,
						   const pjsip_route_hdr *route_set )
{
    const pjsip_route_hdr *hdr;

    pj_mutex_lock(sub->mutex);

    /* Clear existing route set. */
    pj_list_init(&sub->route_set);

    /* Duplicate route headers. */
    hdr = route_set->next;
    while (hdr != route_set) {
	pjsip_route_hdr *new_hdr = pjsip_hdr_clone(sub->pool, hdr);
	pj_list_insert_before(&sub->route_set, new_hdr);
	hdr = hdr->next;
    }

    pj_mutex_unlock(sub->mutex);

    return 0;
}
Esempio n. 19
0
static void* multipart_clone_data(pj_pool_t *pool, const void *data,
				  unsigned len)
{
    const struct multipart_data *src;
    struct multipart_data *dst;
    const pjsip_multipart_part *src_part;

    PJ_UNUSED_ARG(len);

    src = (const struct multipart_data*) data;
    dst = PJ_POOL_ALLOC_T(pool, struct multipart_data);
    pj_list_init(&dst->part_head);

    pj_strdup(pool, &dst->boundary, &src->boundary);

    src_part = src->part_head.next;
    while (src_part != &src->part_head) {
	pjsip_multipart_part *dst_part;
	const pjsip_hdr *src_hdr;

	dst_part = pjsip_multipart_create_part(pool);

	src_hdr = src_part->hdr.next;
	while (src_hdr != &src_part->hdr) {
	    pjsip_hdr *dst_hdr = (pjsip_hdr*)pjsip_hdr_clone(pool, src_hdr);
	    pj_list_push_back(&dst_part->hdr, dst_hdr);
	    src_hdr = src_hdr->next;
	}

	dst_part->body = pjsip_msg_body_clone(pool, src_part->body);

	pj_list_push_back(&dst->part_head, dst_part);

	src_part = src_part->next;
    }

    return (void*)dst;
}
Esempio n. 20
0
static pj_bool_t handle_rx_message(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
{
	pjsip_contact_hdr *contact;

	if (!endpoint) {
		return PJ_FALSE;
	}

	if (endpoint->nat.rewrite_contact && (contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL)) &&
		!contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) {
		pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri);
		pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);

		pj_cstr(&uri->host, rdata->pkt_info.src_name);
		if (strcasecmp("udp", rdata->tp_info.transport->type_name)) {
			uri->transport_param = pj_str(rdata->tp_info.transport->type_name);
		} else {
			uri->transport_param.slen = 0;
		}
		uri->port = rdata->pkt_info.src_port;
		ast_debug(4, "Re-wrote Contact URI host/port to %.*s:%d\n",
			(int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port);

		/* rewrite the session target since it may have already been pulled from the contact header */
		if (dlg && (!dlg->remote.contact
			|| 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;
		}
	}

	if (endpoint->nat.force_rport) {
		rdata->msg_info.via->rport_param = rdata->pkt_info.src_port;
	}

	return PJ_FALSE;
}
Esempio n. 21
0
void process_register_request(pjsip_rx_data* rdata)
{
  pj_status_t status;
  int st_code = PJSIP_SC_OK;

  // Get the URI from the To header and check it is a SIP or SIPS URI.
  pjsip_uri* uri = (pjsip_uri*)pjsip_uri_get_uri(rdata->msg_info.to->uri);

  if (!PJSIP_URI_SCHEME_IS_SIP(uri))
  {
    // Reject a non-SIP/SIPS URI with 404 Not Found (RFC3261 isn't clear
    // whether 404 is the right status code - it says 404 should be used if
    // the AoR isn't valid for the domain in the RequestURI).
    // LCOV_EXCL_START
    LOG_ERROR("Rejecting register request using non SIP URI");
    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               PJSIP_SC_NOT_FOUND,
                               NULL,
                               NULL,
                               NULL);
    return;
    // LCOV_EXCL_STOP
  }

  // Canonicalize the public ID from the URI in the To header.
  std::string public_id = PJUtils::aor_from_uri((pjsip_sip_uri*)uri);
  LOG_DEBUG("Process REGISTER for public ID %s", public_id.c_str());

  // Get the call identifier and the cseq number from the respective headers.
  std::string cid = PJUtils::pj_str_to_string((const pj_str_t*)&rdata->msg_info.cid->id);;
  int cseq = rdata->msg_info.cseq->cseq;
  pjsip_msg *msg = rdata->msg_info.msg;

  // Add SAS markers to the trail attached to the message so the trail
  // becomes searchable.
  SAS::TrailId trail = get_trail(rdata);
  LOG_DEBUG("Report SAS start marker - trail (%llx)", trail);
  SAS::Marker start_marker(trail, SASMarker::INIT_TIME, 1u);
  SAS::report_marker(start_marker);

  SAS::Marker calling_dn(trail, SASMarker::CALLING_DN, 1u);
  pjsip_sip_uri* calling_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(rdata->msg_info.to->uri);
  calling_dn.add_var_param(calling_uri->user.slen, calling_uri->user.ptr);
  SAS::report_marker(calling_dn);

  SAS::Marker cid_marker(trail, SASMarker::SIP_CALL_ID, 1u);
  cid_marker.add_var_param(rdata->msg_info.cid->id.slen, rdata->msg_info.cid->id.ptr);
  SAS::report_marker(cid_marker, SAS::Marker::Scope::TrailGroup);

  // Query the HSS for the associated URIs.
  // This should really include the private ID, but we don't yet have a
  // homestead API for it.  Homestead won't be able to query a third-party HSS
  // without the private ID.
  Json::Value* uris = hss->get_associated_uris(public_id, trail);
  if ((uris == NULL) ||
      (uris->size() == 0))
  {
    // We failed to get the list of associated URIs.  This indicates that the
    // HSS is unavailable, the public identity doesn't exist or the public
    // identity doesn't belong to the private identity.  Reject with 403.
    LOG_ERROR("Rejecting register request with invalid public/private identity");
    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               PJSIP_SC_FORBIDDEN,
                               NULL,
                               NULL,
                               NULL);
    return;
  }

  // Determine the AOR from the first entry in the uris array.
  std::string aor = uris->get((Json::ArrayIndex)0, Json::Value::null).asString();
  LOG_DEBUG("REGISTER for public ID %s uses AOR %s", public_id.c_str(), aor.c_str());

  // Find the expire headers in the message.
  pjsip_expires_hdr* expires = (pjsip_expires_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);

  // Get the system time in seconds for calculating absolute expiry times.
  int now = time(NULL);
  int expiry = 0;

  // The registration service uses optimistic locking to avoid concurrent
  // updates to the same AoR conflicting.  This means we have to loop
  // reading, updating and writing the AoR until the write is successful.
  RegData::AoR* aor_data = NULL;
  do
  {
    if (aor_data != NULL)
    {
      delete aor_data; // LCOV_EXCL_LINE - Single-threaded tests mean we'll
                       //                  always pass CAS.
    }

    // Find the current bindings for the AoR.
    aor_data = store->get_aor_data(aor);
    LOG_DEBUG("Retrieved AoR data %p", aor_data);

    if (aor_data == NULL)
    {
      // Failed to get data for the AoR because there is no connection
      // to the store.  Reject the register with a 500 response.
      // LCOV_EXCL_START - local store (used in testing) never fails
      LOG_ERROR("Failed to get AoR binding for %s from store", aor.c_str());
      st_code = PJSIP_SC_INTERNAL_SERVER_ERROR;
      break;
      // LCOV_EXCL_STOP
    }

    // Now loop through all the contacts.  If there are multiple contacts in
    // the contact header in the SIP message, pjsip parses them to separate
    // contact header structures.
    pjsip_contact_hdr* contact = (pjsip_contact_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);
    while (contact != NULL)
    {
      if (contact->star)
      {
        // Wildcard contact, which can only be used to clear all bindings for
        // the AoR.
        aor_data->clear();
        break;
      }

      pjsip_uri* uri = (contact->uri != NULL) ?
                           (pjsip_uri*)pjsip_uri_get_uri(contact->uri) :
                           NULL;

      if ((uri != NULL) &&
          (PJSIP_URI_SCHEME_IS_SIP(uri)))
      {
        // The binding identifier is based on the +sip.instance parameter if
        // it is present.  If not the contact URI is used instead.
        std::string contact_uri = PJUtils::uri_to_string(PJSIP_URI_IN_CONTACT_HDR, uri);
        std::string binding_id = get_binding_id(contact);
        if (binding_id == "")
        {
          binding_id = contact_uri;
        }
        LOG_DEBUG(". Binding identifier for contact = %s", binding_id.c_str());

        // Find the appropriate binding in the bindings list for this AoR.
        RegData::AoR::Binding* binding = aor_data->get_binding(binding_id);

        if ((cid != binding->_cid) ||
            (cseq > binding->_cseq))
        {
          // Either this is a new binding, has come from a restarted device, or
          // is an update to an existing binding.
          binding->_uri = contact_uri;

          // TODO Examine Via header to see if we're the first hop
          // TODO Only if we're not the first hop, check that the top path header has "ob" parameter

          // Get the Path headers, if present.  RFC 3327 allows us the option of
          // rejecting a request with a Path header if there is no corresponding
          // "path" entry in the Supported header but we don't do so on the assumption
          // that the edge proxy knows what it's doing.
          binding->_path_headers.clear();
          pjsip_generic_string_hdr* path_hdr =
            (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(msg, &STR_PATH, NULL);
          while (path_hdr)
          {
            std::string path = PJUtils::pj_str_to_string(&path_hdr->hvalue);
            LOG_DEBUG("Path header %s", path.c_str());

            // Extract all the paths from this header.
            Utils::split_string(path, ',', binding->_path_headers, 0, true);

            // Look for the next header.
            path_hdr = (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(msg, &STR_PATH, path_hdr->next);
          }

          binding->_cid = cid;
          binding->_cseq = cseq;
          binding->_priority = contact->q1000;
          binding->_params.clear();
          pjsip_param* p = contact->other_param.next;
          while ((p != NULL) && (p != &contact->other_param))
          {
            std::string pname = PJUtils::pj_str_to_string(&p->name);
            std::string pvalue = PJUtils::pj_str_to_string(&p->value);
            binding->_params.push_back(std::make_pair(pname, pvalue));
            p = p->next;
          }

          // Calculate the expiry period for the updated binding.
          expiry = (contact->expires != -1) ? contact->expires :
                       (expires != NULL) ? expires->ivalue : 300;
          if (expiry > 300)
          {
            // Expiry is too long, set it to the maximum of 300 seconds (5 minutes).
            expiry = 300;
          }

          binding->_expires = now + expiry;

          if (analytics != NULL)
          {
            // Generate an analytics log for this binding update.
            analytics->registration(aor, binding_id, contact_uri, expiry);
          }
        }
      }
      contact = (pjsip_contact_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, contact->next);
    }
  }
  while (!store->set_aor_data(aor, aor_data));

  if (aor_data != NULL)
  {
    // Log the bindings.
    log_bindings(aor, aor_data);
  }

  // Build and send the reply.
  pjsip_tx_data* tdata;
  status = PJUtils::create_response(stack_data.endpt, rdata, st_code, NULL, &tdata);
  if (status != PJ_SUCCESS)
  {
    // LCOV_EXCL_START - don't know how to get PJSIP to fail to create a response
    LOG_ERROR("Error building REGISTER %d response %s", st_code,
              PJUtils::pj_status_to_string(status).c_str());
    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               PJSIP_SC_INTERNAL_SERVER_ERROR,
                               NULL,
                               NULL,
                               NULL);
    delete aor_data;
    return;
    // LCOV_EXCL_STOP
  }

  if (st_code != PJSIP_SC_OK)
  {
    // LCOV_EXCL_START - we only reject REGISTER if something goes wrong, and
    // we aren't covering any of those paths so we can't hit this either
    status = pjsip_endpt_send_response2(stack_data.endpt, rdata, tdata, NULL, NULL);
    delete aor_data;
    return;
    // LCOV_EXCL_STOP
  }

  // Add supported and require headers for RFC5626.
  pjsip_generic_string_hdr* gen_hdr;
  gen_hdr = pjsip_generic_string_hdr_create(tdata->pool,
                                            &STR_SUPPORTED,
                                            &STR_OUTBOUND);
  if (gen_hdr == NULL)
  {
    // LCOV_EXCL_START - can't see how this could ever happen
    LOG_ERROR("Failed to add RFC 5626 headers");
    tdata->msg->line.status.code = PJSIP_SC_INTERNAL_SERVER_ERROR;
    status = pjsip_endpt_send_response2(stack_data.endpt, rdata, tdata, NULL, NULL);
    delete aor_data;
    return;
    // LCOV_EXCL_STOP
  }
  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)gen_hdr);

  // Add contact headers for all active bindings.
  for (RegData::AoR::Bindings::const_iterator i = aor_data->bindings().begin();
       i != aor_data->bindings().end();
       ++i)
  {
    RegData::AoR::Binding* binding = i->second;
    if (binding->_expires > now)
    {
      // The binding hasn't expired.
      pjsip_uri* uri = PJUtils::uri_from_string(binding->_uri, tdata->pool);
      if (uri != NULL)
      {
        // Contact URI is well formed, so include this in the response.
        pjsip_contact_hdr* contact = pjsip_contact_hdr_create(tdata->pool);
        contact->star = 0;
        contact->uri = uri;
        contact->q1000 = binding->_priority;
        contact->expires = binding->_expires - now;
        pj_list_init(&contact->other_param);
        for (std::list<std::pair<std::string, std::string> >::iterator j = binding->_params.begin();
             j != binding->_params.end();
             ++j)
        {
          pjsip_param *new_param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
          pj_strdup2(tdata->pool, &new_param->name, j->first.c_str());
          pj_strdup2(tdata->pool, &new_param->value, j->second.c_str());
          pj_list_insert_before(&contact->other_param, new_param);
        }
        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)contact);
      }
      else
      {
        // Contact URI is malformed.  Log an error, but otherwise don't try and
        // fix it.
        // LCOV_EXCL_START hard to hit - needs bad data in the store
        LOG_WARNING("Badly formed contact URI %s for address of record %s",
                    binding->_uri.c_str(), aor.c_str());
        // LCOV_EXCL_STOP
      }
    }
  }

  // Deal with path header related fields in the response.
  pjsip_generic_string_hdr* path_hdr =
    (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(msg, &STR_PATH, NULL);
  if ((path_hdr != NULL) &&
      (!aor_data->bindings().empty()))
  {
    // We have bindings with path headers so we must require outbound.
    pjsip_require_hdr* require_hdr = pjsip_require_hdr_create(tdata->pool);
    require_hdr->count = 1;
    require_hdr->values[0] = STR_OUTBOUND;
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)require_hdr);
  }

  // Echo back any Path headers as per RFC 3327, section 5.3.  We take these
  // from the request as they may not exist in the bindings any more if the
  // bindings have expired.
  while (path_hdr)
  {
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, path_hdr));
    path_hdr = (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(msg, &STR_PATH, path_hdr->next);
  }

  // Construct a Service-Route header pointing at the sprout cluster.  We don't
  // care which sprout handles the subsequent requests as they all have access
  // to all subscriber information.
  pjsip_sip_uri* service_route_uri = pjsip_sip_uri_create(tdata->pool, false);
  pj_strdup(tdata->pool,
            &service_route_uri->host,
            &stack_data.sprout_cluster_domain);
  service_route_uri->port = stack_data.trusted_port;
  service_route_uri->transport_param = pj_str("TCP");
  service_route_uri->lr_param = 1;

  pjsip_route_hdr* service_route = pjsip_route_hdr_create(tdata->pool);
  service_route->name = STR_SERVICE_ROUTE;
  service_route->sname = pj_str("");
  service_route->name_addr.uri = (pjsip_uri*)service_route_uri;

  pjsip_msg_insert_first_hdr(tdata->msg, (pjsip_hdr*)service_route);

  // Add P-Associated-URI headers for all of the associated URIs.
  static const pj_str_t p_associated_uri_hdr_name = pj_str("P-Associated-URI");
  for (Json::ValueIterator it = uris->begin(); it != uris->end(); it++)
  {
    pj_str_t associated_uri = {(char*)(*it).asCString(), strlen((*it).asCString())};
    pjsip_hdr* associated_uri_hdr =
      (pjsip_hdr*)pjsip_generic_string_hdr_create(tdata->pool,
                                                  &p_associated_uri_hdr_name,
                                                  &associated_uri);
    pjsip_msg_add_hdr(tdata->msg, associated_uri_hdr);
  }
  delete uris;

  // Send the response, but prevent the transmitted data from being freed, as we may need to inform the
  // ASes of the 200 OK response we sent.
  pjsip_tx_data_add_ref(tdata);
  status = pjsip_endpt_send_response2(stack_data.endpt, rdata, tdata, NULL, NULL);

  RegistrationUtils::register_with_application_servers(ifchandler, store, rdata, tdata, "");

  // Now we can free the tdata.
  pjsip_tx_data_dec_ref(tdata);

  LOG_DEBUG("Report SAS end marker - trail (%llx)", trail);
  SAS::Marker end_marker(trail, SASMarker::END_TIME, 1u);
  SAS::report_marker(end_marker);
  delete aor_data;
}
Esempio n. 22
0
PJ_DEF(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg,
					pjsip_tx_data **p_tdata)
{
    pjsip_msg *msg;
    pjsip_contact_hdr *hdr;
    const pjsip_hdr *h_allow;
    pj_status_t status;
    pjsip_tx_data *tdata;

    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);

    pj_lock_acquire(regc->lock);

    status = create_request(regc, &tdata);
    if (status != PJ_SUCCESS) {
	pj_lock_release(regc->lock);
	return status;
    }

    msg = tdata->msg;

    /* Add Contact headers. */
    hdr = regc->contact_hdr_list.next;
    while (hdr != &regc->contact_hdr_list) {
	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
			       pjsip_hdr_shallow_clone(tdata->pool, hdr));
	hdr = hdr->next;
    }

    /* Also add bindings which are to be removed */
    while (!pj_list_empty(&regc->removed_contact_hdr_list)) {
	hdr = regc->removed_contact_hdr_list.next;
	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
			       pjsip_hdr_clone(tdata->pool, hdr));
	pj_list_erase(hdr);
    }
    

    if (regc->expires_hdr)
	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
			       pjsip_hdr_shallow_clone(tdata->pool,
						       regc->expires_hdr));

    if (regc->timer.id != 0) {
	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
	regc->timer.id = 0;
    }

    /* Add Allow header (http://trac.pjsip.org/repos/ticket/1039) */
    h_allow = pjsip_endpt_get_capability(regc->endpt, PJSIP_H_ALLOW, NULL);
    if (h_allow) {
	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
			       pjsip_hdr_shallow_clone(tdata->pool, h_allow));

    }

    regc->auto_reg = autoreg;

    pj_lock_release(regc->lock);

    /* Done */
    *p_tdata = tdata;
    return PJ_SUCCESS;
}
Esempio n. 23
0
/*
 * Update authentication session with a challenge.
 */
static void update_digest_session( pj_pool_t *ses_pool, 
				   pjsip_cached_auth *cached_auth,
				   const pjsip_www_authenticate_hdr *hdr )
{
    if (hdr->challenge.digest.qop.slen == 0) {
#if PJSIP_AUTH_AUTO_SEND_NEXT!=0
	if (!cached_auth->last_chal || pj_stricmp2(&hdr->scheme, "digest")) {
	    cached_auth->last_chal = (pjsip_www_authenticate_hdr*)
				     pjsip_hdr_clone(ses_pool, hdr);
	} else {
	    /* Only update if the new challenge is "significantly different"
	     * than the one in the cache, to reduce memory usage.
	     */
	    const pjsip_digest_challenge *d1 = 
			&cached_auth->last_chal->challenge.digest;
	    const pjsip_digest_challenge *d2 = &hdr->challenge.digest;

	    if (pj_strcmp(&d1->domain, &d2->domain) ||
		pj_strcmp(&d1->realm, &d2->realm) ||
		pj_strcmp(&d1->nonce, &d2->nonce) ||
		pj_strcmp(&d1->opaque, &d2->opaque) ||
		pj_strcmp(&d1->algorithm, &d2->algorithm) ||
		pj_strcmp(&d1->qop, &d2->qop))
	    {
		cached_auth->last_chal = (pjsip_www_authenticate_hdr*)
				         pjsip_hdr_clone(ses_pool, hdr);
	    }
	}
#endif
	return;
    }

    /* Initialize cnonce and qop if not present. */
    if (cached_auth->cnonce.slen == 0) {
	/* Save the whole challenge */
	cached_auth->last_chal = (pjsip_www_authenticate_hdr*)
				 pjsip_hdr_clone(ses_pool, hdr);

	/* Create cnonce */
	pj_create_unique_string( ses_pool, &cached_auth->cnonce );

	/* Initialize nonce-count */
	cached_auth->nc = 1;

	/* Save realm. */
	/* Note: allow empty realm (http://trac.pjsip.org/repos/ticket/1061)
	pj_assert(cached_auth->realm.slen != 0);
	*/
	if (cached_auth->realm.slen == 0) {
	    pj_strdup(ses_pool, &cached_auth->realm, 
		      &hdr->challenge.digest.realm);
	}

    } else {
	/* Update last_nonce and nonce-count */
	if (!pj_strcmp(&hdr->challenge.digest.nonce, 
		       &cached_auth->last_chal->challenge.digest.nonce)) 
	{
	    /* Same nonce, increment nonce-count */
	    ++cached_auth->nc;
	} else {
	    /* Server gives new nonce. */
	    pj_strdup(ses_pool, &cached_auth->last_chal->challenge.digest.nonce,
		      &hdr->challenge.digest.nonce);
	    /* Has the opaque changed? */
	    if (pj_strcmp(&cached_auth->last_chal->challenge.digest.opaque,
			  &hdr->challenge.digest.opaque)) 
	    {
		pj_strdup(ses_pool, 
			  &cached_auth->last_chal->challenge.digest.opaque,
			  &hdr->challenge.digest.opaque);
	    }
	    cached_auth->nc = 1;
	}
    }
}
Esempio n. 24
0
/* 
 * Create Authorization/Proxy-Authorization response header based on the challege
 * in WWW-Authenticate/Proxy-Authenticate header.
 */
static pj_status_t auth_respond( pj_pool_t *req_pool,
				 const pjsip_www_authenticate_hdr *hdr,
				 const pjsip_uri *uri,
				 const pjsip_cred_info *cred_info,
				 const pjsip_method *method,
				 pj_pool_t *sess_pool,
				 pjsip_cached_auth *cached_auth,
				 pjsip_authorization_hdr **p_h_auth)
{
    pjsip_authorization_hdr *hauth;
    char tmp[PJSIP_MAX_URL_SIZE];
    pj_str_t uri_str;
    pj_pool_t *pool;
    pj_status_t status;

    /* Verify arguments. */
    PJ_ASSERT_RETURN(req_pool && hdr && uri && cred_info && method &&
		     sess_pool && cached_auth && p_h_auth, PJ_EINVAL);

    /* Print URL in the original request. */
    uri_str.ptr = tmp;
    uri_str.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, tmp,sizeof(tmp));
    if (uri_str.slen < 1) {
	pj_assert(!"URL is too long!");
	return PJSIP_EURITOOLONG;
    }

#   if (PJSIP_AUTH_HEADER_CACHING)
    {
	pool = sess_pool;
	PJ_UNUSED_ARG(req_pool);
    }
#   else
    {
	pool = req_pool;
	PJ_UNUSED_ARG(sess_pool);
    }
#   endif

    if (hdr->type == PJSIP_H_WWW_AUTHENTICATE)
	hauth = pjsip_authorization_hdr_create(pool);
    else if (hdr->type == PJSIP_H_PROXY_AUTHENTICATE)
	hauth = pjsip_proxy_authorization_hdr_create(pool);
    else {
	pj_assert(!"Invalid response header!");
	return PJSIP_EINVALIDHDR;
    }

    /* Only support digest scheme at the moment. */
    if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
	pj_str_t *cnonce = NULL;
	pj_uint32_t nc = 1;

	/* Update the session (nonce-count etc) if required. */
#	if PJSIP_AUTH_QOP_SUPPORT
	{
	    if (cached_auth) {
		update_digest_session( sess_pool, cached_auth, hdr );

		cnonce = &cached_auth->cnonce;
		nc = cached_auth->nc;
	    }
	}
#	endif	/* PJSIP_AUTH_QOP_SUPPORT */

	hauth->scheme = pjsip_DIGEST_STR;
	status = respond_digest( pool, &hauth->credential.digest,
				 &hdr->challenge.digest, &uri_str, cred_info,
				 cnonce, nc, &method->name);
	if (status != PJ_SUCCESS)
	    return status;

	/* Set qop type in auth session the first time only. */
	if (hdr->challenge.digest.qop.slen != 0 && cached_auth) {
	    if (cached_auth->qop_value == PJSIP_AUTH_QOP_NONE) {
		pj_str_t *qop_val = &hauth->credential.digest.qop;
		if (!pj_strcmp(qop_val, &pjsip_AUTH_STR)) {
		    cached_auth->qop_value = PJSIP_AUTH_QOP_AUTH;
		} else {
		    cached_auth->qop_value = PJSIP_AUTH_QOP_UNKNOWN;
		}
	    }
	}
    } else {
	return PJSIP_EINVALIDAUTHSCHEME;
    }

    /* Keep the new authorization header in the cache, only
     * if no qop is not present.
     */
#   if PJSIP_AUTH_HEADER_CACHING
    {
	if (hauth && cached_auth && cached_auth->qop_value == PJSIP_AUTH_QOP_NONE) {
	    pjsip_cached_auth_hdr *cached_hdr;

	    /* Delete old header with the same method. */
	    cached_hdr = cached_auth->cached_hdr.next;
	    while (cached_hdr != &cached_auth->cached_hdr) {
		if (pjsip_method_cmp(method, &cached_hdr->method)==0)
		    break;
		cached_hdr = cached_hdr->next;
	    }

	    /* Save the header to the list. */
	    if (cached_hdr != &cached_auth->cached_hdr) {
		cached_hdr->hdr = hauth;
	    } else {
		cached_hdr = pj_pool_alloc(pool, sizeof(*cached_hdr));
		pjsip_method_copy( pool, &cached_hdr->method, method);
		cached_hdr->hdr = hauth;
		pj_list_insert_before( &cached_auth->cached_hdr, cached_hdr );
	    }
	}

#	if defined(PJSIP_AUTH_AUTO_SEND_NEXT) && PJSIP_AUTH_AUTO_SEND_NEXT!=0
	    if (hdr != cached_auth->last_chal) {
		cached_auth->last_chal = pjsip_hdr_clone(sess_pool, hdr);
	    }
#	endif
    }
#   endif

    *p_h_auth = hauth;
    return PJ_SUCCESS;

}
Esempio n. 25
0
static void regc_tsx_callback(void *token, pjsip_event *event)
{
    pj_status_t status;
    pjsip_regc *regc = (pjsip_regc*) token;
    pjsip_transaction *tsx = event->body.tsx_state.tsx;
    pj_bool_t handled = PJ_TRUE;
    pj_bool_t update_contact = PJ_FALSE;

    pj_atomic_inc(regc->busy_ctr);
    pj_lock_acquire(regc->lock);

    /* Decrement pending transaction counter. */
    pj_assert(regc->has_tsx);
    regc->has_tsx = PJ_FALSE;

    /* Add reference to the transport */
    if (tsx->transport != regc->last_transport) {
	if (regc->last_transport) {
	    pjsip_transport_dec_ref(regc->last_transport);
	    regc->last_transport = NULL;
	}

	if (tsx->transport) {
	    regc->last_transport = tsx->transport;
	    pjsip_transport_add_ref(regc->last_transport);
	}
    }

    if (regc->_delete_flag == 0 && regc->tsx_cb &&
        regc->current_op == REGC_REGISTERING)
    {
        struct pjsip_regc_tsx_cb_param param;

        param.contact_cnt = -1;
        cbparam_init(&param.cbparam, regc, PJ_SUCCESS, tsx->status_code,
		     &tsx->status_text,
                     (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ? 
	              event->body.tsx_state.src.rdata : NULL,
                     -1, 0, NULL);

        /* Call regc tsx callback before handling any response */
        pj_lock_release(regc->lock);
        (*regc->tsx_cb)(&param);
        pj_lock_acquire(regc->lock);

        if (param.contact_cnt >= 0) {
            /* Since we receive non-2xx response, it means that (some) contact
             * bindings haven't been established so we can safely remove these
             * contact headers. This is to avoid removing non-existent contact
             * bindings later.
             */
            if (tsx->status_code/100 != 2) {
                pjsip_contact_hdr *h;

	        h = regc->contact_hdr_list.next;
	        while (h != &regc->contact_hdr_list) {
                    pjsip_contact_hdr *next = h->next;

                    if (h->expires == -1) {
                        pj_list_erase(h);
                    }
                    h = next;
                }
	    }

            /* Update contact address */
            pjsip_regc_update_contact(regc, param.contact_cnt, param.contact);
            update_contact = PJ_TRUE;
        }
    }

    /* Handle 401/407 challenge (even when _delete_flag is set) */
    if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
	tsx->status_code == PJSIP_SC_UNAUTHORIZED)
    {
	pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
	pjsip_tx_data *tdata;

	/* reset current op */
	regc->current_op = REGC_IDLE;

        if (update_contact) {
            pjsip_msg *msg;
            pjsip_hdr *hdr, *ins_hdr;
            pjsip_contact_hdr *chdr;

            /* Delete Contact headers, but we shouldn't delete headers
             * which are supposed to remove contact bindings since
             * we cannot reconstruct those headers.
             */
            msg = tsx->last_tx->msg;
            hdr = msg->hdr.next;
            ins_hdr = &msg->hdr;
            while (hdr != &msg->hdr) {
                pjsip_hdr *next = hdr->next;

                if (hdr->type == PJSIP_H_CONTACT) {
                    chdr = (pjsip_contact_hdr *)hdr;
                    if (chdr->expires != 0) {
                        pj_list_erase(hdr);
                        ins_hdr = next;
                    }
                }
                hdr = next;
            }

            /* Add Contact headers. */
            chdr = regc->contact_hdr_list.next;
            while (chdr != &regc->contact_hdr_list) {
	        pj_list_insert_before(ins_hdr, (pjsip_hdr*)
                    pjsip_hdr_shallow_clone(tsx->last_tx->pool, chdr));
	        chdr = chdr->next;
            }

            /* Also add bindings which are to be removed */
            while (!pj_list_empty(&regc->removed_contact_hdr_list)) {
	        chdr = regc->removed_contact_hdr_list.next;
	        pj_list_insert_before(ins_hdr, (pjsip_hdr*)
                    pjsip_hdr_clone(tsx->last_tx->pool, chdr));
	        pj_list_erase(chdr);
            }
        }

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

	if (status == PJ_SUCCESS) {
	    status = pjsip_regc_send(regc, tdata);
	}
	
	if (status != PJ_SUCCESS) {

	    /* Only call callback if application is still interested
	     * in it.
	     */
	    if (regc->_delete_flag == 0) {
		/* Should be safe to release the lock temporarily.
		 * We do this to avoid deadlock. 
		 */
		pj_lock_release(regc->lock);
		call_callback(regc, status, tsx->status_code, 
			      &rdata->msg_info.msg->line.status.reason,
			      rdata, -1, 0, NULL);
		pj_lock_acquire(regc->lock);
	    }
	}

    } else if (regc->_delete_flag) {

	/* User has called pjsip_regc_destroy(), so don't call callback. 
	 * This regc will be destroyed later in this function.
	 */

	/* Just reset current op */
	regc->current_op = REGC_IDLE;

    } else if (tsx->status_code == PJSIP_SC_INTERVAL_TOO_BRIEF &&
	       regc->current_op == REGC_REGISTERING)
    {
	/* Handle 423 response automatically:
	 *  - set requested expiration to Min-Expires header, ONLY IF
	 *    the original request is a registration (as opposed to
	 *    unregistration) and the requested expiration was indeed
	 *    lower than Min-Expires)
	 *  - resend the request
	 */
	pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
	pjsip_min_expires_hdr *me_hdr;
	pjsip_tx_data *tdata;
	pj_int32_t min_exp;

	/* reset current op */
	regc->current_op = REGC_IDLE;

	/* Update requested expiration */
	me_hdr = (pjsip_min_expires_hdr*)
		 pjsip_msg_find_hdr(rdata->msg_info.msg,
				    PJSIP_H_MIN_EXPIRES, NULL);
	if (me_hdr) {
	    min_exp = me_hdr->ivalue;
	} else {
	    /* Broken server, Min-Expires doesn't exist.
	     * Just guestimate then, BUT ONLY if if this is the
	     * first time we received such response.
	     */
	    enum {
		/* Note: changing this value would require changing couple of
		 *       Python test scripts.
		 */
		UNSPECIFIED_MIN_EXPIRES = 3601
	    };
	    if (!regc->expires_hdr ||
		 regc->expires_hdr->ivalue != UNSPECIFIED_MIN_EXPIRES)
	    {
		min_exp = UNSPECIFIED_MIN_EXPIRES;
	    } else {
		handled = PJ_FALSE;
		PJ_LOG(4,(THIS_FILE, "Registration failed: 423 response "
				     "without Min-Expires header is invalid"));
		goto handle_err;
	    }
	}

	if (regc->expires_hdr && regc->expires_hdr->ivalue >= min_exp) {
	    /* But we already send with greater expiration time, why does
	     * the server send us with 423? Oh well, just fail the request.
	     */
	    handled = PJ_FALSE;
	    PJ_LOG(4,(THIS_FILE, "Registration failed: invalid "
			         "Min-Expires header value in response"));
	    goto handle_err;
	}

	set_expires(regc, min_exp);

	status = pjsip_regc_register(regc, regc->auto_reg, &tdata);
	if (status == PJ_SUCCESS) {
	    status = pjsip_regc_send(regc, tdata);
	}

	if (status != PJ_SUCCESS) {
	    /* Only call callback if application is still interested
	     * in it.
	     */
	    if (!regc->_delete_flag) {
		/* Should be safe to release the lock temporarily.
		 * We do this to avoid deadlock.
		 */
		pj_lock_release(regc->lock);
		call_callback(regc, status, tsx->status_code,
			      &rdata->msg_info.msg->line.status.reason,
			      rdata, -1, 0, NULL);
		pj_lock_acquire(regc->lock);
	    }
	}

    } else {
	handled = PJ_FALSE;
    }

handle_err:
    if (!handled) {
	pjsip_rx_data *rdata;
	pj_int32_t expiration = NOEXP;
	unsigned contact_cnt = 0;
	pjsip_contact_hdr *contact[PJSIP_REGC_MAX_CONTACT];

	if (tsx->status_code/100 == 2) {

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

	    /* Calculate expiration */
	    expiration = calculate_response_expiration(regc, rdata, 
						       &contact_cnt,
						       PJSIP_REGC_MAX_CONTACT,
						       contact);

	    /* Schedule next registration */
            schedule_registration(regc, expiration);

	} else {
	    rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ? 
			event->body.tsx_state.src.rdata : NULL;
	}

	/* Update registration */
	if (expiration==NOEXP) expiration=-1;
	regc->expires = expiration;

	/* Mark operation as complete */
	regc->current_op = REGC_IDLE;

	/* Call callback. */
	/* Should be safe to release the lock temporarily.
	 * We do this to avoid deadlock. 
	 */
	pj_lock_release(regc->lock);
	call_callback(regc, PJ_SUCCESS, tsx->status_code, 
		      (rdata ? &rdata->msg_info.msg->line.status.reason 
			: &tsx->status_text),
		      rdata, expiration, 
		      contact_cnt, contact);
	pj_lock_acquire(regc->lock);
    }

    pj_lock_release(regc->lock);

    /* Delete the record if user destroy regc during the callback. */
    if (pj_atomic_dec_and_get(regc->busy_ctr)==0 && regc->_delete_flag) {
	pjsip_regc_destroy(regc);
    }
}
Esempio n. 26
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;
}
Esempio n. 27
0
/*
 * create response benchmark
 */
static int create_response_bench(pj_timestamp *p_elapsed)
{
    enum { COUNT = 100 };
    unsigned i, j;
    pjsip_via_hdr *via;
    pjsip_rx_data rdata;
    pjsip_tx_data *request;
    pjsip_tx_data *tdata[COUNT];
    pj_timestamp t1, t2, elapsed;
    pj_status_t status;

    /* Create the request first. */
    pj_str_t str_target = pj_str("sip:[email protected]");
    pj_str_t str_from = pj_str("\"Local User\" <sip:[email protected]>");
    pj_str_t str_to = pj_str("\"Remote User\" <sip:[email protected]>");
    pj_str_t str_contact = str_from;

    status = pjsip_endpt_create_request(endpt, &pjsip_invite_method,
					&str_target, &str_from, &str_to,
					&str_contact, NULL, -1, NULL,
					&request);
    if (status != PJ_SUCCESS) {
	app_perror("    error: unable to create request", status);
	return status;
    }

    /* Create several Via headers */
    via = pjsip_via_hdr_create(request->pool);
    via->sent_by.host = pj_str("192.168.0.7");
    via->sent_by.port = 5061;
    via->transport = pj_str("udp");
    via->rport_param = 0;
    via->branch_param = pj_str("012345678901234567890123456789");
    via->recvd_param = pj_str("192.168.0.7");
    pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*) pjsip_hdr_clone(request->pool, via));
    pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*) pjsip_hdr_clone(request->pool, via));
    pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via);
    

    /* Create "dummy" rdata from the tdata */
    pj_bzero(&rdata, sizeof(pjsip_rx_data));
    rdata.tp_info.pool = request->pool;
    rdata.msg_info.msg = request->msg;
    rdata.msg_info.from = (pjsip_from_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL);
    rdata.msg_info.to = (pjsip_to_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL);
    rdata.msg_info.cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL);
    rdata.msg_info.cid = (pjsip_cid_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL);
    rdata.msg_info.via = via;

    /*
     * Now benchmark create_response
     */
    elapsed.u64 = 0;

    for (i=0; i<LOOP; i+=COUNT) {
	pj_bzero(tdata, sizeof(tdata));

	pj_get_timestamp(&t1);

	for (j=0; j<COUNT; ++j) {
	    status = pjsip_endpt_create_response(endpt, &rdata, 200, NULL, &tdata[j]);
	    if (status != PJ_SUCCESS) {
		app_perror("    error: unable to create request", status);
		goto on_error;
	    }
	}

	pj_get_timestamp(&t2);
	pj_sub_timestamp(&t2, &t1);
	pj_add_timestamp(&elapsed, &t2);
	
	for (j=0; j<COUNT; ++j)
	    pjsip_tx_data_dec_ref(tdata[j]);
    }

    p_elapsed->u64 = elapsed.u64;
    pjsip_tx_data_dec_ref(request);
    return PJ_SUCCESS;

on_error:
    for (i=0; i<COUNT; ++i) {
	if (tdata[i])
	    pjsip_tx_data_dec_ref(tdata[i]);
    }
    return -400;
}
Esempio n. 28
0
static pj_bool_t regs_rx_request(pjsip_rx_data *rdata)
{
    pjsip_msg *msg = rdata->msg_info.msg;
    pjsip_hdr hdr_list;
    int code;
    pj_status_t status;

    if (msg->line.req.method.id != PJSIP_REGISTER_METHOD)
	return PJ_FALSE;

    if (!registrar.cfg.respond)
	return PJ_TRUE;

    pj_list_init(&hdr_list);

    if (registrar.cfg.authenticate && 
	pjsip_msg_find_hdr(msg, PJSIP_H_AUTHORIZATION, NULL)==NULL) 
    {
	pjsip_generic_string_hdr *hwww;
	const pj_str_t hname = pj_str("WWW-Authenticate");
	const pj_str_t hvalue = pj_str("Digest realm=\"test\"");

	hwww = pjsip_generic_string_hdr_create(rdata->tp_info.pool, &hname, 
					       &hvalue);
	pj_list_push_back(&hdr_list, hwww);

	code = 401;

    } else {
	if (registrar.cfg.contact_op == EXACT ||
	    registrar.cfg.contact_op == MODIFIED) 
	{
	    pjsip_hdr *hsrc;

	    for (hsrc=msg->hdr.next; hsrc!=&msg->hdr; hsrc=hsrc->next) {
		pjsip_contact_hdr *hdst;

		if (hsrc->type != PJSIP_H_CONTACT)
		    continue;

		hdst = (pjsip_contact_hdr*)
		       pjsip_hdr_clone(rdata->tp_info.pool, hsrc);

		if (hdst->expires==0)
		    continue;

		if (registrar.cfg.contact_op == MODIFIED) {
		    if (PJSIP_URI_SCHEME_IS_SIP(hdst->uri) ||
			PJSIP_URI_SCHEME_IS_SIPS(hdst->uri))
		    {
			pjsip_sip_uri *sip_uri = (pjsip_sip_uri*)
						 pjsip_uri_get_uri(hdst->uri);
			sip_uri->host = pj_str("x-modified-host");
			sip_uri->port = 1;
		    }
		}

		if (registrar.cfg.expires_param)
		    hdst->expires = registrar.cfg.expires_param;

		pj_list_push_back(&hdr_list, hdst);
	    }
	}

	if (registrar.cfg.more_contacts.slen) {
	    pjsip_generic_string_hdr *hcontact;
	    const pj_str_t hname = pj_str("Contact");

	    hcontact = pjsip_generic_string_hdr_create(rdata->tp_info.pool, &hname, 
						       &registrar.cfg.more_contacts);
	    pj_list_push_back(&hdr_list, hcontact);
	}

	if (registrar.cfg.expires) {
	    pjsip_expires_hdr *hexp;

	    hexp = pjsip_expires_hdr_create(rdata->tp_info.pool, 
					    registrar.cfg.expires);
	    pj_list_push_back(&hdr_list, hexp);
	}

	registrar.response_cnt++;

	code = registrar.cfg.status_code;
    }

    status = pjsip_endpt_respond(endpt, NULL, rdata, code, NULL,
				 &hdr_list, NULL, NULL);
    pj_assert(status == PJ_SUCCESS);

    return PJ_TRUE;
}
Esempio n. 29
0
static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
{
    pj_sockaddr hostaddr;
    char temp[80], hostip[PJ_INET6_ADDRSTRLEN];
    pj_str_t local_uri;
    pjsip_dialog *dlg;
    pjsip_rdata_sdp_info *sdp_info;
    pjmedia_sdp_session *answer = NULL;
    pjsip_tx_data *tdata = NULL;
    call_t *call = NULL;
    unsigned i;
    pj_status_t status;

    PJ_LOG(3,(THIS_FILE, "RX %.*s from %s",
	      (int)rdata->msg_info.msg->line.req.method.name.slen,
	      rdata->msg_info.msg->line.req.method.name.ptr,
	      rdata->pkt_info.src_name));

    if (rdata->msg_info.msg->line.req.method.id == PJSIP_REGISTER_METHOD) {
	/* Let me be a registrar! */
	pjsip_hdr hdr_list, *h;
	pjsip_msg *msg;
	int expires = -1;

	pj_list_init(&hdr_list);
	msg = rdata->msg_info.msg;
	h = (pjsip_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
	if (h) {
	    expires = ((pjsip_expires_hdr*)h)->ivalue;
	    pj_list_push_back(&hdr_list, pjsip_hdr_clone(rdata->tp_info.pool, h));
	    PJ_LOG(3,(THIS_FILE, " Expires=%d", expires));
	}
	if (expires != 0) {
	    h = (pjsip_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);
	    if (h)
		pj_list_push_back(&hdr_list, pjsip_hdr_clone(rdata->tp_info.pool, h));
	}

	pjsip_endpt_respond(app.sip_endpt, &mod_sipecho, rdata, 200, NULL,
	                    &hdr_list, NULL, NULL);
	return PJ_TRUE;
    }

    if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
	if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
	    pj_str_t reason = pj_str("Go away");
	    pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
					   400, &reason,
					   NULL, NULL);
	}
	return PJ_TRUE;
    }

    sdp_info = pjsip_rdata_get_sdp_info(rdata);
    if (!sdp_info || !sdp_info->sdp) {
	pj_str_t reason = pj_str("Require valid offer");
	pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
				       400, &reason,
				       NULL, NULL);
    }

    for (i=0; i<MAX_CALLS; ++i) {
	if (app.call[i].inv == NULL) {
	    call = &app.call[i];
	    break;
	}
    }

    if (i==MAX_CALLS) {
	pj_str_t reason = pj_str("We're full");
	pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
				       PJSIP_SC_BUSY_HERE, &reason,
				       NULL, NULL);
	return PJ_TRUE;
    }

    /* Generate Contact URI */
    status = pj_gethostip(AF, &hostaddr);
    if (status != PJ_SUCCESS) {
	app_perror(THIS_FILE, "Unable to retrieve local host IP", status);
	return PJ_TRUE;
    }
    pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);
    pj_ansi_sprintf(temp, "<sip:sipecho@%s:%d>", hostip, SIP_PORT);
    local_uri = pj_str(temp);

    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
				   &local_uri, &dlg);

    if (status == PJ_SUCCESS)
	answer = create_answer(call-app.call, dlg->pool, sdp_info->sdp);
    if (status == PJ_SUCCESS)
    	status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &call->inv);
    if (status == PJ_SUCCESS)
    	status = pjsip_inv_initial_answer(call->inv, rdata, 100,
				          NULL, NULL, &tdata);
    if (status == PJ_SUCCESS)
    	status = pjsip_inv_send_msg(call->inv, tdata);

    if (status == PJ_SUCCESS)
    	status = pjsip_inv_answer(call->inv, 180, NULL,
    	                          NULL, &tdata);
    if (status == PJ_SUCCESS)
    	status = pjsip_inv_send_msg(call->inv, tdata);

    if (status == PJ_SUCCESS)
    	status = pjsip_inv_answer(call->inv, 200, NULL,
    	                          NULL, &tdata);
    if (status == PJ_SUCCESS)
    	status = pjsip_inv_send_msg(call->inv, tdata);

    if (status != PJ_SUCCESS) {
	pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
				       500, NULL, NULL, NULL);
	destroy_call(call);
    } else {
	call->inv->mod_data[mod_sipecho.id] = call;
    }

    return PJ_TRUE;
}
Esempio n. 30
0
/*
 * Send response statefully.
 */
PJ_DEF(pj_status_t) pjsip_endpt_respond(  pjsip_endpoint *endpt,
					  pjsip_module *tsx_user,
					  pjsip_rx_data *rdata,
					  int st_code,
					  const pj_str_t *st_text,
					  const pjsip_hdr *hdr_list,
					  const pjsip_msg_body *body,
					  pjsip_transaction **p_tsx )
{
    pj_status_t status;
    pjsip_tx_data *tdata;
    pjsip_transaction *tsx;

    /* Validate arguments. */
    PJ_ASSERT_RETURN(endpt && rdata, PJ_EINVAL);

    if (p_tsx) *p_tsx = NULL;

    /* Create response message */
    status = pjsip_endpt_create_response( endpt, rdata, st_code, st_text, 
					  &tdata);
    if (status != PJ_SUCCESS)
	return status;

    /* Add the message headers, if any */
    if (hdr_list) {
	const pjsip_hdr *hdr = hdr_list->next;
	while (hdr != hdr_list) {
	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
	    		      pjsip_hdr_clone(tdata->pool, hdr) );
	    hdr = hdr->next;
	}
    }

    /* Add the message body, if any. */
    if (body) {
	tdata->msg->body = pjsip_msg_body_clone( tdata->pool, body );
	if (tdata->msg->body == NULL) {
	    pjsip_tx_data_dec_ref(tdata);
	    return status;
	}
    }

    /* Create UAS transaction. */
    status = pjsip_tsx_create_uas(tsx_user, rdata, &tsx);
    if (status != PJ_SUCCESS) {
	pjsip_tx_data_dec_ref(tdata);
	return status;
    }

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

    /* Send the message. */
    status = pjsip_tsx_send_msg(tsx, tdata);
    if (status != PJ_SUCCESS) {
	pjsip_tx_data_dec_ref(tdata);
    } else if (p_tsx) {
	*p_tsx = tsx;
    }

    return status;
}