/*
 * Initialize server authorization session data structure to serve the 
 * specified realm and to use lookup_func function to look for the credential 
 * info. 
 */
PJ_DEF(pj_status_t) pjsip_auth_srv_init(  pj_pool_t *pool,
					  pjsip_auth_srv *auth_srv,
					  const pj_str_t *realm,
					  pjsip_auth_lookup_cred *lookup,
					  unsigned options )
{
    PJ_ASSERT_RETURN(pool && auth_srv && realm && lookup, PJ_EINVAL);

    pj_bzero(auth_srv, sizeof(*auth_srv));
    pj_strdup( pool, &auth_srv->realm, realm);
    auth_srv->lookup = lookup;
    auth_srv->is_proxy = (options & PJSIP_AUTH_SRV_IS_PROXY);

    return PJ_SUCCESS;
}
Exemple #2
0
/* Duplicate credential */
PJ_DEF(void) pj_stun_auth_cred_dup( pj_pool_t *pool,
				      pj_stun_auth_cred *dst,
				      const pj_stun_auth_cred *src)
{
    dst->type = src->type;

    switch (src->type) {
    case PJ_STUN_AUTH_CRED_STATIC:
	pj_strdup(pool, &dst->data.static_cred.realm,
			&src->data.static_cred.realm);
	pj_strdup(pool, &dst->data.static_cred.username,
			&src->data.static_cred.username);
	dst->data.static_cred.data_type = src->data.static_cred.data_type;
	pj_strdup(pool, &dst->data.static_cred.data,
			&src->data.static_cred.data);
	pj_strdup(pool, &dst->data.static_cred.nonce,
			&src->data.static_cred.nonce);
	break;
    case PJ_STUN_AUTH_CRED_DYNAMIC:
	pj_memcpy(&dst->data.dyn_cred, &src->data.dyn_cred, 
		  sizeof(src->data.dyn_cred));
	break;
    }
}
/*
 * Create NOTIFY
 */
PJ_DEF(pj_status_t) pjsip_mwi_notify(  pjsip_evsub *sub,
				       pjsip_evsub_state state,
				       const pj_str_t *state_str,
				       const pj_str_t *reason,
				       const pjsip_media_type *mime_type,
				       const pj_str_t *body,
				       pjsip_tx_data **p_tdata)
{
    pjsip_mwi *mwi;
    pjsip_tx_data *tdata;
    pj_status_t status;
    
    /* Check arguments. */
    PJ_ASSERT_RETURN(sub && mime_type && body && p_tdata, PJ_EINVAL);

    /* Get the mwi object. */
    mwi = (pjsip_mwi*) pjsip_evsub_get_mod_data(sub, mod_mwi.id);
    PJ_ASSERT_RETURN(mwi != NULL, PJ_EINVALIDOP);

    /* Lock object. */
    pjsip_dlg_inc_lock(mwi->dlg);

    /* Create the NOTIFY request. */
    status = pjsip_evsub_notify( sub, state, state_str, reason, &tdata);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Update the cached message body */
    if (mime_type || body)
	pj_pool_reset(mwi->body_pool);
    if (mime_type)
	pjsip_media_type_cp(mwi->body_pool, &mwi->mime_type, mime_type);
    if (body)
	pj_strdup(mwi->body_pool, &mwi->body, body);

    /* Create message body */
    status = mwi_create_msg_body( mwi, tdata );
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Done. */
    *p_tdata = tdata;

on_return:
    pjsip_dlg_dec_lock(mwi->dlg);
    return status;
}
Exemple #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;
}
int LLVMFuzzerInitialize(int* /*argc*/, char*** argv)
{
    const char* argv0 = (*argv)[0];
    char* path = pj_strdup(argv0);
    char* lastslash = strrchr(path, '/');
    if( lastslash )
    {
        *lastslash = '\0';
        setenv("PROJ_LIB", path, 1);
    }
    else
    {
        setenv("PROJ_LIB", ".", 1);
    }
    free(path);
    return 0;
}
Exemple #6
0
/**
 * Create a "blank" SDP session description. The SDP will contain basic SDP
 * fields such as origin, time, and name, but without any media lines.
 */
