Beispiel #1
0
/// Mangelwurzel can be configured to generate originating or terminating
/// requests, and out of the blue requests. This requires manipulation of the
/// S-CSCF Route header, which will be the top Route header. Mangelwurzel
/// adds the orig parameter for originating requests, removes it for
/// terminating requests and removes the ODI token from the URI for out of
/// the blue requests.
void MangelwurzelTsx::edit_scscf_route_hdr(pjsip_msg* req, pj_pool_t* pool)
{
  pjsip_route_hdr* route_hdr =
    (pjsip_route_hdr*)pjsip_msg_find_hdr(req, PJSIP_H_ROUTE, NULL);

  if (route_hdr != NULL)
  {
    pjsip_sip_uri* scscf_uri = (pjsip_sip_uri*)route_hdr->name_addr.uri;

    pjsip_param* orig_param = pjsip_param_find(&scscf_uri->other_param,
                                               &STR_ORIG);

    if ((_config.orig) && (orig_param == NULL))
    {
      TRC_DEBUG("Add orig param to S-CSCF Route header");
      orig_param = PJ_POOL_ALLOC_T(pool, pjsip_param);
      pj_strdup(pool, &orig_param->name, &STR_ORIG);
      orig_param->value.slen = 0;
      pj_list_insert_after(&scscf_uri->other_param, orig_param);
    }
    else if ((!_config.orig) && (orig_param != NULL))
    {
      TRC_DEBUG("Remove orig param from S-CSCF Route header");
      pj_list_erase(orig_param);
    }

    // Ensure there is no ODI token by clearing the user part of the URI.
    if (_config.ootb)
    {
      TRC_DEBUG("Remove ODI token from S-CSCF Route header");
      scscf_uri->user.ptr = NULL;
      scscf_uri->user.slen = 0;
    }
  }
}
Beispiel #2
0
/*
 * Create new block.
 * Create a new big chunk of memory block, from which user allocation will be
 * taken from.
 */
static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
{
    pj_pool_block *block;

    PJ_CHECK_STACK();
    pj_assert(size >= sizeof(pj_pool_block));

    LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u", 
	 size, pool->capacity, pj_pool_get_used_size(pool)));

    /* Request memory from allocator. */
    block = (pj_pool_block*) 
	(*pool->factory->policy.block_alloc)(pool->factory, size);
    if (block == NULL) {
	(*pool->callback)(pool, size);
	return NULL;
    }

    /* Add capacity. */
    pool->capacity += size;

    /* Set start and end of buffer. */
    block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
    block->end = ((unsigned char*)block) + size;

    /* Set the start pointer, aligning it as needed */
    block->cur = ALIGN_PTR(block->buf, PJ_POOL_ALIGNMENT);

    /* Insert in the front of the list. */
    pj_list_insert_after(&pool->block_list, block);

    LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));

    return block;
}
Beispiel #3
0
/*
 * Create new memory pool.
 */
PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
				       pj_size_t initial_size, 
				       pj_size_t increment_size,
				       pj_pool_callback *callback)
{
    pj_pool_t *pool;
    pj_pool_block *block;
    pj_uint8_t *buffer;

    PJ_CHECK_STACK();

    /* Size must be at least sizeof(pj_pool)+sizeof(pj_pool_block) */
    PJ_ASSERT_RETURN(initial_size >= sizeof(pj_pool_t)+sizeof(pj_pool_block),
		     NULL);

    /* If callback is NULL, set calback from the policy */
    if (callback == NULL)
	callback = f->policy.callback;

    /* Allocate initial block */
    buffer = (pj_uint8_t*) (*f->policy.block_alloc)(f, initial_size);
    if (!buffer)
	return NULL;

    /* Set pool administrative data. */
    pool = (pj_pool_t*)buffer;
    pj_bzero(pool, sizeof(*pool));

    pj_list_init(&pool->block_list);
    pool->factory = f;

    /* Create the first block from the memory. */
    block = (pj_pool_block*) (buffer + sizeof(*pool));
    block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
    block->end = buffer + initial_size;

    /* Set the start pointer, aligning it as needed */
    block->cur = ALIGN_PTR(block->buf, PJ_POOL_ALIGNMENT);

    pj_list_insert_after(&pool->block_list, block);

    pj_pool_init_int(pool, name, increment_size, callback);

    /* Pool initial capacity and used size */
    pool->capacity = initial_size;

    LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
    return pool;
}
Beispiel #4
0
/// Calculate targets for incoming requests by querying HSS.
int ICSCFProxy::UASTsx::calculate_targets()
{
  // Invoke the router to select an S-CSCF.
  std::string scscf;
  int status_code = _router->get_scscf(scscf);

  if (status_code == PJSIP_SC_OK)
  {
    // Found a suitable S-CSCF.
    if (_case == SessionCase::REGISTER)
    {
      // REGISTER request, so add a target with this S-CSCF as the Request-URI.
      LOG_DEBUG("Route REGISTER to S-CSCF %s", scscf.c_str());
      Target* target = new Target;
      target->uri = PJUtils::uri_from_string(scscf, _req->pool);
      add_target(target);

      // Don't add a P-User-Database header - as per 5.3.1.2/TS24.229 Note 3
      // this can only be added if we have local configuration that the S-CSCF
      // can process P-User-Database.
    }
    else
    {
      // Non-register request, so add a Route header for the destination S-CSCF.
      LOG_DEBUG("Route Non-REGISTER to S-CSCF %s", scscf.c_str());
      Target* target = new Target;
      pjsip_sip_uri* route_uri =
               (pjsip_sip_uri*)PJUtils::uri_from_string(scscf, _req->pool);
      route_uri->lr_param = 1;
      if (_case == SessionCase::ORIGINATING)
      {
        // Add the "orig" parameter.
        pjsip_param* p = PJ_POOL_ALLOC_T(_req->pool, pjsip_param);
        pj_strdup(_req->pool, &p->name, &STR_ORIG);
        p->value.slen = 0;
        pj_list_insert_after(&route_uri->other_param, p);
      }
      target->paths.push_back((pjsip_uri*)route_uri);
      add_target(target);

      // Remove the P-Profile-Key header if present.
      PJUtils::remove_hdr(_req->msg, &STR_P_PROFILE_KEY);
    }
  }

  return status_code;
}
Beispiel #5
0
pj_status_t init_registrar(RegStore* registrar_store,
                           RegStore* remote_reg_store,
                           HSSConnection* hss_connection,
                           AnalyticsLogger* analytics_logger,
                           ACRFactory* rfacr_factory,
                           int cfg_max_expires)
{
  pj_status_t status;

  store = registrar_store;
  remote_store = remote_reg_store;
  hss = hss_connection;
  analytics = analytics_logger;
  max_expires = cfg_max_expires;
  acr_factory = rfacr_factory;

  // Construct a Service-Route header pointing at the S-CSCF ready to be added
  // to REGISTER 200 OK response.
  pjsip_sip_uri* service_route_uri = (pjsip_sip_uri*)
                        pjsip_parse_uri(stack_data.pool,
                                        stack_data.scscf_uri.ptr,
                                        stack_data.scscf_uri.slen,
                                        0);
  service_route_uri->lr_param = 1;

  // Add the orig parameter.  The UE must provide this back on future messages
  // to ensure we perform originating processing.
  pjsip_param *orig_param = PJ_POOL_ALLOC_T(stack_data.pool, pjsip_param);
  pj_strdup(stack_data.pool, &orig_param->name, &STR_ORIG);
  pj_strdup2(stack_data.pool, &orig_param->value, "");
  pj_list_insert_after(&service_route_uri->other_param, orig_param);

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

  status = pjsip_endpt_register_module(stack_data.endpt, &mod_registrar);
  PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

  return status;
}
Beispiel #6
0
int pjsip_p_c_f_a_hdr_print_on(void *h, char* buf, pj_size_t len)
{
  const pjsip_parser_const_t *pc = pjsip_parser_const();
  pjsip_p_c_f_a_hdr* hdr = (pjsip_p_c_f_a_hdr*)h;
  char* p = buf;

  // Check that at least the header name will fit.
  int needed = 0;
  needed += hdr->name.slen; // Header name
  needed += 2;              // : and space

  if (needed > (pj_ssize_t)len) {
    return -1;
  }

  // Now write the header name out.
  pj_memcpy(p, hdr->name.ptr, hdr->name.slen);
  p += hdr->name.slen;
  *p++ = ':';
  *p++ = ' ';

  // Now try to write out the three parameter lists.  Annoyingly,
  // pjsip_param_print_on() will always print the separator before each
  // parameter, including the first parameter in this case.
  //
  // The P-Charging-Function-Addresses header has no body (technically
  // invalid SIP) and thus we need to print the first parameter without the
  // separator.  Since this first parameter could be in any of the parameter
  // lists, we have to track (with the found_first_param flag) when we've
  // handled it.
  bool found_first_param = false;
  int printed;

  pjsip_param* param_list = NULL;
  for (int i = 0; i < 3; i++) {
    switch (i) {
      case 0:
        param_list = &hdr->ccf;
        break;
      case 1:
        param_list = &hdr->ecf;
        break;
      case 2:
        param_list = &hdr->other_param;
        break;
    }

    if (pj_list_empty(param_list)) {
      continue; // LCOV_EXCL_LINE
    }

    if (found_first_param) {
      // Simply write out the parameters
      printed = pjsip_param_print_on(param_list, p, buf+len-p,
                                     &pc->pjsip_TOKEN_SPEC,
                                     &pc->pjsip_TOKEN_SPEC, ';');
      if (printed < 0) {
        return -1;
      }
      p += printed;
    } else {
      // We print the first parameter manually then print the rest.
      pjsip_param* first_param = param_list->next;
      pj_list_erase(first_param);

      // Check we have space for the first param before printing it out.
      needed = pj_strlen(&first_param->name);
      if (first_param->value.slen) {
        needed += 1 + pj_strlen(&first_param->value);
      }
      if (needed > buf+len-p) {
        pj_list_insert_after(param_list, first_param);
        return -1;
      }

      pj_memcpy(p, first_param->name.ptr, first_param->name.slen);
      p += first_param->name.slen;
      if (first_param->value.slen) {
        *p++ = '=';
        pj_memcpy(p, first_param->value.ptr, first_param->value.slen);
        p += first_param->value.slen;
      }

      // Now print the rest of this parameter list (may be empty).
      printed = pjsip_param_print_on(param_list, p, buf+len-p,
                                     &pc->pjsip_TOKEN_SPEC,
                                     &pc->pjsip_TOKEN_SPEC, ';');
      if (printed < 0) {
        pj_list_insert_after(param_list, first_param);
        return -1;
      }
      p += printed;

      // Finally, restore the first param to the head of the parameter list.
      pj_list_insert_after(param_list, first_param);

      // We've found the first parameter, everything else is simple.
      found_first_param = true;
    }
  }

  *p = '\0';

  return p - buf;
}
Beispiel #7
0
static pj_status_t create_request(pjsip_regc *regc, 
				  pjsip_tx_data **p_tdata)
{
    pj_status_t status;
    pjsip_tx_data *tdata;

    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);

    /* Create the request. */
    status = pjsip_endpt_create_request_from_hdr( regc->endpt, 
						  pjsip_get_register_method(),
						  regc->srv_url,
						  regc->from_hdr,
						  regc->to_hdr,
						  NULL,
						  regc->cid_hdr,
						  regc->cseq_hdr->cseq,
						  NULL,
						  &tdata);
    if (status != PJ_SUCCESS)
	return status;

    /* Add cached authorization headers. */
    pjsip_auth_clt_init_req( &regc->auth_sess, tdata );

    /* Add Route headers from route set, ideally after Via header */
    if (!pj_list_empty(&regc->route_set)) {
	pjsip_hdr *route_pos;
	const pjsip_route_hdr *route;

	route_pos = (pjsip_hdr*)
		    pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
	if (!route_pos)
	    route_pos = &tdata->msg->hdr;

	route = regc->route_set.next;
	while (route != &regc->route_set) {
	    pjsip_hdr *new_hdr = (pjsip_hdr*)
				 pjsip_hdr_shallow_clone(tdata->pool, route);
	    pj_list_insert_after(route_pos, new_hdr);
	    route_pos = new_hdr;
	    route = route->next;
	}
    }

    /* Add additional request headers */
    if (!pj_list_empty(&regc->hdr_list)) {
	const pjsip_hdr *hdr;

	hdr = regc->hdr_list.next;
	while (hdr != &regc->hdr_list) {
	    pjsip_hdr *new_hdr = (pjsip_hdr*)
				 pjsip_hdr_shallow_clone(tdata->pool, hdr);
	    pjsip_msg_add_hdr(tdata->msg, new_hdr);
	    hdr = hdr->next;
	}
    }

    /* Done. */
    *p_tdata = tdata;
    return PJ_SUCCESS;
}
Beispiel #8
0
int list_test()
{
    list_node nodes[4];    // must be even number of nodes
    list_node list;
    list_node list2;
    list_node *p;
    int i; // don't change to unsigned!

    //
    // Test insert_before().
    //
    list.value = (unsigned)-1;
    pj_list_init(&list);
    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
	nodes[i].value = i;
	pj_list_insert_before(&list, &nodes[i]);
    }
    // check.
    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
	pj_assert(p->value == i);
	if (p->value != i) {
	    return -1;
	}
    }

    //
    // Test insert_after()
    //
    pj_list_init(&list);
    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) {
	pj_list_insert_after(&list, &nodes[i]);
    }
    // check.
    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
	pj_assert(p->value == i);
	if (p->value != i) {
	    return -1;
	}
    }

    //
    // Test merge_last()
    //
    // Init lists
    pj_list_init(&list);
    pj_list_init(&list2);
    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
	pj_list_insert_before(&list, &nodes[i]);
    }
    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
	pj_list_insert_before(&list2, &nodes[i]);
    }
    // merge
    pj_list_merge_last(&list, &list2);
    // check.
    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
	pj_assert(p->value == i);
	if (p->value != i) {
	    return -1;
	}
    }
    // check list is empty
    pj_assert( pj_list_empty(&list2) );
    if (!pj_list_empty(&list2)) {
	return -1;
    }

    // 
    // Check merge_first()
    //
    pj_list_init(&list);
    pj_list_init(&list2);
    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
	pj_list_insert_before(&list, &nodes[i]);
    }
    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
	pj_list_insert_before(&list2, &nodes[i]);
    }
    // merge
    pj_list_merge_first(&list2, &list);
    // check (list2).
    for (i=0, p=list2.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
	pj_assert(p->value == i);
	if (p->value != i) {
	    return -1;
	}
    }
    // check list is empty
    pj_assert( pj_list_empty(&list) );
    if (!pj_list_empty(&list)) {
	return -1;
    }

    //
    // Test insert_nodes_before()
    //
    // init list
    pj_list_init(&list);
    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
	pj_list_insert_before(&list, &nodes[i]);
    }
    // chain remaining nodes
    pj_list_init(&nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2]);
    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2+1; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
	pj_list_insert_before(&nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2], &nodes[i]);
    }
    // insert nodes
    pj_list_insert_nodes_before(&list, &nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2]);
    // check
    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
	pj_assert(p->value == i);
	if (p->value != i) {
	    return -1;
	}
    }

    // erase test.
    pj_list_init(&list);
    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
	nodes[i].value = i;
	pj_list_insert_before(&list, &nodes[i]);
    }
    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) {
	int j;
	pj_list_erase(&nodes[i]);
	for (j=0, p=list.next; j<i; ++j, p=p->next) {
	    pj_assert(p->value == j);
	    if (p->value != j) {
		return -1;
	    }
	}
    }

    // find and search
    pj_list_init(&list);
    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
	nodes[i].value = i;
	pj_list_insert_before(&list, &nodes[i]);
    }
    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
	p = (list_node*) pj_list_find_node(&list, &nodes[i]);
	pj_assert( p == &nodes[i] );
	if (p != &nodes[i]) {
	    return -1;
	}
	p = (list_node*) pj_list_search(&list, (void*)(pj_ssize_t)i, 
					&compare_node);
	pj_assert( p == &nodes[i] );
	if (p != &nodes[i]) {
	    return -1;
	}
    }
    return 0;
}
Beispiel #9
0
static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
{
    pj_caching_pool *cp = (pj_caching_pool*)pf;
    unsigned pool_capacity;
    unsigned i;

    PJ_CHECK_STACK();

    PJ_ASSERT_ON_FAIL(pf && pool, return);

    pj_lock_acquire(cp->lock);

#if PJ_SAFE_POOL
    /* Make sure pool is still in our used list */
    if (pj_list_find_node(&cp->used_list, pool) != pool) {
	pj_assert(!"Attempt to destroy pool that has been destroyed before");
	return;
    }
#endif

    /* Erase from the used list. */
    pj_list_erase(pool);

    /* Decrement used count. */
    --cp->used_count;

    pool_capacity = pj_pool_get_capacity(pool);

    /* Destroy the pool if the size is greater than our size or if the total
     * capacity in our recycle list (plus the size of the pool) exceeds 
     * maximum capacity.
   . */
    if (pool_capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||
	cp->capacity + pool_capacity > cp->max_capacity)
    {
	pj_pool_destroy_int(pool);
	pj_lock_release(cp->lock);
	return;
    }

    /* Reset pool. */
    PJ_LOG(6, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", 
	       pool_capacity, pj_pool_get_used_size(pool), 
	       pj_pool_get_used_size(pool)*100/pool_capacity));
    pj_pool_reset(pool);

    pool_capacity = pj_pool_get_capacity(pool);

    /*
     * Otherwise put the pool in our recycle list.
     */
    i = (unsigned) (unsigned long) pool->factory_data;

    pj_assert(i<PJ_CACHING_POOL_ARRAY_SIZE);
    if (i >= PJ_CACHING_POOL_ARRAY_SIZE ) {
	/* Something has gone wrong with the pool. */
	pj_pool_destroy_int(pool);
	pj_lock_release(cp->lock);
	return;
    }

    pj_list_insert_after(&cp->free_list[i], pool);
    cp->capacity += pool_capacity;

    pj_lock_release(cp->lock);
}
Beispiel #10
0
    //
    // Insert a node in the back.
    //
    void push_back(List_Node *node)
    {
	pj_list_insert_after(root_.prev, node);
    }
