Example #1
0
void
addContactHeader(const pj_str_t *contact_str, pjsip_tx_data *tdata)
{
    pjsip_contact_hdr *contact = pjsip_contact_hdr_create(tdata->pool);
    contact->uri = pjsip_parse_uri(tdata->pool, contact_str->ptr,
                                   contact_str->slen, PJSIP_PARSE_URI_AS_NAMEADDR);
    // remove old contact header (if present)
    pjsip_msg_find_remove_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) contact);
}
Example #2
0
/*! \brief Internal function which adds a contact to a response */
static int registrar_add_contact(void *obj, void *arg, int flags)
{
	struct ast_sip_contact *contact = obj;
	pjsip_tx_data *tdata = arg;
	pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
	pj_str_t uri;

	pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
	hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
	hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;

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

	return 0;
}
Example #3
0
PJ_DEF(pj_status_t) pjsip_regc_unregister_all(pjsip_regc *regc,
					      pjsip_tx_data **p_tdata)
{
    pjsip_tx_data *tdata;
    pjsip_contact_hdr *hcontact;
    pjsip_hdr *hdr;
    pjsip_msg *msg;
    pj_status_t status;

    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);

    pj_lock_acquire(regc->lock);

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

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

    msg = tdata->msg;

    /* Clear removed_contact_hdr_list */
    pj_list_init(&regc->removed_contact_hdr_list);

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

    pj_lock_release(regc->lock);

    *p_tdata = tdata;
    return PJ_SUCCESS;
}
Example #4
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;
}
Example #5
0
/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted)
{
	pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
	struct registrar_contact_details details = {
		.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256),
	};

	if (!details.pool) {
		return -1;
	}

	while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
		int expiration = registrar_get_expiration(aor, contact, rdata);
		RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup);

		if (contact->star) {
			/* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
			if ((expiration != 0) || previous) {
				pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
				return -1;
			}
			continue;
		} else if (previous && previous->star) {
			/* If there is a previous contact and it is a '*' this is a deal breaker */
			pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
			return -1;
		}
		previous = contact;

		if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
			continue;
		}

		details.uri = pjsip_uri_get_uri(contact->uri);

		/* Determine if this is an add, update, or delete for policy enforcement purposes */
		if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) {
			if (expiration) {
				(*added)++;
			}
		} else if (expiration) {
			(*updated)++;
		} else {
			(*deleted)++;
		}
	}

	/* The provided contacts are acceptable, huzzah! */
	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
	return 0;
}

/*! \brief Callback function which prunes static contacts */
static int registrar_prune_static(void *obj, void *arg, int flags)
{
	struct ast_sip_contact *contact = obj;

	return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0;
}

/*! \brief Internal function used to delete all contacts from an AOR */
static int registrar_delete_contact(void *obj, void *arg, int flags)
{
	struct ast_sip_contact *contact = obj;
	const char *aor_name = arg;

	ast_sip_location_delete_contact(contact);
	if (!ast_strlen_zero(aor_name)) {
		ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name);
		ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
				"Contact: %s\r\n"
				"AOR: %s",
				contact->uri,
				aor_name);
	}

	return 0;
}

/*! \brief Internal function which adds a contact to a response */
static int registrar_add_contact(void *obj, void *arg, int flags)
{
	struct ast_sip_contact *contact = obj;
	pjsip_tx_data *tdata = arg;
	pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
	pj_str_t uri;

	pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
	hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
	hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;

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

	return 0;
}