PJ_DEF(pj_status_t) pjmedia_endpt_create_base_sdp( pjmedia_endpt *endpt,
						   pj_pool_t *pool,
						   const pj_str_t *sess_name,
						   const pj_sockaddr *origin,
						   pjmedia_sdp_session **p_sdp)
{
    char tmp_addr[PJ_INET6_ADDRSTRLEN];
    pj_time_val tv;
    pjmedia_sdp_session *sdp;

    /* Sanity check arguments */
    PJ_ASSERT_RETURN(endpt && pool && p_sdp, PJ_EINVAL);

    sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);

    pj_gettimeofday(&tv);
    sdp->origin.user = pj_str("-");
    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
    sdp->origin.net_type = STR_IN;

    if (origin->addr.sa_family == pj_AF_INET()) {
 	sdp->origin.addr_type = STR_IP4;
    } else if (origin->addr.sa_family == pj_AF_INET6()) {
 	sdp->origin.addr_type = STR_IP6;
    } else {
 	pj_assert(!"Invalid address family");
 	return PJ_EAFNOTSUP;
    }

    pj_strdup2(pool, &sdp->origin.addr,
 	       pj_sockaddr_print(origin, tmp_addr, sizeof(tmp_addr), 0));

    if (sess_name)
	pj_strdup(pool, &sdp->name, sess_name);
    else
	sdp->name = STR_SDP_NAME;

    /* SDP time and attributes. */
    sdp->time.start = sdp->time.stop = 0;
    sdp->attr_count = 0;

    /* Done */
    *p_sdp = sdp;

    return PJ_SUCCESS;
}
Exemple #7
0
PJ_DEF(pj_status_t) pjsip_regc_set_via_sent_by( pjsip_regc *regc,
				                pjsip_host_port *via_addr,
                                                pjsip_transport *via_tp)
{
    PJ_ASSERT_RETURN(regc, PJ_EINVAL);

    if (!via_addr)
        pj_bzero(&regc->via_addr, sizeof(regc->via_addr));
    else {
        if (pj_strcmp(&regc->via_addr.host, &via_addr->host))
            pj_strdup(regc->pool, &regc->via_addr.host, &via_addr->host);
        regc->via_addr.port = via_addr->port;
    }
    regc->via_tp = via_tp;

    return PJ_SUCCESS;
}
Exemple #8
0
PJ_DEF(void) pjsip_sip_uri_assign(pj_pool_t *pool, pjsip_sip_uri *url,
                                  const pjsip_sip_uri *rhs)
{
    pj_strdup( pool, &url->user, &rhs->user);
    pj_strdup( pool, &url->passwd, &rhs->passwd);
    pj_strdup( pool, &url->host, &rhs->host);
    url->port = rhs->port;
    pj_strdup( pool, &url->user_param, &rhs->user_param);
    pj_strdup( pool, &url->method_param, &rhs->method_param);
    pj_strdup( pool, &url->transport_param, &rhs->transport_param);
    url->ttl_param = rhs->ttl_param;
    pj_strdup( pool, &url->maddr_param, &rhs->maddr_param);
    pjsip_param_clone(pool, &url->other_param, &rhs->other_param);
    pjsip_param_clone(pool, &url->header_param, &rhs->header_param);
    url->lr_param = rhs->lr_param;
}
Exemple #9
0
/* Get <note> element from PIDF <tuple> element */
static pj_status_t get_tuple_note(const pjpidf_pres *pres,
				  pj_pool_t *pool,
				  pjrpid_element *elem)
{
    const pj_xml_node *nd_tuple, *nd_note;

    nd_tuple = find_node(pres, "tuple");
    if (!nd_tuple)
	return PJSIP_SIMPLE_EBADRPID;

    nd_note = find_node(pres, "note");
    if (nd_note) {
	pj_strdup(pool, &elem->note, &nd_note->content);
	return PJ_SUCCESS;
    }

    return PJSIP_SIMPLE_EBADRPID;
}
Exemple #10
0
PJ_DEF(pj_status_t) pjxpidf_set_uri(pj_pool_t *pool, pjxpidf_pres *pres, 
				    const pj_str_t *uri)
{
    pj_xml_node *presentity;
    pj_xml_node *atom;
    pj_xml_node *addr;
    pj_xml_attr *attr;
    pj_str_t dup_uri;

    presentity = pj_xml_find_node(pres, &STR_PRESENTITY);
    if (!presentity) {
	pj_assert(0);
	return -1;
    }
    atom = pj_xml_find_node(pres, &STR_ATOM);
    if (!atom) {
	pj_assert(0);
	return -1;
    }
    addr = pj_xml_find_node(atom, &STR_ADDRESS);
    if (!addr) {
	pj_assert(0);
	return -1;
    }

    /* Set uri in presentity */
    attr = pj_xml_find_attr(presentity, &STR_URI, NULL);
    if (!attr) {
	pj_assert(0);
	return -1;
    }
    pj_strdup(pool, &dup_uri, uri);
    attr->value = dup_uri;

    /* Set uri in address. */
    attr = pj_xml_find_attr(addr, &STR_URI, NULL);
    if (!attr) {
	pj_assert(0);
	return -1;
    }
    attr->value = dup_uri;

    return 0;
}
Exemple #11
0
/*
 * Add authentication challenge headers to the outgoing response in tdata. 
 * Application may specify its customized nonce and opaque for the challenge, 
 * or can leave the value to NULL to make the function fills them in with 
 * random characters.
 */