Beispiel #11
0
    //
    // Insert node.
    //
    void insert_after(iterator &pos, List_Node *node)
    {
	pj_list_insert_after(*pos, node);
    }
void ICSCFSproutletTsx::on_rx_response(pjsip_msg* rsp, int fork_id)
{
  if (_acr != NULL)
  {
    // Pass the received response to the ACR.
    // @TODO - timestamp from response???
    _acr->rx_response(rsp);
  }

  // Check if this response is one that we are allowed to retry the HSS lookup
  // for.  See TS 24.229 - section 5.3.2.2.
  //
  // Note we support service restoration, so integrity-protected settings in
  // Authorization header are immaterial.
  //
  // Note also that we can never retry once we've routed to the BGCF.
  pjsip_status_code rsp_status = (pjsip_status_code)rsp->line.status.code;
  const ForkState& fork_status = fork_state(fork_id);
  TRC_DEBUG("Check retry conditions for non-REGISTER, S-CSCF %sresponsive",
            (fork_status.error_state != NONE) ? "not " : "");
  if ((!_routed_to_bgcf) &&
      (fork_status.error_state != NONE))
  {
    // Indeed it it, first log to SAS.
    TRC_DEBUG("Attempt retry to alternate S-CSCF for non-REGISTER request");
    std::string st_code = std::to_string(rsp_status);
    SAS::Event event(trail(), SASEvent::SCSCF_RETRY, 0);
    std::string method = "non-REGISTER";
    event.add_var_param(method);
    event.add_var_param(st_code);
    SAS::report_event(event);

    // Now we can simply reuse the UA router we made on the initial request.
    pjsip_sip_uri* scscf_sip_uri = NULL;
    pjsip_msg* req = original_request();
    pj_pool_t* pool = get_pool(req);

    // TS 32.260 Table 5.2.1.1 says an EVENT ACR should be generated on the
    // completion of a Cx query issued in response to a SIP INVITE. It's
    // ambiguous on whether this should be sent on each Cx query completion
    // so we err on the side of over-sending events.
    bool do_billing = (rsp->line.req.method.id == PJSIP_INVITE_METHOD);
    std::string wildcard;
    int status_code = _router->get_scscf(pool,
                                         scscf_sip_uri,
                                         wildcard,
                                         do_billing);

    if (status_code == PJSIP_SC_OK)
    {
      TRC_DEBUG("Found SCSCF for non-REGISTER");

      if (_originating)
      {
        // Add the `orig` parameter.
        pjsip_param* orig_param = PJ_POOL_ALLOC_T(pool, pjsip_param);
        pj_strdup(pool, &orig_param->name, &STR_ORIG);
        orig_param->value.slen = 0;
        pj_list_insert_after(&scscf_sip_uri->other_param, orig_param);
      }

      // Add the P-Profile-Key header here if we've got a wildcard
      if (wildcard != "")
      {
        add_p_profile_header(wildcard, req);
      }

      PJUtils::add_route_header(req, scscf_sip_uri, pool);
      send_request(req);

      // We're not forwarding this response upstream.
      free_msg(rsp);
    }
    else
    {
      free_msg(req);
      send_response(rsp);
    }
  }
  else
  {
    // Provisional, successful or non-retryable response, simply forward on
    // upstream.
    send_response(rsp);
  }
}
void ICSCFSproutletTsx::on_rx_initial_request(pjsip_msg* req)
{
  pj_pool_t* pool = get_pool(req);

  pjsip_route_hdr* hroute = (pjsip_route_hdr*)
                                pjsip_msg_find_hdr(req, PJSIP_H_ROUTE, NULL);

  // TS 24.229 says I-CSCF processing shouldn't be done if a message has more than one Route header.
  // We've stripped one off in Sproutlet processing, so check for a second and just forward the
  // message if it's there.
  if (hroute != NULL)
  {
    send_request(req);
    return;
  }

  pjsip_uri* next_hop = PJUtils::next_hop(req);
  URIClass next_hop_class = URIClassifier::classify_uri(next_hop);
  if (req->line.req.method.id == PJSIP_ACK_METHOD &&
      next_hop == req->line.req.uri &&
      ((next_hop_class == NODE_LOCAL_SIP_URI) ||
       (next_hop_class == HOME_DOMAIN_SIP_URI)))
  {
    // Ignore ACK messages with no Route headers and a local Request-URI, as:
    // - the I-CSCF should not be handling these
    // - we've seen ACKs matching this descrption being generated at overload and looping repeatedly
    //
    // This is a fairly targeted fix for https://github.com/Metaswitch/sprout/issues/1091.
    // TODO: remove this code when #1091 is fixed by other means.
    free_msg(req);
    return;
  }

  // Create an ACR for this transaction.
  _acr = _icscf->get_acr(trail());
  _acr->rx_request(req);

  TRC_DEBUG("I-CSCF initialize transaction for non-REGISTER request");

  // Before we clone the request for retries, remove the P-Profile-Key header
  // if present.
  PJUtils::remove_hdr(req, &STR_P_PROFILE_KEY);

  // Determine orig/term and the served user's name.
  const pjsip_route_hdr* route = route_hdr();
  std::string impu;

  if ((route != NULL) &&
      (pjsip_param_find(&((pjsip_sip_uri*)route->name_addr.uri)->other_param,
                        &STR_ORIG) != NULL))
  {
    // Originating request.
    TRC_DEBUG("Originating request");
    _originating = true;
    impu = PJUtils::public_id_from_uri(PJUtils::orig_served_user(req));

    SAS::Event event(trail(), SASEvent::ICSCF_RCVD_ORIG_NON_REG, 0);
    event.add_var_param(impu);
    event.add_var_param(req->line.req.method.name.slen,
                        req->line.req.method.name.ptr);
    SAS::report_event(event);
  }
  else
  {
    // Terminating request.
    TRC_DEBUG("Terminating request");
    _originating = false;
    pjsip_uri* uri = PJUtils::term_served_user(req);

    // If the Req URI is a SIP URI with the user=phone parameter set, is not a
    // GRUU and the user part starts with '+' (i.e. is a global phone number),
    // we should replace it with a tel URI, as per TS24.229 5.3.2.1.
    if (PJSIP_URI_SCHEME_IS_SIP(uri))
    {
      URIClass uri_class = URIClassifier::classify_uri(uri);
      pjsip_sip_uri* sip_uri = (pjsip_sip_uri*)uri;

      if (uri_class == GLOBAL_PHONE_NUMBER)
      {
        TRC_DEBUG("Change request URI from SIP URI to tel URI");
        req->line.req.uri =
          PJUtils::translate_sip_uri_to_tel_uri(sip_uri, pool);
      }
    }

    impu = PJUtils::public_id_from_uri(PJUtils::term_served_user(req));

    SAS::Event event(trail(), SASEvent::ICSCF_RCVD_TERM_NON_REG, 0);
    event.add_var_param(impu);
    event.add_var_param(req->line.req.method.name.slen,
                        req->line.req.method.name.ptr);
    SAS::report_event(event);
  }

  // Create an LIR router to handle the HSS interactions and S-CSCF
  // selection.
  _router = (ICSCFRouter*)new ICSCFLIRouter(_icscf->get_hss_connection(),
                                            _icscf->get_scscf_selector(),
                                            trail(),
                                            _acr,
                                            _icscf->port(),
                                            impu,
                                            _originating);

  pjsip_sip_uri* scscf_sip_uri = NULL;

  // Use the router we just created to query the HSS for an S-CSCF to use.
  // TS 32.260 Table 5.2.1.1 says an EVENT ACR should be generated on the
  // completion of a Cx query issued in response to a SIP INVITE
  bool do_billing = (req->line.req.method.id == PJSIP_INVITE_METHOD);
  std::string wildcard;
  pjsip_status_code status_code =
    (pjsip_status_code)_router->get_scscf(pool,
                                          scscf_sip_uri,
                                          wildcard,
                                          do_billing);

  if ((!_originating) && (scscf_not_found(status_code)))
  {
    TRC_DEBUG("Couldn't find an S-CSCF, attempt to translate the URI");
    pjsip_uri* uri = PJUtils::term_served_user(req);
    URIClass uri_class = URIClassifier::classify_uri(uri, false);

    // For terminating processing, if the HSS indicates that the user does not
    // exist, and if the request URI is a tel URI, try an ENUM translation. If
    // this succeeds, go back to the HSS. See TS24.229, 5.3.2.1.
    //
    // Before doing that we should check whether the enforce_user_phone flag is
    // set. If it isn't, and we have a numeric SIP URI, it is possible that
    // this should have been a tel URI, so translate it and do the HSS lookup
    // again.  Once again, only do this for global numbers.
    if (PJSIP_URI_SCHEME_IS_SIP(uri) && (uri_class == GLOBAL_PHONE_NUMBER))
    {
      TRC_DEBUG("enforce_user_phone set to false, try using a tel URI");
      uri = PJUtils::translate_sip_uri_to_tel_uri((pjsip_sip_uri*)uri, pool);
      req->line.req.uri = uri;

      // We need to change the IMPU stored on our LIR router so that when
      // we do a new LIR we look up the new IMPU.
      impu = PJUtils::public_id_from_uri(PJUtils::term_served_user(req));
      ((ICSCFLIRouter *)_router)->change_impu(impu);
      status_code = (pjsip_status_code)_router->get_scscf(pool,
                                                          scscf_sip_uri,
                                                          wildcard,
                                                          do_billing);
    }

    if (_icscf->_enum_service)
    {
      // If we still haven't found an S-CSCF, we can now try an ENUM lookup.
      // We put this processing in a loop because in theory we may go round
      // several times before finding an S-CSCF. In reality this is unlikely
      // so we set MAX_ENUM_LOOKUPS to 2.
      for (int ii = 0;
           (ii < MAX_ENUM_LOOKUPS) && (scscf_not_found(status_code));
           ++ii)
      {
        if (PJSIP_URI_SCHEME_IS_TEL(uri))
        {
          // Do an ENUM lookup and see if we should translate the TEL URI
          pjsip_uri* original_req_uri = req->line.req.uri;
          _icscf->translate_request_uri(req, get_pool(req), trail());
          uri = req->line.req.uri;
          URIClass uri_class = URIClassifier::classify_uri(uri, false, true);

          std::string rn;

          if ((uri_class == NP_DATA) ||
              (uri_class == FINAL_NP_DATA))
          {
            // We got number portability information from ENUM - drop out and route to the BGCF.
            route_to_bgcf(req);
            return;
          }
          else if (pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI,
                                 original_req_uri,
                                 req->line.req.uri) != PJ_SUCCESS)
          {
            // The URI has changed, so make sure we do a LIR lookup on it.
            impu = PJUtils::public_id_from_uri(req->line.req.uri);
            ((ICSCFLIRouter *)_router)->change_impu(impu);
          }

          // If we successfully translate the req URI and end up with either another TEL URI or a
          // local SIP URI, we should look for an S-CSCF again.
          if ((uri_class == LOCAL_PHONE_NUMBER) ||
              (uri_class == GLOBAL_PHONE_NUMBER) ||
              (uri_class == HOME_DOMAIN_SIP_URI))
          {
            // TEL or local SIP URI.  Look up the S-CSCF again.
            status_code = (pjsip_status_code)_router->get_scscf(pool,
                                                                scscf_sip_uri,
                                                                wildcard,
                                                                do_billing);
          }
          else
          {
            // Number translated to off-switch.  Drop out of the loop.
            ii = MAX_ENUM_LOOKUPS;
          }
        }
        else
        {
          // Can't translate the number, skip to the end of the loop.
          ii = MAX_ENUM_LOOKUPS;
        }
      }
    }
    else
    {
      // The user is not in the HSS and ENUM is not configured. TS 24.229
      // says that, as an alternative to ENUM, we can "forward the request to
      // the transit functionality for subsequent routeing". Let's do that
      // (currently, we assume the BGCF is the transit functionality, but that
      // may be made configurable in future).
      TRC_DEBUG("No ENUM service available - outing request directly to transit function (BGCF)");
      route_to_bgcf(req);
      return;
    }
  }

  URIClass uri_class = URIClassifier::classify_uri(req->line.req.uri);
  if (status_code == PJSIP_SC_OK)
  {
    TRC_DEBUG("Found SCSCF for non-REGISTER");

    if (_originating)
    {
      // Add the `orig` parameter.
      pjsip_param* orig_param = PJ_POOL_ALLOC_T(get_pool(req), pjsip_param);
      pj_strdup(get_pool(req), &orig_param->name, &STR_ORIG);
      orig_param->value.slen = 0;
      pj_list_insert_after(&scscf_sip_uri->other_param, orig_param);
    }

    // Add the P-Profile-Key header here if we've got a wildcard
    if (wildcard != "")
    {
      add_p_profile_header(wildcard, req);
    }

    PJUtils::add_route_header(req, scscf_sip_uri, get_pool(req));
    send_request(req);
  }
  else if ((uri_class == OFFNET_SIP_URI) ||
           (uri_class == GLOBAL_PHONE_NUMBER))
  {
    // Target is a TEL URI or not in our home domain.  Pass to the BGCF.
    route_to_bgcf(req);
  }
  else
  {
    // Target is in our home domain, but we failed to find an S-CSCF. This is the final response.
    pjsip_msg* rsp = create_response(req, status_code);
    send_response(rsp);
    free_msg(req);
  }
}
Beispiel #14
0
static pj_status_t create_request(pjsip_publishc *pubc, 
				  pjsip_tx_data **p_tdata)
{
    const pj_str_t STR_EVENT = { "Event", 5 };
    pj_status_t status;
    pjsip_generic_string_hdr *hdr;
    pjsip_tx_data *tdata;

    PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);

    /* Create the request. */
    status = pjsip_endpt_create_request_from_hdr( pubc->endpt, 
						  &pjsip_publish_method,
						  pubc->target_uri,
						  pubc->from_hdr,
						  pubc->to_hdr,
						  NULL,
						  pubc->cid_hdr,
						  pubc->cseq_hdr->cseq,
						  NULL,
						  &tdata);
    if (status != PJ_SUCCESS)
	return status;

    /* Add cached authorization headers. */
    pjsip_auth_clt_init_req( &pubc->auth_sess, tdata );

    /* Add Route headers from route set, ideally after Via header */
    if (!pj_list_empty(&pubc->route_set)) {
	pjsip_hdr *route_pos;
	const pjsip_route_hdr *route;

	route_pos = (pjsip_hdr*)
		    pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
	if (!route_pos)
	    route_pos = &tdata->msg->hdr;

	route = pubc->route_set.next;
	while (route != &pubc->route_set) {
	    pjsip_hdr *new_hdr = (pjsip_hdr*)
	    			 pjsip_hdr_shallow_clone(tdata->pool, route);
	    pj_list_insert_after(route_pos, new_hdr);
	    route_pos = new_hdr;
	    route = route->next;
	}
    }

    /* Add Event header */
    hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT,
					  &pubc->event);
    if (hdr)
	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);


    /* Add SIP-If-Match if we have etag */
    if (pubc->etag.slen) {
	const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };

	hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME,
					      &pubc->etag);
	if (hdr)
	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
    }


    /* Done. */
    *p_tdata = tdata;
    return PJ_SUCCESS;
}
static pj_status_t lb_put_frame( pjmedia_port *this_port,
				 const pjmedia_frame *frame)
{
    pj_status_t status;
    struct leaky_bucket_port *lb = (struct leaky_bucket_port*)this_port;
    struct leaky_bucket_item *item = PJ_POOL_ZALLOC_T(lb->pool,
            struct leaky_bucket_item);
    PJ_ASSERT_RETURN(this_port->info.signature == SIGNATURE, PJ_EINVAL);
    pj_memcpy(&item->frame, frame, sizeof(pjmedia_frame));
    PJ_LOG(6, (THIS_FILE, "packet: sz=%d ts=%llu",
                frame->size/sizeof(pj_uint16_t), frame->timestamp.u64));

    /* if frame is not empty, push all previous frames into downstream port  */
    if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO){
        status = lb_push_frames_till(lb, frame->timestamp);
        if (status != PJ_SUCCESS) return status;
    }
    /* update bucket and received packet states */
    if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO ) {
        if (lb->bucket_size > lb->items){
            void *buf;
            unsigned sent_delay;
            if (lb->sent_delay) { /* sent delay or pps is set */
                sent_delay = lb->sent_delay;
            } else { /* bps is set, compute sent delay on the fly */
                int hdr_sz = 20 + 8 + 12;
                sent_delay = 8.0 * (hdr_sz + frame->size) * \
                    lb->base.info.clock_rate / lb->bits_per_second;
                PJ_LOG(6, (THIS_FILE, "Sent delay: %u. Pack sz: %u. Samples: %u",
                            sent_delay, frame->size, lb->base.info.samples_per_frame));
            }
            /* update timestamps */
            if (lb->frames == 0){
                lb->last_ts = item->frame.timestamp;
            } else if ( lb->last_ts.u64 + sent_delay < item->frame.timestamp.u64  ) {
                lb->last_ts = item->frame.timestamp;
            } else {
                lb->last_ts.u64 += sent_delay;
                item->frame.timestamp = lb->last_ts;
            }
            buf = pj_pool_zalloc(lb->pool, frame->size);
            pj_memcpy(buf, frame->buf, frame->size);
            item->frame.buf = buf;
            PJ_LOG(6, (THIS_FILE, "packet in buf: sz=%d ts=%llu",
                item->frame.size/sizeof(pj_uint16_t), item->frame.timestamp.u64));
            lb->items++;
        } else {
            pj_bzero(item, sizeof(*item));
            item->frame.type = PJMEDIA_FRAME_TYPE_NONE;
            PJ_LOG(6, (THIS_FILE, "bucket size %u exhausted, packet dropped",
                lb->bucket_size));
        }
    } else {
        PJ_LOG(6, (THIS_FILE, "received empty frame"));
    }
    /* put frame at the end of list or init an empty one */
    if (lb->last_item == NULL){
        pj_list_init(item);
        lb->first_item = lb->last_item = item;
    } else {
        pj_list_insert_after(lb->last_item, item);
        lb->last_item = item;
    }
    lb->frames++;
    return PJ_SUCCESS;
}
/**
  * @isFirstPacket first packet in a frame
  * @isMarketPacket last packet in a frame
  */