/*! \brief Helper function which adds a Date header to a response */
static void registrar_add_date_header(pjsip_tx_data *tdata)
{
	char date[256];
	struct tm tm;
	time_t t = time(NULL);

	gmtime_r(&t, &tm);
	strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm);

	ast_sip_add_header(tdata, "Date", date);
}
void SubscriptionSproutletTsx::process_subscription_request(pjsip_msg* req)
{
  SAS::TrailId trail_id = trail();

  // 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(PJSIP_MSG_TO_HDR(req)->uri);

  if ((!PJSIP_URI_SCHEME_IS_SIP(uri)) && (!PJSIP_URI_SCHEME_IS_TEL(uri)))
  {
    // Reject a non-SIP/TEL 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).
    TRC_DEBUG("Rejecting subscribe request using invalid URI scheme");

    SAS::Event event(trail_id, SASEvent::SUBSCRIBE_FAILED_EARLY_URLSCHEME, 0);
    SAS::report_event(event);

    pjsip_msg* rsp = create_response(req, PJSIP_SC_NOT_FOUND);
    send_response(rsp);
    free_msg(req);
    return;
  }

  // Check if the contact header is present. If it isn't, we want to abort
  // processing before going any further, to avoid unnecessary work.
  pjsip_contact_hdr* contact_hdr =
             (pjsip_contact_hdr*)pjsip_msg_find_hdr(req, PJSIP_H_CONTACT, NULL);

  if (contact_hdr == NULL)
  {
    TRC_DEBUG("Unable to parse contact header from request. "
              "Aborting processing");
    pjsip_msg* rsp = create_response(req, PJSIP_SC_BAD_REQUEST);
    send_response(rsp);
    free_msg(req);
    return;
  }

  // Check if this is a subscription request from a binding that was emergency
  // registered.
  bool emergency_subscription = false;

  while (contact_hdr != NULL)
  {
    emergency_subscription = PJUtils::is_emergency_registration(contact_hdr);

    if (!emergency_subscription)
    {
      break;
    }

    contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(req,
                                                          PJSIP_H_CONTACT,
                                                          contact_hdr->next);
  }

  if (emergency_subscription)
  {
    // Reject a subscription with a Contact header containing a contact address
    // that's been registered for emergency service.
    TRC_DEBUG("Rejecting subscribe request from emergency registration");

    SAS::Event event(trail_id, SASEvent::SUBSCRIBE_FAILED_EARLY_EMERGENCY, 0);
    SAS::report_event(event);

    // Allow-Events is a mandatory header on 489 responses.
    pjsip_msg* rsp = create_response(req, PJSIP_SC_BAD_EVENT);
    pjsip_generic_string_hdr* allow_events_hdr =
                           pjsip_generic_string_hdr_create(get_pool(rsp),
                                                           &STR_ALLOW_EVENTS,
                                                           &STR_REG);
    pjsip_msg_add_hdr(rsp, (pjsip_hdr*)allow_events_hdr);
    send_response(rsp);
    free_msg(req);
    return;
  }

  // At this point we are going to attempt to process the subscribe.
  // Canonicalize the public ID from the URI in the To header.
  std::string public_id = PJUtils::public_id_from_uri(uri);

  TRC_DEBUG("Process SUBSCRIBE for public ID %s", public_id.c_str());

  // Get the call identifier from the headers.
  std::string cid = PJUtils::pj_str_to_string(&PJSIP_MSG_CID_HDR(req)->id);

  // Add SAS markers to the trail attached to the message so the trail
  // becomes searchable.
  SAS::Event event(trail_id, SASEvent::SUBSCRIBE_START, 0);
  event.add_var_param(public_id);
  SAS::report_event(event);

  // Create an ACR for the request. The node role is always considered
  // originating for SUBSCRIBE requests.
  ACR* acr = _subscription->_acr_factory->get_acr(trail_id,
                                                  ACR::CALLING_PARTY,
                                                  ACR::NODE_ROLE_ORIGINATING);
  acr->rx_request(req);

  // Work out the expiry time of the subscription.
  pjsip_expires_hdr* expires =
             (pjsip_expires_hdr*)pjsip_msg_find_hdr(req, PJSIP_H_EXPIRES, NULL);
  int expiry = (expires != NULL) ?
                expires->ivalue :
                SubscriptionSproutlet::DEFAULT_SUBSCRIPTION_EXPIRES;

  if (expiry > _subscription->_max_expires)
  {
    // Expiry is too long, set it to the maximum.
    TRC_DEBUG("Requested expiry (%d) is too long, setting to the maximum (%d)",
              expiry, _subscription->_max_expires);
    expiry = _subscription->_max_expires;
  }

  // Create a subscription object from the request that we can pass down to
  // be set into/updated in the different stores
  Subscription* new_subscription = create_subscription(req, expiry);
  HSSConnection::irs_info irs_info;
  HTTPCode rc;

  // Update or remove the subscription in the subscriber manager depending on
  // the expiry time.
  if (expiry != 0)
  {
    TRC_DEBUG("Adding/updating the subscription with ID %s",
              new_subscription->get_id().c_str());

    Subscriptions new_subscriptions;
    new_subscriptions.insert(std::make_pair(new_subscription->get_id(), new_subscription));
    rc = _subscription->_sm->update_subscriptions(
                   public_id,
                   new_subscriptions,
                   irs_info,
                   trail_id);
  }
  else
  {
    TRC_DEBUG("Removing the subscription with ID %s",
              new_subscription->get_id().c_str());

    rc = _subscription->_sm->remove_subscriptions(public_id,
                                                  {new_subscription->get_id()},
                                                  irs_info,
                                                  trail_id);
  }

  pjsip_status_code st_code =
                 determine_sm_sip_response(rc, irs_info._regstate, "SUBSCRIBE");

  pjsip_msg* rsp = create_response(req, st_code);

  if (st_code == PJSIP_SC_OK)
  {
    // The subscribe was successful. SAS log, and add headers to the response.
    TRC_DEBUG("The subscribe has been successful");

    SAS::Event sub_accepted(trail_id, SASEvent::SUBSCRIBE_ACCEPTED, 0);
    SAS::report_event(sub_accepted);

    // Add expires headers
    pjsip_expires_hdr* expires_hdr = pjsip_expires_hdr_create(get_pool(rsp),
                                                              expiry);
    pjsip_msg_add_hdr(rsp, (pjsip_hdr*)expires_hdr);

    // Add the contact header
    pjsip_contact_hdr* contact_hdr = pjsip_contact_hdr_create(get_pool(rsp));
    pjsip_name_addr* contact_uri = pjsip_name_addr_create(get_pool(rsp));
    contact_uri->uri = (pjsip_uri*)stack_data.scscf_uri;
    contact_hdr->uri = (pjsip_uri*)contact_uri;
    pjsip_msg_add_hdr(rsp, (pjsip_hdr*)contact_hdr);

    // Add a P-Charging-Function-Addresses header to the successful SUBSCRIBE
    // response containing the charging addresses returned by the HSS.
    PJUtils::add_pcfa_header(rsp,
                             get_pool(rsp),
                             irs_info._ccfs,
                             irs_info._ecfs,
                             false);

  }
  else if (st_code == PJSIP_SC_TEMPORARILY_UNAVAILABLE)
  {
    // A 480 response means that the subscriber wasn't registered. SAS log
    // this.
    TRC_DEBUG("The subscribe has failed as the subscriber (%s) wasn't registered",
              public_id.c_str());

    SAS::Event event(trail_id, SASEvent::SUBSCRIBE_FAILED_EARLY_NOT_REG, 0);
    SAS::report_event(event);
  }
  else
  {
    // The subscribe was unsuccessful.
    TRC_DEBUG("The subscribe failed with return code %d", st_code);

    SAS::Event sub_failed(trail_id, SASEvent::SUBSCRIBE_FAILED, 0);
    sub_failed.add_var_param(public_id);
    SAS::report_event(sub_failed);
  }

  // Add the to tag to the response (even if the subscribe was rejected).
  pjsip_to_hdr *to = (pjsip_to_hdr*) pjsip_msg_find_hdr(rsp,
                                                        PJSIP_H_TO,
                                                        NULL);
  pj_strdup2(get_pool(rsp), &to->tag, new_subscription->_to_tag.c_str());

  // Pass the response to the ACR.
  acr->tx_response(rsp);

  // Send the response.
  send_response(rsp);

  // Send the ACR and delete it.
  acr->send();
  delete acr; acr = NULL;

  delete new_subscription; new_subscription = NULL;
  free_msg(req);
}
Example #7
0
void process_register_request(pjsip_rx_data* rdata)
{
  pj_status_t status;
  int st_code = PJSIP_SC_OK;
  SAS::TrailId trail = get_trail(rdata);

  // 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)) && (!PJSIP_URI_SCHEME_IS_TEL(uri)))
  {
    // Reject a non-SIP/TEL 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).
    LOG_ERROR("Rejecting register request using invalid URI scheme");

    SAS::Event event(trail, SASEvent::REGISTER_FAILED, 0);
    // Can't log the public ID as the REGISTER has failed too early
    std::string public_id = "UNKNOWN";
    std::string error_msg = "Rejecting register request using invalid URI scheme";
    event.add_var_param(public_id);
    event.add_var_param(error_msg);
    SAS::report_event(event);

    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               PJSIP_SC_NOT_FOUND,
                               NULL,
                               NULL,
                               NULL);
    return;
  }

  // Allocate an ACR for this transaction and pass the request to it.
  ACR* acr = acr_factory->get_acr(get_trail(rdata),
                                  CALLING_PARTY,
                                  ACR::requested_node_role(rdata->msg_info.msg));
  acr->rx_request(rdata->msg_info.msg, rdata->pkt_info.timestamp);

  // Canonicalize the public ID from the URI in the To header.
  std::string public_id = PJUtils::public_id_from_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);;
  pjsip_msg *msg = rdata->msg_info.msg;

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

  PJUtils::report_sas_to_from_markers(trail, rdata->msg_info.msg);
  PJUtils::mark_sas_call_branch_ids(trail, NULL, rdata->msg_info.msg);

  // Query the HSS for the associated URIs.
  std::vector<std::string> uris;
  std::map<std::string, Ifcs> ifc_map;
  std::string private_id;
  std::string private_id_for_binding;
  bool success = get_private_id(rdata, private_id);
  if (!success)
  {
    // There are legitimate cases where we don't have a private ID
    // here (for example, on a re-registration where Bono has set the
    // Integrity-Protected header), so this is *not* a failure
    // condition.

    // We want the private ID here so that Homestead can use it to
    // subscribe for updates from the HSS - but on a re-registration,
    // Homestead should already have subscribed for updates during the
    // initial registration, so we can just make a request using our
    // public ID.
    private_id = "";

    // IMS compliant clients will always have the Auth header on all REGISTERs,
    // including reREGISTERS. Non-IMS clients won't, but their private ID
    // will always be the public ID with the sip: removed.
    private_id_for_binding = PJUtils::default_private_id_from_uri(uri);
  }
  else
  {
    private_id_for_binding = private_id;
  }

  SAS::Event event(trail, SASEvent::REGISTER_START, 0);
  event.add_var_param(public_id);
  event.add_var_param(private_id);
  SAS::report_event(event);

  std::string regstate;
  std::deque<std::string> ccfs;
  std::deque<std::string> ecfs;
  HTTPCode http_code = hss->update_registration_state(public_id,
                                                      private_id,
                                                      HSSConnection::REG,
                                                      regstate,
                                                      ifc_map,
                                                      uris,
                                                      ccfs,
                                                      ecfs,
                                                      trail);
  if ((http_code != HTTP_OK) || (regstate != HSSConnection::STATE_REGISTERED))
  {
    // We failed to register this subscriber at the HSS.  This indicates that the
    // HSS is unavailable, the public identity doesn't exist or the public
    // identity doesn't belong to the private identity.

    // The client shouldn't retry when the subscriber isn't present in the
    // HSS; reject with a 403 in this case.
    //
    // The client should retry on timeout but no other Clearwater nodes should
    // (as Sprout will already have retried on timeout). Reject with a 504
    // (503 is used for overload).
    st_code = PJSIP_SC_SERVER_TIMEOUT;

    if (http_code == HTTP_NOT_FOUND)
    {
      st_code = PJSIP_SC_FORBIDDEN;
    }

    LOG_ERROR("Rejecting register request with invalid public/private identity");

    SAS::Event event(trail, SASEvent::REGISTER_FAILED, 0);
    event.add_var_param(public_id);
    std::string error_msg = "Rejecting register request with invalid public/private identity";
    event.add_var_param(error_msg);
    SAS::report_event(event);

    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               st_code,
                               NULL,
                               NULL,
                               NULL);
    delete acr;
    return;
  }

  // Determine the AOR from the first entry in the uris array.
  std::string aor = uris.front();
  LOG_DEBUG("REGISTER for public ID %s uses AOR %s", public_id.c_str(), aor.c_str());

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

  // Loop through each contact header. If every registration is an emergency
  // registration and its expiry is 0 then reject with a 501.
  // If there are valid registration updates to make then attempt to write to
  // store, which also stops emergency registrations from being deregistered.
  bool reject_with_501 = true;
  bool any_emergency_registrations = false;
  bool reject_with_400 = false;
  pjsip_contact_hdr* contact_hdr = (pjsip_contact_hdr*)
                 pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);

  while (contact_hdr != NULL)
  {
    pjsip_expires_hdr* expires = (pjsip_expires_hdr*)pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
    expiry = (contact_hdr->expires != -1) ? contact_hdr->expires :
             (expires != NULL) ? expires->ivalue :
              max_expires;

    if ((contact_hdr->star) && (expiry != 0))
    {
      // Wildcard contact, which can only be used if the expiry is 0
      LOG_ERROR("Attempted to deregister all bindings, but expiry value wasn't 0");
      reject_with_400 = true;
      break;
    }

    reject_with_501 = (reject_with_501 &&
                       PJUtils::is_emergency_registration(contact_hdr) && (expiry == 0));
    any_emergency_registrations = (any_emergency_registrations ||
                                  PJUtils::is_emergency_registration(contact_hdr));

    contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
                                                          PJSIP_H_CONTACT,
                                                          contact_hdr->next);
  }

  if (reject_with_400)
  {
    SAS::Event event(trail, SASEvent::REGISTER_FAILED, 0);
    event.add_var_param(public_id);
    std::string error_msg = "Rejecting register request with invalid contact header";
    event.add_var_param(error_msg);
    SAS::report_event(event);

    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               PJSIP_SC_BAD_REQUEST,
                               NULL,
                               NULL,
                               NULL);
    delete acr;
    return;
  }

  if (reject_with_501)
  {
    LOG_ERROR("Rejecting register request as attempting to deregister an emergency registration");

    SAS::Event event(trail, SASEvent::REGISTER_FAILED, 0);
    event.add_var_param(public_id);
    std::string error_msg = "Rejecting deregister request for emergency registrations";
    event.add_var_param(error_msg);
    SAS::report_event(event);

    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               PJSIP_SC_NOT_IMPLEMENTED,
                               NULL,
                               NULL,
                               NULL);
    delete acr;
    return;
  }


  // Write to the local store, checking the remote store if there is no entry locally.
  RegStore::AoR* aor_data = write_to_store(store, aor, rdata, now, expiry,
                                           is_initial_registration, NULL, remote_store,
                                           true, private_id_for_binding, trail);
  if (aor_data != NULL)
  {
    // Log the bindings.
    log_bindings(aor, aor_data);

    // If we have a remote store, try to store this there too.  We don't worry
    // about failures in this case.
    if (remote_store != NULL)
    {
      int tmp_expiry = 0;
      bool ignored;
      RegStore::AoR* remote_aor_data = write_to_store(remote_store, aor, rdata, now,
                                                      tmp_expiry, ignored, aor_data,
                                                      NULL, false, private_id_for_binding,
                                                      trail);
      delete remote_aor_data;
    }
  }
  else
  {
    // Failed to connect to the local store.  Reject the register with a 500
    // response.
    // LCOV_EXCL_START - the can't fail to connect to the store we use for UT
    st_code = PJSIP_SC_INTERNAL_SERVER_ERROR;

    SAS::Event event(trail, SASEvent::REGISTER_FAILED, 0);
    event.add_var_param(public_id);
    std::string error_msg = "Unable to access Registration Store";
    event.add_var_param(error_msg);
    SAS::report_event(event);

    // LCOV_EXCL_STOP
  }

  // 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
    std::string error_msg = "Error building REGISTER " + std::to_string(status) +
                            " response " + PJUtils::pj_status_to_string(status);

    LOG_ERROR(error_msg.c_str());

    SAS::Event event(trail, SASEvent::REGISTER_FAILED, 0);
    event.add_var_param(public_id);
    event.add_var_param(error_msg);
    SAS::report_event(event);

    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               PJSIP_SC_INTERNAL_SERVER_ERROR,
                               NULL,
                               NULL,
                               NULL);
    delete acr;
    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);

    SAS::Event event(trail, SASEvent::REGISTER_FAILED, 0);
    event.add_var_param(public_id);
    std::string error_msg = "REGISTER failed with status code: " + std::to_string(st_code);
    event.add_var_param(error_msg);
    SAS::report_event(event);

    delete acr;
    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");

    SAS::Event event(trail, SASEvent::REGISTER_FAILED, 0);
    event.add_var_param(public_id);
    std::string error_msg = "Failed to add RFC 5636 headers";
    event.add_var_param(error_msg);
    SAS::report_event(event);

    tdata->msg->line.status.code = PJSIP_SC_INTERNAL_SERVER_ERROR;
    pjsip_tx_data_invalidate_msg(tdata);
    status = pjsip_endpt_send_response2(stack_data.endpt, rdata, tdata, NULL, NULL);
    delete acr;
    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 (RegStore::AoR::Bindings::const_iterator i = aor_data->bindings().begin();
       i != aor_data->bindings().end();
       ++i)
  {
    RegStore::AoR::Binding* binding = i->second;
    if (binding->_expires > now)
    {
      // The binding hasn't expired.  Parse the Contact URI from the store,
      // making sure it is formatted as a name-address.
      pjsip_uri* uri = PJUtils::uri_from_string(binding->_uri, tdata->pool, PJ_TRUE);
      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::map<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);
        }

        // The pub-gruu parameter on the Contact header is calculated
        // from the instance-id, to avoid unnecessary storage in
        // memcached.

        std::string gruu = binding->pub_gruu_quoted_string(tdata->pool);
        if (!gruu.empty())
        {
          pjsip_param *new_param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
          pj_strdup2(tdata->pool, &new_param->name, "pub-gruu");
          pj_strdup2(tdata->pool, &new_param->value, gruu.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());

        SAS::Event event(trail, SASEvent::REGISTER_FAILED, 0);
        event.add_var_param(public_id);
        std::string error_msg = "Badly formed contact URI - " + binding->_uri;
        event.add_var_param(error_msg);
        SAS::report_event(event);
        // LCOV_EXCL_STOP
      }
    }
  }

  // Deal with path header related fields in the response.
  pjsip_routing_hdr* path_hdr = (pjsip_routing_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_routing_hdr*)
                    pjsip_msg_find_hdr_by_name(msg, &STR_PATH, path_hdr->next);
  }

  // Add the Service-Route header.  It isn't safe to do this with the
  // pre-built header from the global pool because the chaining data
  // structures in the header may get overwritten, but it is safe to do a
  // shallow clone.
  pjsip_hdr* clone = (pjsip_hdr*)
                          pjsip_hdr_shallow_clone(tdata->pool, service_route);
  pjsip_msg_insert_first_hdr(tdata->msg, clone);

  // Add P-Associated-URI headers for all of the associated URIs.
  for (std::vector<std::string>::iterator it = uris.begin();
       it != uris.end();
       it++)
  {
    pjsip_routing_hdr* pau =
                        identity_hdr_create(tdata->pool, STR_P_ASSOCIATED_URI);
    pau->name_addr.uri = PJUtils::uri_from_string(*it, tdata->pool);
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pau);
  }

  // Add a PCFA header.
  PJUtils::add_pcfa_header(tdata->msg, tdata->pool, ccfs, ecfs, true);

  // Pass the response to the ACR.
  acr->tx_response(tdata->msg);

  // 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);

  // Send the ACR and delete it.
  acr->send_message();
  delete acr;

  // TODO in sto397: we should do third-party registration once per
  // service profile (i.e. once per iFC, using an arbitrary public
  // ID). hss->get_subscription_data should be enhanced to provide an
  // appropriate data structure (representing the ServiceProfile
  // nodes) and we should loop through that. Don't send any register that
  // contained emergency registrations to the application servers.

  if (!any_emergency_registrations)
  {
    RegistrationUtils::register_with_application_servers(ifc_map[public_id],
                                                         store,
                                                         rdata,
                                                         tdata,
                                                         expiry,
                                                         is_initial_registration,
                                                         public_id,
                                                         trail);
  }

  // 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, MARKER_ID_END, 1u);
  SAS::report_marker(end_marker);
  delete aor_data;
}
Example #8
0
/*
 * Create UAC subscription.
 */