PJ_DEF(pj_status_t) pjsip_auth_srv_challenge(  pjsip_auth_srv *auth_srv,
					       const pj_str_t *qop,
					       const pj_str_t *nonce,
					       const pj_str_t *opaque,
					       pj_bool_t stale,
					       pjsip_tx_data *tdata)
{
    pjsip_www_authenticate_hdr *hdr;
    char nonce_buf[16];
    pj_str_t random;

    PJ_ASSERT_RETURN( auth_srv && tdata, PJ_EINVAL );

    random.ptr = nonce_buf;
    random.slen = sizeof(nonce_buf);

    /* Create the header. */
    if (auth_srv->is_proxy)
	hdr = pjsip_proxy_authenticate_hdr_create(tdata->pool);
    else
	hdr = pjsip_www_authenticate_hdr_create(tdata->pool);

    /* Initialize header. 
     * Note: only support digest authentication now.
     */
    hdr->scheme = pjsip_DIGEST_STR;
    hdr->challenge.digest.algorithm = pjsip_MD5_STR;
    if (nonce) {
	pj_strdup(tdata->pool, &hdr->challenge.digest.nonce, nonce);
    } else {
	pj_create_random_string(nonce_buf, sizeof(nonce_buf));
	pj_strdup(tdata->pool, &hdr->challenge.digest.nonce, &random);
    }
    if (opaque) {
	pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, opaque);
    } else {
	pj_create_random_string(nonce_buf, sizeof(nonce_buf));
	pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, &random);
    }
    if (qop) {
	pj_strdup(tdata->pool, &hdr->challenge.digest.qop, qop);
    } else {
	hdr->challenge.digest.qop.slen = 0;
    }
    pj_strdup(tdata->pool, &hdr->challenge.digest.realm, &auth_srv->realm);
    hdr->challenge.digest.stale = stale;

    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);

    return PJ_SUCCESS;
}
Exemple #12
0
/* Add command to the command hash */
static void add_cmd_name(pj_cli_t *cli, pj_cli_cmd_spec *group, 
			 pj_cli_cmd_spec *cmd, pj_str_t *cmd_name)
{
    pj_str_t cmd_val;
    pj_str_t add_cmd;
    char cmd_ptr[64];

    cmd_val.ptr = &cmd_ptr[0];
    cmd_val.slen = 0;

    if (group) {
	pj_strcat(&cmd_val, &group->name);
    }
    pj_strcat(&cmd_val, cmd_name);
    pj_strdup(cli->pool, &add_cmd, &cmd_val);
    
    pj_hash_set(cli->pool, cli->cmd_name_hash, 
		cmd_val.ptr, cmd_val.slen, 0, cmd);
}
Exemple #13
0
PJ_DEF(void) pjpidf_tuple_set_contact_prio(pj_pool_t *pool, pjpidf_tuple *t, 
					   const pj_str_t *prio)
{
    pj_xml_node *node = pj_xml_find_node(t, &CONTACT);
    pj_xml_attr *attr;

    if (!node) {
	node = PJ_POOL_ALLOC_T(pool, pj_xml_node);
	xml_init_node(pool, node, &CONTACT, NULL);
	pj_xml_add_node(t, node);
    }
    attr = pj_xml_find_attr(node, &PRIORITY, NULL);
    if (!attr) {
	attr = xml_create_attr(pool, &PRIORITY, prio);
	pj_xml_add_attr(node, attr);
    } else {
	pj_strdup(pool, &attr->value, prio);
    }
}
Exemple #14
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;
}
Exemple #15
0
/* Test transaction layer. */
static int tsx_layer_test(void)
{
    pj_str_t target, from, tsx_key;
    pjsip_tx_data *tdata;
    pjsip_transaction *tsx, *found;
    pj_status_t status;

    PJ_LOG(3,(THIS_FILE, "  transaction layer test"));

    target = pj_str(TARGET_URI);
    from = pj_str(FROM_URI);

    status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target,
					&from, &target, NULL, NULL, -1, NULL,
					&tdata);
    if (status != PJ_SUCCESS) {
	app_perror("  error: unable to create request", status);
	return -110;
    }

    status = pjsip_tsx_create_uac(NULL, tdata, &tsx);
    if (status != PJ_SUCCESS) {
	app_perror("   error: unable to create transaction", status);
	return -120;
    }

    pj_strdup(tdata->pool, &tsx_key, &tsx->transaction_key);

    found = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE);
    if (found != tsx) {
	return -130;
    }

    pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
    flush_events(500);

    if (pjsip_tx_data_dec_ref(tdata) != PJSIP_EBUFDESTROYED) {
	return -140;
    }

    return 0;
}
Exemple #16
0
PJ_DECL(void) pjdialog_info_local_set_identity_display(pj_pool_t *pool,
                            pjdialog_info_local *local,
                            const pj_str_t *identity_display)
{
    pj_xml_node *node = pj_xml_find_node((pj_xml_node*)local, &IDENTITY);
    pj_xml_attr *attr;

    if (!node) {
        node = PJ_POOL_ALLOC_T(pool, pj_xml_node);
        xml_init_node(pool, node, &IDENTITY, NULL);
        pj_xml_add_node(local, node);
    }
    attr = pj_xml_find_attr(node, &DISPLAY, NULL);
    if (!attr) {
        attr = xml_create_attr(pool, &DISPLAY, identity_display);
        pj_xml_add_attr(node, attr);
    } else {
        pj_strdup(pool, &attr->value, identity_display);
    }
}
Exemple #17
0
PJ_DECL(void) pjdialog_info_local_set_target_uri(pj_pool_t *pool,
                            pjdialog_info_local *local,
                            const pj_str_t * target_uri)
{
    pj_xml_node *node = pj_xml_find_node((pj_xml_node*)local, &TARGET);
    pj_xml_attr *attr;

    if (!node) {
        node = PJ_POOL_ALLOC_T(pool, pj_xml_node);
        xml_init_node(pool, node, &TARGET, NULL);
        pj_xml_add_node(local, node);
    }
    attr = pj_xml_find_attr(node, &URI, NULL);
    if (!attr) {
        attr = xml_create_attr(pool, &URI, target_uri);
        pj_xml_add_attr(node, attr);
    } else {
        pj_strdup(pool, &attr->value, target_uri);
    }
}
PJ_DEF(pj_status_t) pjsip_pres_parse_xpidf2(char *body, unsigned body_len,
					    pj_pool_t *pool,
					    pjsip_pres_status *pres_status)
{
    pjxpidf_pres *xpidf;

    xpidf = pjxpidf_parse(pool, body, body_len);
    if (xpidf == NULL)
	return PJSIP_SIMPLE_EBADXPIDF;

    pres_status->info_cnt = 1;
    
    pj_strdup(pool,
	      &pres_status->info[0].contact,
	      pjxpidf_get_uri(xpidf));
    pres_status->info[0].basic_open = pjxpidf_get_status(xpidf);
    pres_status->info[0].id.slen = 0;
    pres_status->info[0].tuple_node = NULL;

    return PJ_SUCCESS;
}
Exemple #19
0
/* Add command to the command hash */
static void add_cmd_name(pj_cli_t *cli, pj_cli_cmd_spec *group, 
			 pj_cli_cmd_spec *cmd, pj_str_t *cmd_name)
{
    pj_str_t cmd_val;
    pj_str_t add_cmd;
    char cmd_ptr[MAX_CMD_HASH_NAME_LENGTH];

    cmd_val.ptr = cmd_ptr;
    cmd_val.slen = 0;

    if (group) {
	char cmd_str[MAX_CMD_ID_LENGTH];
	pj_ansi_sprintf(cmd_str, "%d", group->id);
	pj_strcat2(&cmd_val, cmd_str);	
    }
    pj_strcat(&cmd_val, cmd_name);
    pj_strdup(cli->pool, &add_cmd, &cmd_val);
    
    pj_hash_set(cli->pool, cli->cmd_name_hash, cmd_val.ptr, 
		(unsigned)cmd_val.slen, 0, cmd);
}
Exemple #20
0
/* Schedule timer to send response for the specified UAS transaction */
static void schedule_send_response( pjsip_rx_data *rdata,
				    const pj_str_t *tsx_key,
				    int status_code,
				    int msec_delay )
{
    pj_status_t status;
    pjsip_tx_data *tdata;
    pj_timer_entry *t;
    struct response *r;
    pj_time_val delay;

    status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL, 
					  &tdata);
    if (status != PJ_SUCCESS) {
	app_perror("    error: unable to create response", status);
	test_complete = -198;
	return;
    }

    r = PJ_POOL_ALLOC_T(tdata->pool, struct response);
    pj_strdup(tdata->pool, &r->tsx_key, tsx_key);
    r->tdata = tdata;

    delay.sec = 0;
    delay.msec = msec_delay;
    pj_time_val_normalize(&delay);

    t = PJ_POOL_ZALLOC_T(tdata->pool, pj_timer_entry);
    t->user_data = r;
    t->cb = &send_response_timer;

    status = pjsip_endpt_schedule_timer(endpt, t, &delay);
    if (status != PJ_SUCCESS) {
	pjsip_tx_data_dec_ref(tdata);
	app_perror("    error: unable to schedule timer", status);
	test_complete = -199;
	return;
    }
}
Exemple #21
0
/*
 * This is a utility function to parse X-PIDF body into PJSIP presence status.
 */