PJ_DEF(int) jitter_buffer_insert_packet(Jitter_Buffer *jitter_buffer, 
pj_uint16_t seq, pj_uint32_t ts, pjmedia_frame_type frame_type, 
char *payload, int size, 
pj_bool_t isFirstPacket, pj_bool_t isMarketPacket) {
    int ret = 0;
    if(pj_mutex_lock(jitter_buffer->jb_mutex) != PJ_SUCCESS) {
        return -1;
    }
    pj_ssize_t current;
    JTPacket *packet = NULL;
    Frame_Buffer *frame;
    // is running
    if(!jitter_buffer->running) {
        ret = -2;
        goto ON_RET;
    }
    // sanity check
    if(ts == 0 || (frame_type != PJMEDIA_FRAME_TYPE_EMPTY && size == 0)) {
        ret = -3;
        goto ON_RET;
    }
    if(!jitter_buffer->first_packet) {
        isFirstPacket = PJ_TRUE;
        jitter_buffer->first_packet = PJ_TRUE;
    }
    //clean old frames
    //CleanOldFrames(jitter_buffer);
    //update jitter
    current = GetCurrentTimeMs();
    if(frame_type != PJMEDIA_FRAME_TYPE_EMPTY && frame_type != PJMEDIA_FRAME_TYPE_NONE) {
        if(jitter_buffer->waiting_for_completed_frame.timestamp == ts) {
            jitter_buffer->waiting_for_completed_frame.frame_size += size;
            jitter_buffer->waiting_for_completed_frame.latest_packet_timestamp = current;
        } else if(jitter_buffer->waiting_for_completed_frame.latest_packet_timestamp > 0 && 
            current - jitter_buffer->waiting_for_completed_frame.latest_packet_timestamp  > 2000) {
                //too old
                UpdateJitterEstimatorForWaitingFrame(jitter_buffer, &jitter_buffer->waiting_for_completed_frame);
                jitter_buffer->waiting_for_completed_frame.frame_size = 0;
                jitter_buffer->waiting_for_completed_frame.latest_packet_timestamp = -1;
                jitter_buffer->waiting_for_completed_frame.timestamp = 0;
        }
    }
    //create packet
    packet = NULL;
    if(jt_packet_create(&packet, &jitter_buffer->packet_alloc, seq, ts, frame_type, 
                    isFirstPacket, isMarketPacket, payload, size) != 0) {
        if(packet)
            list_alloc_insert(packet, &jitter_buffer->packet_alloc);
        ret = -1;
        goto ON_RET;
    }
    //GetCurrentTimeInLocal(packet->time_in_jb, 60);
    if(!isFirstPacket) {
        //is first packet in frame
        isFirstPacket = first_packet_in_frame(jitter_buffer, packet);
        packet->isFirst = isFirstPacket;
    }
    if(isMarketPacket) {
        //check if next packet is first packet
        Frame_Buffer *next_frame = findFrame(&jitter_buffer->frameList, packet->ts, '>');
        if(next_frame != NULL) {
            JTPacket * first_packet = next_frame->session_info.packetList.next;
            if(packet != &next_frame->session_info.packetList) {
                if(InSequence(packet->seq, first_packet->seq)) {
                    first_packet->isFirst = PJ_TRUE;
                }
            }
        }
    }
    //clean old frames
    CleanOldFrames(jitter_buffer);   
    // is old packet 
    if(decode_state_isOldPacket(packet, &jitter_buffer->decode_state)) {
            decode_state_updateOldPacket(packet, &jitter_buffer->decode_state);
            list_alloc_insert(packet, &jitter_buffer->packet_alloc);
            ret = -1;
            goto ON_RET;
    }
    
    // find or alloc a frame
    frame = findFrame(&jitter_buffer->frameList, packet->ts, '=');
    if(frame == NULL) { //alloc one
        //if(jitter_buffer->number_of_frames > jitter_buffer->max_number_of_frames) {
        if(jitter_buffer->number_of_frames > jitter_buffer->max_number_of_frames) {
            //clean old frames at least one
            Frame_Buffer *oldestFrame = jitter_buffer->frameList.next;
            if(oldestFrame != &jitter_buffer->frameList)
                RealseFrame(jitter_buffer, oldestFrame);
        }
        list_alloc_alloc(Frame_Buffer, &frame, &jitter_buffer->frame_alloc);
        //init
        frame_buffer_init(frame, &jitter_buffer->packet_alloc);
    }
    //insert packet into the frame
    ret = frame_buffer_insert_packet(frame, packet);
    if(ret > 0) {
        list_alloc_insert(packet, &jitter_buffer->packet_alloc);
        frame_buffer_reset(frame);
        list_alloc_insert(frame, &jitter_buffer->frame_alloc);
        ret = -1;
        goto ON_RET;
    } else if (ret < 0) {
        frame_buffer_reset(frame);
        list_alloc_insert(frame, &jitter_buffer->frame_alloc);
        ret = -1;
        goto ON_RET;
    } else {
        event_set(jitter_buffer->packet_event);
        if(packet->isRetrans)
            frame_buffer_IncrementNackCount(frame);
    }
    
    //insert frame to frame list
    if(findFrame(&jitter_buffer->frameList, frame->ts, '=') == NULL) {
        Frame_Buffer *prev_frame = findFrame(&jitter_buffer->frameList, frame->ts, '<');
        prev_frame = (prev_frame == NULL ? &jitter_buffer->frameList : prev_frame);
        pj_list_insert_after(prev_frame, frame);
        event_set(jitter_buffer->frame_event);
        jitter_buffer->number_of_frames++;
    }
    ON_RET:
    pj_mutex_unlock(jitter_buffer->jb_mutex);
    return ret;
    
}