PJ_DEF(pjsip_event_sub*) pjsip_event_sub_create( pjsip_endpoint *endpt,
						 const pj_str_t *from,
						 const pj_str_t *to,
						 const pj_str_t *event,
						 int expires,
						 int accept_cnt,
						 const pj_str_t accept[],
						 void *user_data,
						 const pjsip_event_sub_cb *cb)
{
    pjsip_tx_data *tdata;
    pj_pool_t *pool;
    const pjsip_hdr *hdr;
    pjsip_event_sub *sub;
    PJ_USE_EXCEPTION;

    PJ_LOG(5,(THIS_FILE, "Creating event subscription %.*s to %.*s",
			 event->slen, event->ptr, to->slen, to->ptr));

    /* Create pool for the event subscription. */
    pool = pjsip_endpt_create_pool(endpt, "esub", SUB_POOL_SIZE, SUB_POOL_INC);
    if (!pool) {
	return NULL;
    }

    /* Init subscription. */
    sub = pj_pool_calloc(pool, 1, sizeof(*sub));
    sub->pool = pool;
    sub->endpt = endpt;
    sub->role = PJSIP_ROLE_UAC;
    sub->state = PJSIP_EVENT_SUB_STATE_PENDING;
    sub->state_str = state[sub->state];
    sub->user_data = user_data;
    sub->timer.id = 0;
    sub->default_interval = expires;
    pj_memcpy(&sub->cb, cb, sizeof(*cb));
    pj_list_init(&sub->auth_sess);
    pj_list_init(&sub->route_set);
    sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE);
    if (!sub->mutex) {
	pjsip_endpt_destroy_pool(endpt, pool);
	return NULL;
    }

    /* The easiest way to parse the parameters is to create a dummy request! */
    tdata = pjsip_endpt_create_request( endpt, &SUBSCRIBE, to, from, to, from,
					NULL, -1, NULL);
    if (!tdata) {
	pj_mutex_destroy(sub->mutex);
	pjsip_endpt_destroy_pool(endpt, pool);
	return NULL;
    }

    /* 
     * Duplicate headers in the request to our structure. 
     */
    PJ_TRY {
	int i;

	/* From */
	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL);
	pj_assert(hdr != NULL);
	sub->from = pjsip_hdr_clone(pool, hdr);
        
	/* To */
	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL);
	pj_assert(hdr != NULL);
	sub->to = pjsip_hdr_clone(pool, hdr);

	/* Contact. */
	sub->contact = pjsip_contact_hdr_create(pool);
	sub->contact->uri = sub->from->uri;

	/* Call-ID */
	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CALL_ID, NULL);
	pj_assert(hdr != NULL);
	sub->call_id = pjsip_hdr_clone(pool, hdr);

	/* CSeq */
	sub->cseq = pj_rand() % 0xFFFF;

	/* Event. */
	sub->event = pjsip_event_hdr_create(sub->pool);
	pj_strdup(pool, &sub->event->event_type, event);

	/* Expires. */
	sub->uac_expires = pjsip_expires_hdr_create(pool);
	sub->uac_expires->ivalue = expires;

	/* Accept. */
	sub->local_accept = pjsip_accept_hdr_create(pool);
	for (i=0; i<accept_cnt && i < PJSIP_MAX_ACCEPT_COUNT; ++i) {
	    sub->local_accept->count++;
	    pj_strdup(sub->pool, &sub->local_accept->values[i], &accept[i]);
	}

	/* Register to hash table. */
	create_subscriber_key( &sub->key, pool, PJSIP_ROLE_UAC, 
			       &sub->call_id->id, &sub->from->tag);
	pj_mutex_lock( mgr.mutex );
	pj_hash_set( pool, mgr.ht, sub->key.ptr, sub->key.slen, sub);
	pj_mutex_unlock( mgr.mutex );

    }
    PJ_DEFAULT {
	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): caught exception %d during init", 
			     sub, state[sub->state].ptr, PJ_GET_EXCEPTION()));

	pjsip_tx_data_dec_ref(tdata);
	pj_mutex_destroy(sub->mutex);
	pjsip_endpt_destroy_pool(endpt, sub->pool);
	return NULL;
    }
    PJ_END;

    /* All set, delete temporary transmit data as we don't need it. */
    pjsip_tx_data_dec_ref(tdata);

    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): client created, target=%.*s, event=%.*s",
			 sub, state[sub->state].ptr,
			 to->slen, to->ptr, event->slen, event->ptr));

    return sub;
}
Example #9
0
/* This function is called when we receive SUBSCRIBE request message for 
 * a new subscription.
 */