PJ_DEF(pj_status_t) pjsip_pres_parse_xpidf(pjsip_rx_data *rdata,
					   pj_pool_t *pool,
					   pjsip_pres_status *pres_status)
{
    pjxpidf_pres *xpidf;

    xpidf = pjxpidf_parse(rdata->tp_info.pool, 
			  (char*)rdata->msg_info.msg->body->data,
			  rdata->msg_info.msg->body->len);
    if (xpidf == NULL)
	return PJSIP_SIMPLE_EBADXPIDF;

    pres_status->info_cnt = 1;
    
    pj_strdup(pool,
	      &pres_status->info[0].contact,
	      pjxpidf_get_uri(xpidf));
    pres_status->info[0].basic_open = pjxpidf_get_status(xpidf);
    pres_status->info[0].id.slen = 0;

    return PJ_SUCCESS;
}
Exemple #22
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;
}
/*!
 * \internal
 * \brief Adds diversion header information to an outbound SIP message
 *
 * \param tdata The outbound message
 * \param data The redirecting data used to fill parts of the diversion header
 */
static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
{
	pjsip_fromto_hdr *hdr;
	pjsip_name_addr *name_addr;
	pjsip_sip_uri *uri;
	pjsip_param *param;
	pjsip_fromto_hdr *old_hdr;

	struct ast_party_id *id = &data->from;
	pjsip_uri *base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;

	if (!id->number.valid || ast_strlen_zero(id->number.str)) {
		return;
	}

	hdr = pjsip_from_hdr_create(tdata->pool);
	hdr->type = PJSIP_H_OTHER;
	pj_strdup(tdata->pool, &hdr->name, &diversion_name);
	hdr->sname.slen = 0;

	name_addr = pjsip_uri_clone(tdata->pool, base);
	uri = pjsip_uri_get_uri(name_addr->uri);

	pj_strdup2(tdata->pool, &name_addr->display, id->name.str);
	pj_strdup2(tdata->pool, &uri->user, id->number.str);

	param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
	param->name = pj_str("reason");
	param->value = pj_str((char*)reason_code_to_str(&data->reason));
	pj_list_insert_before(&hdr->other_param, param);

	hdr->uri = (pjsip_uri *) name_addr;
	old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &diversion_name, NULL);
	if (old_hdr) {
		pj_list_erase(old_hdr);
	}
	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
}
/*
 * Create message body and attach it to the (NOTIFY) request.
 */