static void on_new_subscription( pjsip_transaction *tsx, pjsip_rx_data *rdata )
{
    package *pkg;
    pj_pool_t *pool;
    pjsip_event_sub *sub = NULL;
    pj_str_t hname;
    int status = 200;
    pj_str_t reason = { NULL, 0 };
    pjsip_tx_data *tdata;
    pjsip_expires_hdr *expires;
    pjsip_accept_hdr *accept;
    pjsip_event_hdr *evhdr;

    /* Get the Event header. */
    hname = pj_str("Event");
    evhdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL);
    if (!evhdr) {
	status = 400;
	reason = pj_str("No Event header in request");
	goto send_response;
    }

    /* Find corresponding package. 
     * We don't lock the manager's mutex since we assume the package list
     * won't change once the application is running!
     */
    pkg = mgr.pkg_list.next;
    while (pkg != &mgr.pkg_list) {
	if (pj_stricmp(&pkg->event, &evhdr->event_type) == 0)
	    break;
	pkg = pkg->next;
    }

    if (pkg == &mgr.pkg_list) {
	/* Event type is not supported by any packages! */
	status = 489;
	reason = pj_str("Bad Event");
	goto send_response;
    }

    /* First check that the Accept specification matches the 
     * package's Accept types.
     */
    accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL);
    if (accept) {
	unsigned i;
	pj_str_t *content_type = NULL;

	for (i=0; i<accept->count && !content_type; ++i) {
	    int j;
	    for (j=0; j<pkg->accept_cnt; ++j) {
		if (pj_stricmp(&accept->values[i], &pkg->accept[j])==0) {
		    content_type = &pkg->accept[j];
		    break;
		}
	    }
	}

	if (!content_type) {
	    status = PJSIP_SC_NOT_ACCEPTABLE_HERE;
	    goto send_response;
	}
    }

    /* Check whether the package wants to accept the subscription. */
    pj_assert(pkg->cb.on_query_subscribe != NULL);
    (*pkg->cb.on_query_subscribe)(rdata, &status);
    if (!PJSIP_IS_STATUS_IN_CLASS(status,200))
	goto send_response;

    /* Create new subscription record. */
    pool = pjsip_endpt_create_pool(tsx->endpt, "esub", 
				   SUB_POOL_SIZE, SUB_POOL_INC);
    if (!pool) {
	status = 500;
	goto send_response;
    }
    sub = pj_pool_calloc(pool, 1, sizeof(*sub));
    sub->pool = pool;
    sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE);
    if (!sub->mutex) {
	status = 500;
	goto send_response;
    }

    PJ_LOG(4,(THIS_FILE, "event_sub%p: notifier is created.", sub));

    /* Start locking mutex. */
    pj_mutex_lock(sub->mutex);

    /* Init UAS subscription */
    sub->endpt = tsx->endpt;
    sub->role = PJSIP_ROLE_UAS;
    sub->state = PJSIP_EVENT_SUB_STATE_PENDING;
    sub->state_str = state[sub->state];
    pj_list_init(&sub->auth_sess);
    pj_list_init(&sub->route_set);
    sub->from = pjsip_hdr_clone(pool, rdata->to);
    pjsip_fromto_set_from(sub->from);
    if (sub->from->tag.slen == 0) {
	pj_create_unique_string(pool, &sub->from->tag);
	rdata->to->tag = sub->from->tag;
    }
    sub->to = pjsip_hdr_clone(pool, rdata->from);
    pjsip_fromto_set_to(sub->to);
    sub->contact = pjsip_contact_hdr_create(pool);
    sub->contact->uri = sub->from->uri;
    sub->call_id = pjsip_cid_hdr_create(pool);
    pj_strdup(pool, &sub->call_id->id, &rdata->call_id);
    sub->cseq = pj_rand() % 0xFFFF;
    
    expires = pjsip_msg_find_hdr( rdata->msg, PJSIP_H_EXPIRES, NULL);
    if (expires) {
	sub->default_interval = expires->ivalue;
	if (sub->default_interval > 0 && 
	    sub->default_interval < SECONDS_BEFORE_EXPIRY) 
	{
	    status = 423; /* Interval too short. */
	    goto send_response;
	}
    } else {
	sub->default_interval = 600;
    }

    /* Clone Event header. */
    sub->event = pjsip_hdr_clone(pool, evhdr);

    /* Register to hash table. */
    create_subscriber_key(&sub->key, pool, PJSIP_ROLE_UAS, &sub->call_id->id,
			  &sub->from->tag);
    pj_mutex_lock(mgr.mutex);
    pj_hash_set(pool, mgr.ht, sub->key.ptr, sub->key.slen, sub);
    pj_mutex_unlock(mgr.mutex);

    /* Set timer where subscription will expire only when expires<>0. 
     * Subscriber may send new subscription with expires==0.
     */
    if (sub->default_interval != 0) {
	sub_schedule_uas_expire( sub, sub->default_interval-SECONDS_BEFORE_EXPIRY);
    }

    /* Notify application. */
    if (pkg->cb.on_subscribe) {
	pjsip_event_sub_cb *cb = NULL;
	sub->pending_tsx++;
	(*pkg->cb.on_subscribe)(sub, rdata, &cb, &sub->default_interval);
	sub->pending_tsx--;
	if (cb == NULL)
	    pj_memset(&sub->cb, 0, sizeof(*cb));
	else
	    pj_memcpy(&sub->cb, cb, sizeof(*cb));
    }


send_response:
    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s)(UAS): status=%d", 
			  sub, state[sub->state].ptr, status));

    tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status);
    if (tdata) {
	if (reason.slen) {
	    /* Customize reason text. */
	    tdata->msg->line.status.reason = reason;
	}
	if (PJSIP_IS_STATUS_IN_CLASS(status,200)) {
	    /* Add Expires header. */
	    pjsip_expires_hdr *hdr;

	    hdr = pjsip_expires_hdr_create(tdata->pool);
	    hdr->ivalue = sub->default_interval;
	    pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr );
	}
	if (status == 423) {
	    /* Add Min-Expires header. */
	    pjsip_min_expires_hdr *hdr;

	    hdr = pjsip_min_expires_hdr_create(tdata->pool);
	    hdr->ivalue = SECONDS_BEFORE_EXPIRY;
	    pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr);
	}
	if (status == 489 || 
	    status==PJSIP_SC_NOT_ACCEPTABLE_HERE ||
	    PJSIP_IS_STATUS_IN_CLASS(status,200)) 
	{
	    /* Add Allow-Events header. */
	    pjsip_hdr *hdr;
	    hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events);
	    pjsip_msg_add_hdr(tdata->msg, hdr);

	    /* Should add Accept header?. */
	}

	pjsip_tsx_on_tx_msg(tsx, tdata);
    }

    /* If received new subscription with expires=0, terminate. */
    if (sub && sub->default_interval == 0) {
	pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED);
	if (sub->cb.on_sub_terminated) {
	    pj_str_t reason = { "timeout", 7 };
	    (*sub->cb.on_sub_terminated)(sub, &reason);
	}
    }

    if (!PJSIP_IS_STATUS_IN_CLASS(status,200) || (sub && sub->delete_flag)) {
	if (sub && sub->mutex) {
	    pjsip_event_sub_destroy(sub);
	} else if (sub) {
	    pjsip_endpt_destroy_pool(tsx->endpt, sub->pool);
	}
    } else {
	pj_assert(status >= 200);
	pj_mutex_unlock(sub->mutex);
    }
}
Example #10
-1
int dummy_function()
{
    pj_caching_pool cp;
 
    sprintf(NULL, "%d", 0);
    rand();
    
#ifdef HAS_PJLIB
    pj_init();
    pj_caching_pool_init(&cp, NULL, 0);
    pj_array_erase(NULL, 0, 0, 0);
    pj_create_unique_string(NULL, NULL);
    pj_hash_create(NULL, 0);
    pj_hash_get(NULL, NULL, 0, NULL);
    pj_hash_set(NULL, NULL, NULL, 0, 0, NULL);
    pj_ioqueue_create(NULL, 0, NULL);
    pj_ioqueue_register_sock(NULL, NULL, 0, NULL, NULL, NULL);
    pj_pool_alloc(NULL, 0);
    pj_timer_heap_create(NULL, 0, NULL);
#endif

#ifdef HAS_PJLIB_STUN
    pjstun_get_mapped_addr(&cp.factory, 0, NULL, NULL, 80, NULL, 80, NULL);
#endif

#ifdef HAS_PJLIB_GETOPT
    pj_getopt_long(0, NULL, NULL, NULL, NULL);
#endif
    
#ifdef HAS_PJLIB_XML
    pj_xml_parse(NULL, NULL, 100);
    pj_xml_print(NULL, NULL, 10, PJ_FALSE);
    pj_xml_clone(NULL, NULL);
    pj_xml_node_new(NULL, NULL);
    pj_xml_attr_new(NULL, NULL, NULL);
    pj_xml_add_node(NULL, NULL);
    pj_xml_add_attr(NULL, NULL);
    pj_xml_find_node(NULL, NULL);
    pj_xml_find_next_node(NULL, NULL, NULL);
    pj_xml_find_attr(NULL, NULL, NULL);
    pj_xml_find(NULL, NULL, NULL, NULL);
#endif

#ifdef HAS_PJLIB_SCANNER
    pj_cis_buf_init(NULL);
    pj_cis_init(NULL, NULL);
    pj_cis_dup(NULL, NULL);
    pj_cis_add_alpha(NULL);
    pj_cis_add_str(NULL, NULL);

    pj_scan_init(NULL, NULL, 0, 0, NULL);
    pj_scan_fini(NULL);
    pj_scan_peek(NULL, NULL, NULL);
    pj_scan_peek_n(NULL, 0, NULL);
    pj_scan_peek_until(NULL, NULL, NULL);
    pj_scan_get(NULL, NULL, NULL);
    pj_scan_get_unescape(NULL, NULL, NULL);
    pj_scan_get_quote(NULL, 0, 0, NULL);
    pj_scan_get_n(NULL, 0, NULL);
    pj_scan_get_char(NULL);
    pj_scan_get_until(NULL, NULL, NULL);
    pj_scan_strcmp(NULL, NULL, 0);
    pj_scan_stricmp(NULL, NULL, 0);
    pj_scan_stricmp_alnum(NULL, NULL, 0);
    pj_scan_get_newline(NULL);
    pj_scan_restore_state(NULL, NULL);
#endif

#ifdef HAS_PJLIB_DNS
    pj_dns_make_query(NULL, NULL, 0, 0, NULL);
    pj_dns_parse_packet(NULL, NULL, 0, NULL);
    pj_dns_packet_dup(NULL, NULL, 0, NULL);
#endif

#ifdef HAS_PJLIB_RESOLVER
    pj_dns_resolver_create(NULL, NULL, 0, NULL, NULL, NULL);
    pj_dns_resolver_set_ns(NULL, 0, NULL, NULL);
    pj_dns_resolver_handle_events(NULL, NULL);
    pj_dns_resolver_destroy(NULL, 0);
    pj_dns_resolver_start_query(NULL, NULL, 0, 0, NULL, NULL, NULL);
    pj_dns_resolver_cancel_query(NULL, 0);
    pj_dns_resolver_add_entry(NULL, NULL, 0);
#endif

#ifdef HAS_PJLIB_SRV_RESOLVER
    pj_dns_srv_resolve(NULL, NULL, 0, NULL, NULL, PJ_FALSE, NULL, NULL);
#endif

#ifdef HAS_PJLIB_CRC32
    pj_crc32_init(NULL);
    pj_crc32_update(NULL, NULL, 0);
    pj_crc32_final(NULL);
#endif

#ifdef HAS_PJLIB_HMAC_MD5
    pj_hmac_md5(NULL, 0, NULL, 0, NULL);
#endif

#ifdef HAS_PJLIB_HMAC_SHA1
    pj_hmac_sha1(NULL, 0, NULL, 0, NULL);
#endif

#ifdef HAS_PJNATH_STUN
    pj_stun_session_create(NULL, NULL, NULL, PJ_FALSE, NULL);
    pj_stun_session_destroy(NULL);
    pj_stun_session_set_credential(NULL, NULL);
    pj_stun_session_create_req(NULL, 0, NULL, NULL);
    pj_stun_session_create_ind(NULL, 0, NULL);
    pj_stun_session_create_res(NULL, NULL, 0, NULL, NULL);
    pj_stun_session_send_msg(NULL, PJ_FALSE, NULL, 0, NULL);
#endif

#ifdef HAS_PJNATH_ICE
    pj_ice_strans_create(NULL, NULL, 0, NULL, NULL, NULL);
    pj_ice_strans_set_stun_domain(NULL, NULL, NULL);
    pj_ice_strans_create_comp(NULL, 0, 0, NULL);
    pj_ice_strans_add_cand(NULL, 0, PJ_ICE_CAND_TYPE_HOST, 0, NULL, PJ_FALSE);
    pj_ice_strans_init_ice(NULL, PJ_ICE_SESS_ROLE_CONTROLLED, NULL, NULL);
    pj_ice_strans_start_ice(NULL, NULL, NULL, 0, NULL);
    pj_ice_strans_stop_ice(NULL);
    pj_ice_strans_sendto(NULL, 0, NULL, 0, NULL, 0);
#endif

#ifdef HAS_PJSIP_CORE_MSG_ELEM
    /* Parameter container */
    pjsip_param_find(NULL, NULL);
    pjsip_param_print_on(NULL, NULL, 0, NULL, NULL, 0);

    /* SIP URI */
    pjsip_sip_uri_create(NULL, 0);
    pjsip_name_addr_create(NULL);

    /* TEL URI */
    pjsip_tel_uri_create(NULL);

    /* Message and headers */
    pjsip_msg_create(NULL, PJSIP_REQUEST_MSG);
    pjsip_msg_print(NULL, NULL, 0);
    pjsip_accept_hdr_create(NULL);
    pjsip_allow_hdr_create(NULL);
    pjsip_cid_hdr_create(NULL);
    pjsip_clen_hdr_create(NULL);
    pjsip_cseq_hdr_create(NULL);
    pjsip_contact_hdr_create(NULL);
    pjsip_ctype_hdr_create(NULL);
    pjsip_expires_hdr_create(NULL, 0);
    pjsip_from_hdr_create(NULL);
    pjsip_max_fwd_hdr_create(NULL, 0);
    pjsip_min_expires_hdr_create(NULL, 0);
    pjsip_rr_hdr_create(NULL);
    pjsip_require_hdr_create(NULL);
    pjsip_retry_after_hdr_create(NULL, 0);
    pjsip_supported_hdr_create(NULL);
    pjsip_unsupported_hdr_create(NULL);
    pjsip_via_hdr_create(NULL);
    pjsip_warning_hdr_create(NULL, 0, NULL, NULL);

    pjsip_parse_uri(NULL, NULL, 0, 0);
    pjsip_parse_msg(NULL, NULL, 0, NULL);
    pjsip_parse_rdata(NULL, 0, NULL);
    pjsip_find_msg(NULL, 0, 0, NULL);
#endif

#ifdef HAS_PJSIP_CORE
    pjsip_endpt_create(NULL, NULL, NULL);

    pjsip_tpmgr_create(NULL, NULL, NULL, NULL, NULL);
    pjsip_tpmgr_destroy(NULL);
    pjsip_transport_send(NULL, NULL, NULL, 0, NULL, NULL);


#endif

#ifdef HAS_PJSIP_CORE_MSG_UTIL
    pjsip_endpt_create_request(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
			       -1, NULL, NULL);
    pjsip_endpt_create_request_from_hdr(NULL, NULL, NULL, NULL, NULL, NULL,
					NULL, -1, NULL, NULL);
    pjsip_endpt_create_response(NULL, NULL, -1, NULL, NULL);
    pjsip_endpt_create_ack(NULL, NULL, NULL, NULL);
    pjsip_endpt_create_cancel(NULL, NULL, NULL);
    pjsip_get_request_dest(NULL, NULL);
    pjsip_endpt_send_request_stateless(NULL, NULL, NULL, NULL);
    pjsip_get_response_addr(NULL, NULL, NULL);
    pjsip_endpt_send_response(NULL, NULL, NULL, NULL, NULL);
    pjsip_endpt_respond_stateless(NULL, NULL, -1, NULL, NULL, NULL);
#endif

#ifdef HAS_PJSIP_UDP_TRANSPORT
    pjsip_udp_transport_start(NULL, NULL, NULL, 1, NULL);
#endif

#ifdef HAS_PJSIP_TCP_TRANSPORT
    pjsip_tcp_transport_start(NULL, NULL, 1, NULL);
#endif

#ifdef HAS_PJSIP_TLS_TRANSPORT
    pjsip_tls_transport_start(NULL, NULL, NULL, NULL, 0, NULL);
#endif

#ifdef HAS_PJSIP_TRANSACTION
    pjsip_tsx_layer_init_module(NULL);

    pjsip_tsx_layer_destroy();
    pjsip_tsx_create_uac(NULL, NULL, NULL);
    pjsip_tsx_create_uas(NULL, NULL, NULL);
    pjsip_tsx_recv_msg(NULL, NULL);
    pjsip_tsx_send_msg(NULL, NULL);
    pjsip_tsx_terminate(NULL, 200);

    pjsip_endpt_send_request(NULL, NULL, -1, NULL, NULL);
    pjsip_endpt_respond(NULL, NULL, NULL, -1, NULL, NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_SDP
    pjmedia_sdp_parse(NULL, NULL, 1024, NULL);
    pjmedia_sdp_print(NULL, NULL, 1024);
    pjmedia_sdp_validate(NULL);
    pjmedia_sdp_session_clone(NULL, NULL);
    pjmedia_sdp_session_cmp(NULL, NULL, 0);
    pjmedia_sdp_attr_to_rtpmap(NULL, NULL, NULL);
    pjmedia_sdp_attr_get_fmtp(NULL, NULL);
    pjmedia_sdp_attr_get_rtcp(NULL, NULL);
    pjmedia_sdp_conn_clone(NULL, NULL);
    pjmedia_sdp_media_clone(NULL, NULL);
    pjmedia_sdp_media_find_attr(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_SDP_NEGOTIATOR
    pjmedia_sdp_neg_create_w_local_offer(NULL, NULL, NULL);
    pjmedia_sdp_neg_create_w_remote_offer(NULL, NULL, NULL, NULL);
    pjmedia_sdp_neg_get_state(NULL);
    pjmedia_sdp_neg_negotiate(NULL, NULL, PJ_FALSE);
#endif

#ifdef HAS_PJSIP_UA_LAYER
    pjsip_ua_init_module(NULL, NULL);
    pjsip_ua_destroy();
    pjsip_dlg_create_uac(NULL, NULL, NULL, NULL, NULL, NULL);
    pjsip_dlg_create_uas_and_inc_lock(NULL, NULL, NULL, NULL);
    pjsip_dlg_terminate(NULL);
    pjsip_dlg_set_route_set(NULL, NULL);
    pjsip_dlg_create_request(NULL, NULL, -1, NULL);
    pjsip_dlg_send_request(NULL, NULL, -1, NULL);
    pjsip_dlg_create_response(NULL, NULL, -1, NULL, NULL);
    pjsip_dlg_modify_response(NULL, NULL, -1, NULL);
    pjsip_dlg_send_response(NULL, NULL, NULL);
    pjsip_dlg_respond(NULL, NULL, -1, NULL, NULL, NULL);
#endif

#ifdef HAS_PJSIP_AUTH_CLIENT
    pjsip_auth_clt_init(NULL, NULL, NULL, 0);
    pjsip_auth_clt_clone(NULL, NULL, NULL);
    pjsip_auth_clt_set_credentials(NULL, 0, NULL);
    pjsip_auth_clt_init_req(NULL, NULL);
    pjsip_auth_clt_reinit_req(NULL, NULL, NULL, NULL);
#endif

#ifdef HAS_PJSIP_INV_SESSION
    pjsip_inv_usage_init(NULL, NULL);
    pjsip_inv_create_uac(NULL, NULL, 0, NULL);
    pjsip_inv_verify_request(NULL, NULL, NULL, NULL, NULL, NULL);
    pjsip_inv_create_uas(NULL, NULL, NULL, 0, NULL);
    pjsip_inv_terminate(NULL, 200, PJ_FALSE);
    pjsip_inv_invite(NULL, NULL);
    pjsip_inv_initial_answer(NULL, NULL, 200, NULL, NULL, NULL);
    pjsip_inv_answer(NULL, 200, NULL, NULL, NULL);
    pjsip_inv_end_session(NULL, 200, NULL, NULL);
    pjsip_inv_reinvite(NULL, NULL, NULL, NULL);
    pjsip_inv_update(NULL, NULL, NULL, NULL);
    pjsip_inv_send_msg(NULL, NULL);
    pjsip_dlg_get_inv_session(NULL);
    //pjsip_tsx_get_inv_session(NULL);
    pjsip_inv_state_name(PJSIP_INV_STATE_NULL);
#endif

#ifdef HAS_PJSIP_REGC
    //pjsip_regc_get_module();
    pjsip_regc_create(NULL, NULL, NULL, NULL);
    pjsip_regc_destroy(NULL);
    pjsip_regc_get_info(NULL, NULL);
    pjsip_regc_get_pool(NULL);
    pjsip_regc_init(NULL, NULL, NULL, NULL, 0, NULL, 600);
    pjsip_regc_set_credentials(NULL, 1, NULL);
    pjsip_regc_set_route_set(NULL, NULL);
    pjsip_regc_register(NULL, PJ_TRUE, NULL);
    pjsip_regc_unregister(NULL, NULL);
    pjsip_regc_update_contact(NULL, 10, NULL);
    pjsip_regc_update_expires(NULL, 600);
    pjsip_regc_send(NULL, NULL);
#endif

#ifdef HAS_PJSIP_EVENT_FRAMEWORK
    pjsip_evsub_init_module(NULL);
    pjsip_evsub_instance();
    pjsip_evsub_register_pkg(NULL, NULL, 30, 10, NULL);
    pjsip_evsub_create_uac(NULL, NULL, NULL, 10, NULL);
    pjsip_evsub_create_uas(NULL, NULL, NULL, 10, NULL);
    pjsip_evsub_terminate(NULL, PJ_FALSE);
    pjsip_evsub_get_state(NULL);
    pjsip_evsub_get_state_name(NULL);
    pjsip_evsub_initiate(NULL, NULL, -1, NULL);
    pjsip_evsub_accept(NULL, NULL, 200, NULL);
    pjsip_evsub_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, NULL);
    pjsip_evsub_current_notify(NULL, NULL);
    pjsip_evsub_send_request(NULL, NULL);
    pjsip_tsx_get_evsub(NULL);
    pjsip_evsub_set_mod_data(NULL, 1, NULL);
    pjsip_evsub_get_mod_data(NULL, 1);
#endif

#ifdef HAS_PJSIP_CALL_TRANSFER
    pjsip_xfer_init_module(NULL);
    pjsip_xfer_create_uac(NULL, NULL, NULL);
    pjsip_xfer_create_uas(NULL, NULL, NULL, NULL);
    pjsip_xfer_initiate(NULL, NULL, NULL);
    pjsip_xfer_accept(NULL, NULL, 200, NULL);
    pjsip_xfer_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, 200, NULL, NULL);
    pjsip_xfer_current_notify(NULL, NULL);
    pjsip_xfer_send_request(NULL, NULL);
#endif

#ifdef HAS_PJSIP_PRESENCE
    pjsip_pres_init_module(NULL, NULL);
    pjsip_pres_instance();
    pjsip_pres_create_uac(NULL, NULL, 0, NULL);
    pjsip_pres_create_uas(NULL, NULL, NULL, NULL);
    pjsip_pres_terminate(NULL, PJ_FALSE);
    pjsip_pres_initiate(NULL, 100, NULL);
    pjsip_pres_accept(NULL, NULL, 200, NULL);
    pjsip_pres_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, NULL);
    pjsip_pres_current_notify(NULL, NULL);
    pjsip_pres_send_request(NULL, NULL);
    pjsip_pres_get_status(NULL, NULL);
    pjsip_pres_set_status(NULL, NULL);