static pj_status_t mwi_create_msg_body( pjsip_mwi *mwi, 
					pjsip_tx_data *tdata)
{
    pjsip_msg_body *body;
    pj_str_t dup_text;

    PJ_ASSERT_RETURN(mwi->mime_type.type.slen && mwi->body.slen, PJ_EINVALIDOP);
    
    /* Clone the message body and mime type */
    pj_strdup(tdata->pool, &dup_text, &mwi->body);

    /* Create the message body */
    body = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_msg_body);
    pjsip_media_type_cp(tdata->pool, &body->content_type, &mwi->mime_type);
    body->data = dup_text.ptr;
    body->len = (unsigned)dup_text.slen;
    body->print_body = &pjsip_print_text_body;
    body->clone_data = &pjsip_clone_text_data;

    /* Attach to tdata */
    tdata->msg->body = body;

    return PJ_SUCCESS;
}
Exemple #25
0
/*
 * Create relay.
 */
static pj_status_t create_relay(pj_turn_srv *srv,
				pj_turn_allocation *alloc,
				const pj_stun_msg *msg,
				const alloc_request *req,
				pj_turn_relay_res *relay)
{
    enum { RETRY = 40 };
    pj_pool_t *pool = alloc->pool;
    int retry, retry_max, sock_type;
    pj_ioqueue_callback icb;
    int af, namelen;
    pj_stun_string_attr *sa;
    pj_status_t status;

    pj_bzero(relay, sizeof(*relay));

    relay->allocation = alloc;
    relay->tp.sock = PJ_INVALID_SOCKET;

    /* TODO: get the requested address family from somewhere */
    af = alloc->transport->listener->addr.addr.sa_family;

    /* Save realm */
    sa = (pj_stun_string_attr*)
	 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0);
    PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
    pj_strdup(pool, &relay->realm, &sa->value);

    /* Save username */
    sa = (pj_stun_string_attr*)
	 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
    PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
    pj_strdup(pool, &relay->user, &sa->value);

    /* Lifetime and timeout */
    relay->lifetime = req->lifetime;
    pj_timer_entry_init(&relay->timer, TIMER_ID_NONE, relay,
			&relay_timeout_cb);
    resched_timeout(alloc);

    /* Transport type */
    relay->hkey.tp_type = req->tp_type;

    /* Create the socket */
    if (req->tp_type == PJ_TURN_TP_UDP) {
	sock_type = pj_SOCK_DGRAM();
    } else if (req->tp_type == PJ_TURN_TP_TCP) {
	sock_type = pj_SOCK_STREAM();
    } else {
	pj_assert(!"Unknown transport");
	return PJ_EINVALIDOP;
    }

    status = pj_sock_socket(af, sock_type, 0, &relay->tp.sock);
    if (status != PJ_SUCCESS) {
	pj_bzero(relay, sizeof(*relay));
	return status;
    }

    /* Find suitable port for this allocation */
    if (req->rpp_port) {
	retry_max = 1;
    } else {
	retry_max = RETRY;
    }

    for (retry=0; retry<retry_max; ++retry) {
	pj_uint16_t port;
	pj_sockaddr bound_addr;

	pj_lock_acquire(srv->core.lock);

	if (req->rpp_port) {
	    port = (pj_uint16_t) req->rpp_port;
	} else if (req->tp_type == PJ_TURN_TP_UDP) {
	    port = (pj_uint16_t) srv->ports.next_udp++;
	    if (srv->ports.next_udp > srv->ports.max_udp)
		srv->ports.next_udp = srv->ports.min_udp;
	} else if (req->tp_type == PJ_TURN_TP_TCP) {
	    port = (pj_uint16_t) srv->ports.next_tcp++;
	    if (srv->ports.next_tcp > srv->ports.max_tcp)
		srv->ports.next_tcp = srv->ports.min_tcp;
	} else {
	    pj_assert(!"Invalid transport");
	    port = 0;
	}

	pj_lock_release(srv->core.lock);

	pj_sockaddr_init(af, &bound_addr, NULL, port);

	status = pj_sock_bind(relay->tp.sock, &bound_addr,
			      pj_sockaddr_get_len(&bound_addr));
	if (status == PJ_SUCCESS)
	    break;
    }

    if (status != PJ_SUCCESS) {
	/* Unable to allocate port */
	PJ_LOG(4,(THIS_FILE, "Unable to allocate relay, giving up: err %d",
		  status));
	pj_sock_close(relay->tp.sock);
	relay->tp.sock = PJ_INVALID_SOCKET;
	return status;
    }

    /* Init relay key */
    namelen = sizeof(relay->hkey.addr);
    status = pj_sock_getsockname(relay->tp.sock, &relay->hkey.addr, &namelen);
    if (status != PJ_SUCCESS) {
	PJ_LOG(4,(THIS_FILE, "pj_sock_getsockname() failed: err %d",
		  status));
	pj_sock_close(relay->tp.sock);
	relay->tp.sock = PJ_INVALID_SOCKET;
	return status;
    }
    if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
	pj_sockaddr_copy_addr(&relay->hkey.addr,
			      &alloc->transport->listener->addr);
    }
    if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
	pj_sockaddr tmp_addr;
	pj_gethostip(af, &tmp_addr);
	pj_sockaddr_copy_addr(&relay->hkey.addr, &tmp_addr);
    }

    /* Init ioqueue */
    pj_bzero(&icb, sizeof(icb));
    icb.on_read_complete = &on_rx_from_peer;

    status = pj_ioqueue_register_sock(pool, srv->core.ioqueue, relay->tp.sock,
				      relay, &icb, &relay->tp.key);
    if (status != PJ_SUCCESS) {
	PJ_LOG(4,(THIS_FILE, "pj_ioqueue_register_sock() failed: err %d",
		  status));
	pj_sock_close(relay->tp.sock);
	relay->tp.sock = PJ_INVALID_SOCKET;
	return status;
    }

    /* Kick off pending read operation */
    pj_ioqueue_op_key_init(&relay->tp.read_key, sizeof(relay->tp.read_key));
    on_rx_from_peer(relay->tp.key, &relay->tp.read_key, 0);

    /* Done */
    return PJ_SUCCESS;
}
Exemple #26
0
/**
 * Create a SDP session description that describes the endpoint
 * capability.
 */
PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
					      pj_pool_t *pool,
					      unsigned stream_cnt,
					      const pjmedia_sock_info sock_info[],
					      pjmedia_sdp_session **p_sdp )
{
    pj_time_val tv;
    unsigned i;
    const pj_sockaddr *addr0;
    pjmedia_sdp_session *sdp;
    pjmedia_sdp_media *m;
    pjmedia_sdp_attr *attr;

    /* Sanity check arguments */
    PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL);

    /* Check that there are not too many codecs */
    PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT,
		     PJ_ETOOMANY);

    /* Create and initialize basic SDP session */
    sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);

    addr0 = &sock_info[0].rtp_addr_name;

    pj_gettimeofday(&tv);
    sdp->origin.user = pj_str("-");
    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
    sdp->origin.net_type = STR_IN;

    if (addr0->addr.sa_family == pj_AF_INET()) {
	sdp->origin.addr_type = STR_IP4;
	pj_strdup2(pool, &sdp->origin.addr, 
		   pj_inet_ntoa(addr0->ipv4.sin_addr));
    } else if (addr0->addr.sa_family == pj_AF_INET6()) {
	char tmp_addr[PJ_INET6_ADDRSTRLEN];

	sdp->origin.addr_type = STR_IP6;
	pj_strdup2(pool, &sdp->origin.addr, 
		   pj_sockaddr_print(addr0, tmp_addr, sizeof(tmp_addr), 0));

    } else {
	pj_assert(!"Invalid address family");
	return PJ_EAFNOTSUP;
    }

    sdp->name = STR_SDP_NAME;

    /* Since we only support one media stream at present, put the
     * SDP connection line in the session level.
     */
    sdp->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
    sdp->conn->net_type = sdp->origin.net_type;
    sdp->conn->addr_type = sdp->origin.addr_type;
    sdp->conn->addr = sdp->origin.addr;


    /* SDP time and attributes. */
    sdp->time.start = sdp->time.stop = 0;
    sdp->attr_count = 0;

    /* Create media stream 0: */

    sdp->media_count = 1;
    m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
    sdp->media[0] = m;

    /* Standard media info: */
    pj_strdup(pool, &m->desc.media, &STR_AUDIO);
    m->desc.port = pj_sockaddr_get_port(addr0);
    m->desc.port_count = 1;
    pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);

    /* Init media line and attribute list. */
    m->desc.fmt_count = 0;
    m->attr_count = 0;

    /* Add "rtcp" attribute */
#if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0
    if (sock_info->rtcp_addr_name.addr.sa_family != 0) {
	attr = pjmedia_sdp_attr_create_rtcp(pool, &sock_info->rtcp_addr_name);
	if (attr)
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
    }