#endif

#ifdef HAS_PJSIP_IS_COMPOSING
    pjsip_iscomposing_create_xml(NULL, PJ_TRUE, NULL, NULL, 0);
    pjsip_iscomposing_create_body(NULL, PJ_TRUE, NULL, NULL, 0);
    pjsip_iscomposing_parse(NULL, NULL, 0, NULL, NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA
    pjmedia_endpt_create(NULL, NULL, 1, NULL);
    pjmedia_endpt_destroy(NULL);
    pjmedia_endpt_create_sdp(NULL, NULL, 1, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_EC
    pjmedia_echo_create(NULL, 0, 0, 0, 0, 0, NULL);
    pjmedia_echo_destroy(NULL);
    pjmedia_echo_playback(NULL, NULL);
    pjmedia_echo_capture(NULL, NULL, 0);
    pjmedia_echo_cancel(NULL, NULL, NULL, 0, NULL);
#endif

#ifdef HAS_PJMEDIA_SND_DEV
    pjmedia_snd_init(NULL);
    pjmedia_snd_get_dev_count();
    pjmedia_snd_get_dev_info(0);
    pjmedia_snd_open(-1, -1, 8000, 1, 80, 16, NULL, NULL, NULL, NULL);
    pjmedia_snd_open_rec(-1, 8000, 1, 160, 16, NULL, NULL, NULL);
    pjmedia_snd_open_player(-1, 8000, 1, 160, 16, NULL, NULL, NULL);
    pjmedia_snd_stream_start(NULL);
    pjmedia_snd_stream_stop(NULL);
    pjmedia_snd_stream_close(NULL);
    pjmedia_snd_deinit();
#endif

#ifdef HAS_PJMEDIA_SND_PORT
    pjmedia_snd_port_create(NULL, -1, -1, 8000, 1, 180, 16, 0, NULL);
    pjmedia_snd_port_create_rec(NULL, -1, 8000, 1, 160, 16, 0, NULL);
    pjmedia_snd_port_create_player(NULL, -1, 8000, 1, 160, 16, 0, NULL);
    pjmedia_snd_port_destroy(NULL);
    pjmedia_snd_port_get_snd_stream(NULL);
    pjmedia_snd_port_connect(NULL, NULL);
    pjmedia_snd_port_get_port(NULL);
    pjmedia_snd_port_disconnect(NULL);
#endif

#ifdef HAS_PJMEDIA_RESAMPLE
    pjmedia_resample_create(NULL, PJ_TRUE, PJ_TRUE, 0, 0, 0, 0, NULL);
    pjmedia_resample_run(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_SILENCE_DET
    pjmedia_silence_det_create(NULL, 8000, 80, NULL);
    pjmedia_silence_det_detect(NULL, NULL, 0, NULL);
    pjmedia_silence_det_apply(NULL, 0);
#endif

#ifdef HAS_PJMEDIA_PLC
    pjmedia_plc_create(NULL, 8000, 80, 0, NULL);
    pjmedia_plc_save(NULL, NULL);
    pjmedia_plc_generate(NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_CONFERENCE
    pjmedia_conf_create(NULL, 10, 8000, 1, 160, 16, 0, NULL);
    pjmedia_conf_destroy(NULL);
    pjmedia_conf_get_master_port(NULL);
    pjmedia_conf_add_port(NULL, NULL, NULL, NULL, NULL);
    pjmedia_conf_configure_port(NULL, 1, 0, 0);
    pjmedia_conf_connect_port(NULL, 0, 0, 0);
    pjmedia_conf_disconnect_port(NULL, 0, 0);
    pjmedia_conf_remove_port(NULL, 0);
    pjmedia_conf_enum_ports(NULL, NULL, NULL);
    pjmedia_conf_get_port_info(NULL, 0, NULL);
    pjmedia_conf_get_ports_info(NULL, NULL, NULL);
    pjmedia_conf_get_signal_level(NULL, 0, NULL, NULL);
    pjmedia_conf_adjust_rx_level(NULL, 0, 0);
    pjmedia_conf_adjust_tx_level(NULL, 0, 0);
#endif

#ifdef HAS_PJMEDIA_MASTER_PORT
    pjmedia_master_port_create(NULL, NULL, NULL, 0, NULL);
    pjmedia_master_port_start(NULL);
    pjmedia_master_port_stop(NULL);
    pjmedia_master_port_set_uport(NULL, NULL);
    pjmedia_master_port_get_uport(NULL);
    pjmedia_master_port_set_dport(NULL, NULL);
    pjmedia_master_port_get_dport(NULL);
    pjmedia_master_port_destroy(NULL, PJ_FALSE);
#endif

#ifdef HAS_PJMEDIA_RTP
    pjmedia_rtp_session_init(NULL, 0, 0);
    pjmedia_rtp_encode_rtp(NULL, 0, 0, 0, 0, NULL, NULL);
    pjmedia_rtp_decode_rtp(NULL, NULL, 0, NULL, NULL, NULL);
    pjmedia_rtp_session_update(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_RTCP
    pjmedia_rtcp_init(NULL, NULL, 0, 0, 0);
    pjmedia_rtcp_get_ntp_time(NULL, NULL);
    pjmedia_rtcp_fini(NULL);
    pjmedia_rtcp_rx_rtp(NULL, 0, 0, 0);
    pjmedia_rtcp_tx_rtp(NULL, 0);
    pjmedia_rtcp_rx_rtcp(NULL, NULL, 0);
    pjmedia_rtcp_build_rtcp(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_JBUF
    pjmedia_jbuf_create(NULL, NULL, 0, 0, 0, NULL);
    pjmedia_jbuf_set_fixed(NULL, 0);
    pjmedia_jbuf_set_adaptive(NULL, 0, 0, 0);
    pjmedia_jbuf_destroy(NULL);
    pjmedia_jbuf_put_frame(NULL, NULL, 0, 0);
    pjmedia_jbuf_get_frame(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_STREAM
    pjmedia_stream_create(NULL, NULL, NULL, NULL, NULL, NULL);
    pjmedia_stream_destroy(NULL);
    pjmedia_stream_get_port(NULL, NULL);
    pjmedia_stream_get_transport(NULL);
    pjmedia_stream_start(NULL);
    pjmedia_stream_get_stat(NULL, NULL);
    pjmedia_stream_pause(NULL, PJMEDIA_DIR_ENCODING);
    pjmedia_stream_resume(NULL, PJMEDIA_DIR_ENCODING);
    pjmedia_stream_dial_dtmf(NULL, NULL);
    pjmedia_stream_check_dtmf(NULL);
    pjmedia_stream_get_dtmf(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_TONEGEN
    pjmedia_tonegen_create(NULL, 0, 0, 0, 0, 0, NULL);
    pjmedia_tonegen_is_busy(NULL);
    pjmedia_tonegen_stop(NULL);
    pjmedia_tonegen_play(NULL, 0, NULL, 0);
    pjmedia_tonegen_play_digits(NULL, 0, NULL, 0);
    pjmedia_tonegen_get_digit_map(NULL, NULL);
    pjmedia_tonegen_set_digit_map(NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_UDP_TRANSPORT
    pjmedia_transport_udp_create(NULL, NULL, 0, 0, NULL);
    pjmedia_transport_udp_close(NULL);
#endif

#ifdef HAS_PJMEDIA_FILE_PLAYER
    pjmedia_wav_player_port_create(NULL, NULL, 0, 0, 0, NULL);
    pjmedia_wav_player_port_set_pos(NULL, 0);
    pjmedia_wav_player_port_get_pos(NULL);
    pjmedia_wav_player_set_eof_cb(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_FILE_CAPTURE
    pjmedia_wav_writer_port_create(NULL, NULL, 8000, 1, 80, 16, 0, 0, NULL);
    pjmedia_wav_writer_port_get_pos(NULL);
    pjmedia_wav_writer_port_set_cb(NULL, 0, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_MEM_PLAYER
    pjmedia_mem_player_create(NULL, NULL, 1000, 8000, 1, 80, 16, 0, NULL);
#endif

#ifdef HAS_PJMEDIA_MEM_CAPTURE
    pjmedia_mem_capture_create(NULL, NULL, 1000, 8000, 1, 80, 16, 0, NULL);
#endif

#ifdef HAS_PJMEDIA_ICE
    pjmedia_ice_create(NULL, NULL, 0, NULL, NULL);
    pjmedia_ice_destroy(NULL);
    pjmedia_ice_start_init(NULL, 0, NULL, NULL, NULL);
    pjmedia_ice_init_ice(NULL, PJ_ICE_SESS_ROLE_CONTROLLED, NULL, NULL);
    pjmedia_ice_modify_sdp(NULL, NULL, NULL);
    pjmedia_ice_start_ice(NULL, NULL, NULL, 0);
    pjmedia_ice_stop_ice(NULL);
#endif

#ifdef HAS_PJMEDIA_G711_CODEC
    pjmedia_codec_g711_init(NULL);
    pjmedia_codec_g711_deinit();
#endif

#ifdef HAS_PJMEDIA_GSM_CODEC
    pjmedia_codec_gsm_init(NULL);
    pjmedia_codec_gsm_deinit();
#endif

#ifdef HAS_PJMEDIA_SPEEX_CODEC
    pjmedia_codec_speex_init(NULL, 0, 0, 0);
    pjmedia_codec_speex_deinit();
#endif

#ifdef HAS_PJMEDIA_ILBC_CODEC
    pjmedia_codec_ilbc_init(NULL, 0);
    pjmedia_codec_ilbc_deinit();
#endif

    return 0;
}