#endif

    /* Add format, rtpmap, and fmtp (when applicable) for each codec */
    for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {

	pjmedia_codec_info *codec_info;
	pjmedia_sdp_rtpmap rtpmap;
	char tmp_param[3];
	pjmedia_sdp_attr *attr;
	pjmedia_codec_param codec_param;
	pj_str_t *fmt;

	if (endpt->codec_mgr.codec_desc[i].prio == PJMEDIA_CODEC_PRIO_DISABLED)
	    break;

	codec_info = &endpt->codec_mgr.codec_desc[i].info;
	pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr, codec_info,
					    &codec_param);
	fmt = &m->desc.fmt[m->desc.fmt_count++];

	fmt->ptr = (char*) pj_pool_alloc(pool, 8);
	fmt->slen = pj_utoa(codec_info->pt, fmt->ptr);

	rtpmap.pt = *fmt;
	rtpmap.enc_name = codec_info->encoding_name;

#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
	if (codec_info->pt == PJMEDIA_RTP_PT_G722)
	    rtpmap.clock_rate = 8000;
	else
	    rtpmap.clock_rate = codec_info->clock_rate;
#else
	rtpmap.clock_rate = codec_info->clock_rate;
#endif

	/* For audio codecs, rtpmap parameters denotes the number
	 * of channels, which can be omited if the value is 1.
	 */
	if (codec_info->type == PJMEDIA_TYPE_AUDIO &&
	    codec_info->channel_cnt > 1)
	{
	    /* Can only support one digit channel count */
	    pj_assert(codec_info->channel_cnt < 10);

	    tmp_param[0] = (char)('0' + codec_info->channel_cnt);

	    rtpmap.param.ptr = tmp_param;
	    rtpmap.param.slen = 1;

	} else {
	    rtpmap.param.slen = 0;
	}

	if (codec_info->pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
	    pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
	    m->attr[m->attr_count++] = attr;
	}

	/* Add fmtp params */
	if (codec_param.setting.dec_fmtp.cnt > 0) {
	    enum { MAX_FMTP_STR_LEN = 160 };
	    char buf[MAX_FMTP_STR_LEN];
	    unsigned buf_len = 0, i;
	    pjmedia_codec_fmtp *dec_fmtp = &codec_param.setting.dec_fmtp;

	    /* Print codec PT */
	    buf_len += pj_ansi_snprintf(buf, 
					MAX_FMTP_STR_LEN - buf_len, 
					"%d", 
					codec_info->pt);

	    for (i = 0; i < dec_fmtp->cnt; ++i) {
		unsigned test_len = 2;

		/* Check if buf still available */
		test_len = dec_fmtp->param[i].val.slen + 
			   dec_fmtp->param[i].name.slen;
		if (test_len + buf_len >= MAX_FMTP_STR_LEN)
		    return PJ_ETOOBIG;

		/* Print delimiter */
		buf_len += pj_ansi_snprintf(&buf[buf_len], 
					    MAX_FMTP_STR_LEN - buf_len,
					    (i == 0?" ":";"));

		/* Print an fmtp param */
		if (dec_fmtp->param[i].name.slen)
		    buf_len += pj_ansi_snprintf(
					    &buf[buf_len],
					    MAX_FMTP_STR_LEN - buf_len,
					    "%.*s=%.*s",
					    (int)dec_fmtp->param[i].name.slen,
					    dec_fmtp->param[i].name.ptr,
					    (int)dec_fmtp->param[i].val.slen,
					    dec_fmtp->param[i].val.ptr);
		else
		    buf_len += pj_ansi_snprintf(&buf[buf_len], 
					    MAX_FMTP_STR_LEN - buf_len,
					    "%.*s", 
					    (int)dec_fmtp->param[i].val.slen,
					    dec_fmtp->param[i].val.ptr);
	    }

	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);

	    attr->name = pj_str("fmtp");
	    attr->value = pj_strdup3(pool, buf);
	    m->attr[m->attr_count++] = attr;
	}
    }

    /* Add sendrecv attribute. */
    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
    attr->name = STR_SENDRECV;
    m->attr[m->attr_count++] = attr;

#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0

    /*
     * Add support telephony event
     */
    m->desc.fmt[m->desc.fmt_count++] = 
	pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR);

    /* Add rtpmap. */
    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
    attr->name = pj_str("rtpmap");
    attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR 
			 " telephone-event/8000");
    m->attr[m->attr_count++] = attr;

    /* Add fmtp */
    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
    attr->name = pj_str("fmtp");
    attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR " 0-15");
    m->attr[m->attr_count++] = attr;
#endif

    /* Done */
    *p_sdp = sdp;

    return PJ_SUCCESS;

}
Exemple #27
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;
}
Exemple #28
0
/*! \brief Function which negotiates an incoming media stream */
static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
					 const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
{
	char host[NI_MAXHOST];
	RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
	enum ast_media_type media_type = stream_to_media_type(session_media->stream_type);
	enum ast_sip_session_media_encryption encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
	int res;

	/* If port is 0, ignore this media stream */
	if (!stream->desc.port) {
		ast_debug(3, "Media stream '%s' is already declined\n", session_media->stream_type);
		return 0;
	}

	/* If no type formats have been configured reject this stream */
	if (!ast_format_cap_has_type(session->endpoint->media.codecs, media_type)) {
		ast_debug(3, "Endpoint has no codecs for media type '%s', declining stream\n", session_media->stream_type);
		return 0;
	}

	/* Ensure incoming transport is compatible with the endpoint's configuration */
	if (!session->endpoint->media.rtp.use_received_transport) {
		encryption = check_endpoint_media_transport(session->endpoint, stream);

		if (encryption == AST_SIP_MEDIA_TRANSPORT_INVALID) {
			return -1;
		}
	}

	ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host));

	/* Ensure that the address provided is valid */
	if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
		/* The provided host was actually invalid so we error out this negotiation */
		return -1;
	}

	/* Using the connection information create an appropriate RTP instance */
	if (!session_media->rtp && create_rtp(session, session_media, ast_sockaddr_is_ipv6(addrs))) {
		return -1;
	}

	res = setup_media_encryption(session, session_media, sdp, stream);
	if (res) {
		if (!session->endpoint->media.rtp.encryption_optimistic) {
			/* If optimistic encryption is disabled and crypto should have been enabled
			 * but was not this session must fail.
			 */
			return -1;
		}
		/* There is no encryption, sad. */
		session_media->encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
 	}

	/* If we've been explicitly configured to use the received transport OR if
	 * encryption is on and crypto is present use the received transport.
	 * This is done in case of optimistic because it may come in as RTP/AVP or RTP/SAVP depending
	 * on the configuration of the remote endpoint (optimistic themselves or mandatory).
	 */
	if ((session->endpoint->media.rtp.use_received_transport) ||
		((encryption == AST_SIP_MEDIA_ENCRYPT_SDES) && !res)) {
		pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport);
 	}

	if (set_caps(session, session_media, stream)) {
		return 0;
	}
	return 1;
}
void SessionExpiresHelper::process_response(pjsip_msg* rsp,
                                            pj_pool_t* pool,
                                            SAS::TrailId trail)
{
  // Session expires is only allowed on INVITE and UPDATE methods.
  pjsip_method* method = &PJSIP_MSG_CSEQ_HDR(rsp)->method;

  if ((pjsip_method_cmp(method, pjsip_get_invite_method()) != 0) &&
      (pjsip_method_cmp(method, &METHOD_UPDATE) != 0))
  {
    return;
  }

  // We only need to process successful final responses.
  if (!PJSIP_IS_STATUS_IN_CLASS(rsp->line.status.code, 200))
  {
    return;
  }

  pjsip_session_expires_hdr* se_hdr = (pjsip_session_expires_hdr*)
    pjsip_msg_find_hdr_by_name(rsp, &STR_SESSION_EXPIRES, NULL);

  if (se_hdr == NULL)
  {
    // There is no session-expires header. This means we are most downstream
    // device that supports session timers, and in particular the UAS does not
    // support them.
    //
    // If the UAC does not support session timers, there's nothing more we can
    // do - session timers will not be used for this dialog.
    //
    // If the UAC *does* support session timers, re-add a session-expires header
    // that instructs the UAC to be the refresher.
    if (_uac_supports_timer)
    {
      se_hdr = pjsip_session_expires_hdr_create(pool);
      pjsip_msg_add_hdr(rsp, (pjsip_hdr*)se_hdr);
      se_hdr->expires = _se_on_req;
      se_hdr->refresher = SESSION_REFRESHER_UAC;

      // Also update (or add) the require header to force the UAC to do session
      // refreshes.
      pjsip_require_hdr* require_hdr = (pjsip_require_hdr*)
        pjsip_msg_find_hdr(rsp, PJSIP_H_REQUIRE, NULL);

      if (require_hdr == NULL)
      {
        require_hdr = (pjsip_require_hdr*)pjsip_require_hdr_create(pool);
        pjsip_msg_add_hdr(rsp, (pjsip_hdr*)require_hdr);
      }

      pj_strdup(pool, &require_hdr->values[require_hdr->count], &STR_TIMER);
      require_hdr->count++;
    }
  }

  if (_initial_request)
  {
    if (se_hdr == NULL)
    {
      SAS::Event event(trail, SASEvent::SESS_TIMER_NO_UA_SUPPORT, 0);
      SAS::report_event(event);
    }
    else if (se_hdr->expires > _target_se)
    {
      SAS::Event event(trail, SASEvent::SESS_TIMER_INTERVAL_TOO_LONG, 0);
      event.add_static_param(_target_se);
      event.add_static_param(se_hdr->expires);
      SAS::report_event(event);
    }
  }
}
Exemple #30
0
PJ_DEF(void) pjsip_name_addr_assign(pj_pool_t *pool, pjsip_name_addr *dst,
                                    const pjsip_name_addr *src)
{
    pj_strdup( pool, &dst->display, &src->display);
    dst->uri = (pjsip_uri*) pjsip_uri_clone(pool, src->uri);
}