[Asterisk-code-review] res_pjsip_geolocation: Initial commit (asterisk[development/16/geolocation])
George Joseph
asteriskteam at digium.com
Fri Mar 25 06:34:16 CDT 2022
George Joseph has submitted this change. ( https://gerrit.asterisk.org/c/asterisk/+/18191 )
Change subject: res_pjsip_geolocation: Initial commit
......................................................................
res_pjsip_geolocation: Initial commit
* Added two parameters to endpoint: geoloc_incoming_call_profile
and geoloc_outgoing_call_profile. Alembic included. res_pjsip
now has a use/optional dependency on res_geolocation for
validation.
* Added the res_pjsip_geolocation module with support for incoming
calls.
* Fixed ast_datastore_free so it's tolerant of being passed a
NULL pointer. This makes it RAII_VAR compatible.
* Added PJSTR_PRINTF_SPEC and PJSTR_PRINTF_VAR(_v) convenience
macros to res_pjsip.h.
ast_log(LOG_ERROR, "some pjstr value: " PJSTR_PRINTF_SPEC "\n",
PJSTR_PRINTF_VAR(&some_pjstr));
* Did more renames of functions and files.
Change-Id: I6ccb5108a5eec060efb8116502fbff3cc63d7554
---
M configs/samples/pjsip.conf.sample
A contrib/ast-db-manage/config/versions/7197536bb68d_geoloc_endpoint_params.py
M include/asterisk/res_geolocation.h
M include/asterisk/res_pjsip.h
M main/datastore.c
M res/res_geolocation.c
D res/res_geolocation/geoloc_channel.c
M res/res_geolocation/geoloc_config.c
A res/res_geolocation/geoloc_datastore.c
M res/res_geolocation/geoloc_eprofile.c
M res/res_pjsip.c
M res/res_pjsip/pjsip_config.xml
M res/res_pjsip/pjsip_configuration.c
A res/res_pjsip_geolocation.c
14 files changed, 777 insertions(+), 121 deletions(-)
Approvals:
George Joseph: Looks good to me, approved; Approved for Submit
diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample
index 8118086..97d1e73 100644
--- a/configs/samples/pjsip.conf.sample
+++ b/configs/samples/pjsip.conf.sample
@@ -898,6 +898,17 @@
; responses.
; (default: no)
+;geoloc_incoming_call_profile =
+ ; This geolocation profile will be applied to all calls received
+ ; by the channel driver from the remote endpoint before they're
+ ; forwarded to the dialplan.
+;geoloc_outgoing_call_profile =
+ ; This geolocation profile will be applied to all calls received
+ ; by the channel driver from the dialplan before they're forwarded
+ ; the remote endpoint.
+;
+
+
;==========================AUTH SECTION OPTIONS=========================
;[auth]
; SYNOPSIS: Authentication type
diff --git a/contrib/ast-db-manage/config/versions/7197536bb68d_geoloc_endpoint_params.py b/contrib/ast-db-manage/config/versions/7197536bb68d_geoloc_endpoint_params.py
new file mode 100644
index 0000000..bf9de50
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/7197536bb68d_geoloc_endpoint_params.py
@@ -0,0 +1,22 @@
+"""Geoloc Endpoint Params
+
+Revision ID: 7197536bb68d
+Revises: 8f72185e437f
+Create Date: 2022-03-07 05:32:54.909429
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '7197536bb68d'
+down_revision = '8f72185e437f'
+
+from alembic import op
+import sqlalchemy as sa
+
+def upgrade():
+ op.add_column('ps_endpoints', sa.Column('geoloc_incoming_call_profile', sa.String(80)))
+ op.add_column('ps_endpoints', sa.Column('geoloc_outgoing_call_profile', sa.String(80)))
+
+def downgrade():
+ op.drop_column('ps_endpoints', 'geoloc_outgoing_call_profile')
+ op.drop_column('ps_endpoints', 'geoloc_incoming_call_profile')
diff --git a/include/asterisk/res_geolocation.h b/include/asterisk/res_geolocation.h
index 7fae4bf..80f1caf 100644
--- a/include/asterisk/res_geolocation.h
+++ b/include/asterisk/res_geolocation.h
@@ -22,6 +22,7 @@
#include "asterisk/sorcery.h"
#include "asterisk/config.h"
#include "asterisk/xml.h"
+#include "asterisk/optional_api.h"
enum ast_geoloc_pidf_element {
AST_PIDF_ELEMENT_NONE = 0,
@@ -67,7 +68,7 @@
struct ast_variable *usage_rules_vars;
};
-struct ast_geoloc_effective_profile {
+struct ast_geoloc_eprofile {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(id);
AST_STRING_FIELD(location_reference);
@@ -85,6 +86,34 @@
struct ast_variable *usage_rules_vars;
};
+/*!
+ * \brief Check if res_geolocation is available
+ *
+ * \return 1 if available, 0 otherwise.
+ */
+AST_OPTIONAL_API(int, ast_geoloc_is_loaded, (void), { return 0; });
+
+/*!
+ * \brief Retrieve a geolocation location object by id.
+ *
+ * \param id Location object id.
+ *
+ * \return Location object or NULL if not found.
+ */
+AST_OPTIONAL_API(struct ast_geoloc_location *, ast_geoloc_get_location,
+ (const char *id),
+ { return NULL; });
+
+/*!
+ * \brief Retrieve a geolocation profile by id.
+ *
+ * \param id profile id.
+ *
+ * \return Profile or NULL if not found.
+ */
+AST_OPTIONAL_API(struct ast_geoloc_profile *, ast_geoloc_get_profile,
+ (const char *id),
+ { return NULL; });
/*!
* \brief Given an official civicAddress code, return its friendly name.
@@ -164,7 +193,13 @@
* \return The datastore.
*/
struct ast_datastore *ast_geoloc_datastore_create_from_eprofile(
- struct ast_geoloc_effective_profile *eprofile);
+ struct ast_geoloc_eprofile *eprofile);
+
+struct ast_datastore *ast_geoloc_datastore_create(const char *id);
+int ast_geoloc_datastore_add_eprofile(struct ast_datastore *ds,
+ struct ast_geoloc_eprofile *eprofile);
+int ast_geoloc_datastore_size(struct ast_datastore *ds);
+struct ast_geoloc_eprofile *ast_geoloc_datastore_get_eprofile(struct ast_datastore *ds, int ix);
/*!
* \brief Allocate a new, empty effective profile.
@@ -173,7 +208,7 @@
*
* \return The effective profile ao2 object.
*/
-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_alloc(const char *name);
+struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name);
/*!
* \brief Allocate a new effective profile from an existing profile.
@@ -182,7 +217,7 @@
*
* \return The effective profile ao2 object.
*/
-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile);
+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile);
/*!
* \brief Allocate a new effective profile from an XML PIDF-LO document
@@ -192,7 +227,7 @@
*
* \return The effective profile ao2 object.
*/
-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_pidf(
+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(
struct ast_xml_doc *pidf_xmldoc, const char *reference_string);
/*!
@@ -203,7 +238,7 @@
*
* \return The effective profile ao2 object.
*/
-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_uri(const char *uri,
+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_uri(const char *uri,
const char *reference_string);
/*!
@@ -213,6 +248,6 @@
*
* \return 0 on success, any other value on error.
*/
-int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_effective_profile *eprofile);
+int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile);
#endif /* INCLUDE_ASTERISK_RES_GEOLOCATION_H_ */
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index a4d0607..40e13e2 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -62,6 +62,9 @@
#define PJSIP_EXPIRES_NOT_SPECIFIED ((pj_uint32_t)-1)
#endif
+#define PJSTR_PRINTF_SPEC "%.*s"
+#define PJSTR_PRINTF_VAR(_v) ((int)(_v).slen), ((_v).ptr)
+
/* Response codes from RFC8224 */
#define AST_STIR_SHAKEN_RESPONSE_CODE_STALE_DATE 403
#define AST_STIR_SHAKEN_RESPONSE_CODE_USE_IDENTITY_HEADER 428
@@ -871,6 +874,10 @@
unsigned int stir_shaken;
/*! Should we authenticate OPTIONS requests per RFC 3261? */
unsigned int allow_unauthenticated_options;
+ /*! The name of the geoloc profile to apply when Asterisk receives a call from this endpoint */
+ AST_STRING_FIELD_EXTENDED(geoloc_incoming_call_profile);
+ /*! The name of the geoloc profile to apply when Asterisk sends a call to this endpoint */
+ AST_STRING_FIELD_EXTENDED(geoloc_outgoing_call_profile);
};
/*! URI parameter for symmetric transport */
diff --git a/main/datastore.c b/main/datastore.c
index f37ee6c..d5adfae 100644
--- a/main/datastore.c
+++ b/main/datastore.c
@@ -69,6 +69,10 @@
{
int res = 0;
+ if (!datastore) {
+ return 0;
+ }
+
/* Using the destroy function (if present) destroy the data */
if (datastore->info->destroy != NULL && datastore->data != NULL) {
datastore->info->destroy(datastore->data);
diff --git a/res/res_geolocation.c b/res/res_geolocation.c
index 9108102..19dd84b 100644
--- a/res/res_geolocation.c
+++ b/res/res_geolocation.c
@@ -24,6 +24,8 @@
#include "asterisk.h"
+#define AST_API_MODULE
+#include "asterisk/res_geolocation.h"
#include "res_geolocation/geoloc_private.h"
static int reload_module(void)
diff --git a/res/res_geolocation/geoloc_channel.c b/res/res_geolocation/geoloc_channel.c
deleted file mode 100644
index aa8ad87..0000000
--- a/res/res_geolocation/geoloc_channel.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2022, Sangoma Technologies Corporation
- *
- * George Joseph <gjoseph at sangoma.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#include "asterisk.h"
-#include "asterisk/datastore.h"
-#include "asterisk/res_geolocation.h"
-#include "geoloc_private.h"
-
-
-struct ast_sorcery *geoloc_sorcery;
-
-static void geoloc_datastore_destructor(void *obj)
-{
- struct ast_geoloc_effective_profile *eprofile = obj;
- ao2_ref(eprofile, -1);
-}
-
-
-static const struct ast_datastore_info geoloc_datastore_info = {
- .type = "geolocation",
- .destroy = geoloc_datastore_destructor
-};
-
-
-struct ast_datastore *ast_geoloc_datastore_create_from_profile_name(const char *profile_name)
-{
- struct ast_datastore *ds = NULL;
- struct ast_geoloc_effective_profile *eprofile = NULL;
- struct ast_geoloc_profile *profile = NULL;
-
- if (ast_strlen_zero(profile_name)) {
- return NULL;
- }
-
- ds = ast_datastore_alloc(&geoloc_datastore_info, NULL);
- if (!ds) {
- ast_log(LOG_ERROR, "A datasatore couldn't be allocated for profile '%s'", profile_name);
- return NULL;
- }
-
- profile = ast_sorcery_retrieve_by_id(geoloc_sorcery, "profile", profile_name);
- if (!profile) {
- ast_datastore_free(ds);
- ast_log(LOG_ERROR, "A profile with the name '%s' was not found", profile_name);
- return NULL;
- }
-
- eprofile = ast_geoloc_eprofile_create_from_profile(profile);
- ao2_ref(profile, -1);
- if (!eprofile) {
- ast_datastore_free(ds);
- ast_log(LOG_ERROR, "An effective profile with the name '%s' couldn't be allocated", profile_name);
- return NULL;
- }
-
- ds->data = eprofile;
-
- return ds;
-}
-
-int geoloc_channel_unload(void)
-{
- if (geoloc_sorcery) {
- ast_sorcery_unref(geoloc_sorcery);
- }
- return AST_MODULE_LOAD_SUCCESS;
-}
-
-int geoloc_channel_load(void)
-{
- geoloc_sorcery = geoloc_get_sorcery();
- return AST_MODULE_LOAD_SUCCESS;
-}
-
-int geoloc_channel_reload(void)
-{
- return AST_MODULE_LOAD_SUCCESS;
-}
diff --git a/res/res_geolocation/geoloc_config.c b/res/res_geolocation/geoloc_config.c
index b707c89..309df22 100644
--- a/res/res_geolocation/geoloc_config.c
+++ b/res/res_geolocation/geoloc_config.c
@@ -19,8 +19,8 @@
#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
+#define AST_API_MODULE
#include "geoloc_private.h"
-#include "asterisk/res_geolocation.h"
static struct ast_sorcery *geoloc_sorcery;
@@ -433,7 +433,7 @@
struct ast_str *refinement_str = NULL;
struct ast_str *variables_str = NULL;
struct ast_str *resolved_str = NULL;
- struct ast_geoloc_effective_profile *eprofile = ast_geoloc_eprofile_create_from_profile(profile);
+ struct ast_geoloc_eprofile *eprofile = ast_geoloc_eprofile_create_from_profile(profile);
ao2_ref(profile, -1);
if (!ast_strlen_zero(eprofile->location_reference)) {
@@ -514,6 +514,24 @@
AST_CLI_DEFINE(geoloc_config_cli_reload, "Reload Geolocation Configuration"),
};
+struct ast_geoloc_location * AST_OPTIONAL_API_NAME(ast_geoloc_get_location)(const char *id)
+{
+ if (ast_strlen_zero(id)) {
+ return NULL;
+ }
+
+ return ast_sorcery_retrieve_by_id(geoloc_sorcery, "location", id);
+}
+
+struct ast_geoloc_profile * AST_OPTIONAL_API_NAME(ast_geoloc_get_profile)(const char *id)
+{
+ if (ast_strlen_zero(id)) {
+ return NULL;
+ }
+
+ return ast_sorcery_retrieve_by_id(geoloc_sorcery, "profile", id);
+}
+
int geoloc_config_reload(void)
{
if (geoloc_sorcery) {
@@ -589,3 +607,8 @@
return AST_MODULE_LOAD_SUCCESS;
}
+int AST_OPTIONAL_API_NAME(ast_geoloc_is_loaded)(void)
+{
+ return 1;
+}
+
diff --git a/res/res_geolocation/geoloc_datastore.c b/res/res_geolocation/geoloc_datastore.c
new file mode 100644
index 0000000..17e2847
--- /dev/null
+++ b/res/res_geolocation/geoloc_datastore.c
@@ -0,0 +1,219 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2022, Sangoma Technologies Corporation
+ *
+ * George Joseph <gjoseph at sangoma.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/datastore.h"
+#include "asterisk/res_geolocation.h"
+#include "asterisk/vector.h"
+#include "geoloc_private.h"
+
+#define GEOLOC_DS_TYPE "geoloc_eprofiles"
+
+struct ast_sorcery *geoloc_sorcery;
+
+struct eprofiles_datastore {
+ const char *id;
+ AST_VECTOR(geoloc_eprofiles, struct ast_geoloc_eprofile *) eprofiles;
+};
+
+static void geoloc_datastore_free(void *obj)
+{
+ struct eprofiles_datastore *eds = obj;
+
+ AST_VECTOR_RESET(&eds->eprofiles, ao2_cleanup);
+ AST_VECTOR_FREE(&eds->eprofiles);
+ ast_free(eds);
+}
+
+static const struct ast_datastore_info geoloc_datastore_info = {
+ .type = GEOLOC_DS_TYPE,
+ .destroy = geoloc_datastore_free
+};
+
+struct ast_datastore *ast_geoloc_datastore_create(const char *id)
+{
+ struct ast_datastore *ds = NULL;
+ struct eprofiles_datastore *eds = NULL;
+ int rc = 0;
+
+ if (ast_strlen_zero(id)) {
+ ast_log(LOG_ERROR, "A geoloc datastore can't be allocated with a NULL or empty id\n");
+ return NULL;
+ }
+
+ ds = ast_datastore_alloc(&geoloc_datastore_info, NULL);
+ if (!ds) {
+ ast_log(LOG_ERROR, "Geoloc datastore '%s' couldn't be allocated\n", id);
+ return NULL;
+ }
+
+ eds = ast_calloc(1, sizeof(*eds));
+ if (!eds) {
+ ast_datastore_free(ds);
+ ast_log(LOG_ERROR, "Private structure for geoloc datastore '%s' couldn't be allocated\n", id);
+ return NULL;
+ }
+ ds->data = eds;
+
+
+ rc = AST_VECTOR_INIT(&eds->eprofiles, 2);
+ if (rc != 0) {
+ ast_datastore_free(ds);
+ ast_log(LOG_ERROR, "Vector for geoloc datastore '%s' couldn't be initialized\n", id);
+ return NULL;
+ }
+
+ return ds;
+}
+
+int ast_geoloc_datastore_add_eprofile(struct ast_datastore *ds,
+ struct ast_geoloc_eprofile *eprofile)
+{
+ struct eprofiles_datastore *eds = NULL;
+ int rc = 0;
+
+ if (!ds || !ast_strings_equal(ds->info->type, GEOLOC_DS_TYPE) || !ds->data || !eprofile) {
+ return -1;
+ }
+
+ eds = ds->data;
+ rc = AST_VECTOR_APPEND(&eds->eprofiles, eprofile);
+ if (rc != 0) {
+ ast_log(LOG_ERROR, "Couldn't add eprofile '%s' to geoloc datastore '%s'\n", eprofile->id, eds->id);
+ }
+
+ return rc;
+}
+
+int ast_geoloc_datastore_size(struct ast_datastore *ds)
+{
+ struct eprofiles_datastore *eds = NULL;
+
+ if (!ds || !ast_strings_equal(ds->info->type, GEOLOC_DS_TYPE) || !ds->data) {
+ return -1;
+ }
+
+ eds = ds->data;
+
+ return AST_VECTOR_SIZE(&eds->eprofiles);
+}
+
+struct ast_geoloc_eprofile *ast_geoloc_datastore_get_eprofile(struct ast_datastore *ds, int ix)
+{
+ struct eprofiles_datastore *eds = NULL;
+ struct ast_geoloc_eprofile *eprofile;
+
+ if (!ds || !ast_strings_equal(ds->info->type, GEOLOC_DS_TYPE) || !ds->data) {
+ return NULL;
+ }
+
+ eds = ds->data;
+
+ if (ix >= AST_VECTOR_SIZE(&eds->eprofiles)) {
+ return NULL;
+ }
+
+ eprofile = AST_VECTOR_GET(&eds->eprofiles, ix);
+ return ao2_bump(eprofile);
+}
+
+struct ast_datastore *ast_geoloc_datastore_create_from_eprofile(
+ struct ast_geoloc_eprofile *eprofile)
+{
+ struct ast_datastore *ds;
+ int rc = 0;
+
+ if (!eprofile) {
+ return NULL;
+ }
+
+ ds = ast_geoloc_datastore_create(eprofile->id);
+ if (!ds) {
+ return NULL;
+ }
+
+ rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
+ if (rc != 0) {
+ ast_datastore_free(ds);
+ ds = NULL;
+ }
+
+ return ds;
+}
+
+struct ast_datastore *ast_geoloc_datastore_create_from_profile_name(const char *profile_name)
+{
+ struct ast_datastore *ds = NULL;
+ struct ast_geoloc_eprofile *eprofile = NULL;
+ struct ast_geoloc_profile *profile = NULL;
+ int rc = 0;
+
+ if (ast_strlen_zero(profile_name)) {
+ return NULL;
+ }
+
+ profile = ast_sorcery_retrieve_by_id(geoloc_sorcery, "profile", profile_name);
+ if (!profile) {
+ ast_log(LOG_ERROR, "A profile with the name '%s' was not found\n", profile_name);
+ return NULL;
+ }
+
+ ds = ast_geoloc_datastore_create(profile_name);
+ if (!ds) {
+ ast_log(LOG_ERROR, "A datasatore couldn't be allocated for profile '%s'\n", profile_name);
+ ao2_ref(profile, -1);
+ return NULL;
+ }
+
+ eprofile = ast_geoloc_eprofile_create_from_profile(profile);
+ ao2_ref(profile, -1);
+ if (!eprofile) {
+ ast_datastore_free(ds);
+ ast_log(LOG_ERROR, "An effective profile with the name '%s' couldn't be allocated\n", profile_name);
+ return NULL;
+ }
+
+ rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
+ ao2_ref(eprofile, -1);
+ if (rc != 0) {
+ ast_datastore_free(ds);
+ ds = NULL;
+ }
+
+ return ds;
+}
+
+int geoloc_channel_unload(void)
+{
+ if (geoloc_sorcery) {
+ ast_sorcery_unref(geoloc_sorcery);
+ }
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+int geoloc_channel_load(void)
+{
+ geoloc_sorcery = geoloc_get_sorcery();
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+int geoloc_channel_reload(void)
+{
+ return AST_MODULE_LOAD_SUCCESS;
+}
diff --git a/res/res_geolocation/geoloc_eprofile.c b/res/res_geolocation/geoloc_eprofile.c
index b6641c7..3ea0d7d 100644
--- a/res/res_geolocation/geoloc_eprofile.c
+++ b/res/res_geolocation/geoloc_eprofile.c
@@ -32,8 +32,8 @@
static struct ast_sorcery *geoloc_sorcery;
-static void geoloc_effective_profile_destructor(void *obj) {
- struct ast_geoloc_effective_profile *eprofile = obj;
+static void geoloc_eprofile_destructor(void *obj) {
+ struct ast_geoloc_eprofile *eprofile = obj;
ast_string_field_free_memory(eprofile);
ast_variables_destroy(eprofile->location_vars);
@@ -43,10 +43,10 @@
ast_variables_destroy(eprofile->usage_rules_vars);
}
-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_alloc(const char *name)
+struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name)
{
- struct ast_geoloc_effective_profile *eprofile = ao2_alloc_options(sizeof(*eprofile),
- geoloc_effective_profile_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
+ struct ast_geoloc_eprofile *eprofile = ao2_alloc_options(sizeof(*eprofile),
+ geoloc_eprofile_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
ast_string_field_init(eprofile, 256);
ast_string_field_set(eprofile, id, name); /* SAFE string fields handle NULL */
@@ -54,7 +54,7 @@
return eprofile;
}
-int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_effective_profile *eprofile)
+int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile)
{
struct ast_geoloc_location *loc = NULL;
struct ast_variable *var;
@@ -68,13 +68,16 @@
}
eprofile->format = loc->format;
+
ast_variables_destroy(eprofile->location_vars);
- eprofile->location_vars = ast_variables_dup(loc->location_vars);
+ eprofile->location_vars = loc->location_vars ? ast_variables_dup(loc->location_vars) : NULL;
ao2_ref(loc, -1);
+ loc = NULL;
}
ast_variables_destroy(eprofile->effective_location);
- eprofile->effective_location = ast_variables_dup(eprofile->location_vars);
+ eprofile->effective_location = eprofile->location_vars ? ast_variables_dup(eprofile->location_vars) : NULL;
+
if (eprofile->location_refinement) {
for (var = eprofile->location_refinement; var; var = var->next) {
struct ast_variable *newvar = ast_variable_new(var->name, var->value, "");
@@ -101,9 +104,9 @@
(_rc); \
})
-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile)
+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile)
{
- struct ast_geoloc_effective_profile *eprofile;
+ struct ast_geoloc_eprofile *eprofile;
const char *profile_id;
int rc = 0;
@@ -148,10 +151,10 @@
return eprofile;
}
-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_uri(const char *uri,
+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_uri(const char *uri,
const char *reference_string)
{
- struct ast_geoloc_effective_profile *eprofile = NULL;
+ struct ast_geoloc_eprofile *eprofile = NULL;
char *local_uri;
if (ast_strlen_zero(uri)) {
@@ -178,11 +181,11 @@
return eprofile;
}
-static struct ast_geoloc_effective_profile *geoloc_eprofile_create_from_xslt_result(
+static struct ast_geoloc_eprofile *geoloc_eprofile_create_from_xslt_result(
struct ast_xml_doc *result_doc,
const char *reference_string)
{
- struct ast_geoloc_effective_profile *eprofile;
+ struct ast_geoloc_eprofile *eprofile;
struct ast_xml_node *presence = NULL;
struct ast_xml_node *pidf_element = NULL;
struct ast_xml_node *location_info = NULL;
@@ -241,11 +244,11 @@
return eprofile;
}
-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_pidf(
+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(
struct ast_xml_doc *pidf_xmldoc, const char *reference_string)
{
RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);
- struct ast_geoloc_effective_profile *eprofile;
+ struct ast_geoloc_eprofile *eprofile;
/*
* The namespace prefixes used here (dm, def, gp, etc) don't have to match
@@ -361,7 +364,7 @@
AST_TEST_DEFINE(test_create_from_uri)
{
- RAII_VAR(struct ast_geoloc_effective_profile *, eprofile, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);
const char *uri = NULL;
int rc = AST_TEST_PASS;
@@ -399,7 +402,7 @@
)
{
RAII_VAR(struct ast_str *, str, NULL, ast_free);
- RAII_VAR(struct ast_geoloc_effective_profile *, eprofile, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);
RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);
const char *search[] = { "path", path, NULL };
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 1e41360..8900964 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -53,6 +53,7 @@
<depend>res_sorcery_memory</depend>
<depend>res_sorcery_astdb</depend>
<use type="module">res_statsd</use>
+ <use type="module">res_geolocation</use>
<support_level>core</support_level>
***/
@@ -2714,5 +2715,5 @@
.reload = reload_module,
.load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,
.requires = "dnsmgr,res_pjproject,res_sorcery_config,res_sorcery_memory,res_sorcery_astdb",
- .optional_modules = "res_statsd",
+ .optional_modules = "res_geolocation,res_statsd",
);
diff --git a/res/res_pjsip/pjsip_config.xml b/res/res_pjsip/pjsip_config.xml
index 6470ab6..0f7b5c5 100644
--- a/res/res_pjsip/pjsip_config.xml
+++ b/res/res_pjsip/pjsip_config.xml
@@ -1135,6 +1135,24 @@
responses.</para>
</description>
</configOption>
+ <configOption name="geoloc_incoming_call_profile" default="">
+ <synopsis>Geolocation profile to apply to incoming calls</synopsis>
+ <description><para>
+ This geolocation profile will be applied to all calls received
+ by the channel driver from the remote endpoint before they're
+ forwarded to the dialplan.
+ </para>
+ </description>
+ </configOption>
+ <configOption name="geoloc_outgoing_call_profile" default="">
+ <synopsis>Geolocation profile to apply to outgoing calls</synopsis>
+ <description><para>
+ This geolocation profile will be applied to all calls received
+ by the channel driver from the dialplan before they're forwarded
+ the remote endpoint.
+ </para>
+ </description>
+ </configOption>
</configObject>
<configObject name="auth">
<synopsis>Authentication type</synopsis>
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index eccc639..70d2a19 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -21,6 +21,7 @@
#include <pjsip.h>
#include <pjsip_ua.h>
+#include "asterisk/res_geolocation.h"
#include "asterisk/res_pjsip.h"
#include "include/res_pjsip_private.h"
#include "asterisk/res_pjsip_cli.h"
@@ -1370,6 +1371,36 @@
}
}
+ if (!ast_strlen_zero(endpoint->geoloc_incoming_call_profile) ||
+ !ast_strlen_zero(endpoint->geoloc_outgoing_call_profile)) {
+
+ if (!ast_geoloc_is_loaded()) {
+ ast_log(LOG_ERROR, "A geoloc incoming and/or outgoing call_profile was specified on endpoint '%s'"
+ " but res_geolocation is not loaded.\n", ast_sorcery_object_get_id(endpoint));
+ return -1;
+ }
+
+ if (!ast_strlen_zero(endpoint->geoloc_incoming_call_profile)) {
+ struct ast_geoloc_profile *profile = ast_geoloc_get_profile(endpoint->geoloc_incoming_call_profile);
+ if (!profile) {
+ ast_log(LOG_ERROR, "geoloc_incoming_call_profile '%s' on endpoint '%s' doesn't exist\n",
+ endpoint->geoloc_incoming_call_profile, ast_sorcery_object_get_id(endpoint));
+ return -1;
+ }
+ ao2_cleanup(profile);
+ }
+
+ if (!ast_strlen_zero(endpoint->geoloc_outgoing_call_profile)) {
+ struct ast_geoloc_profile *profile = ast_geoloc_get_profile(endpoint->geoloc_outgoing_call_profile);
+ if (!profile) {
+ ast_log(LOG_ERROR, "geoloc_outgoing_call_profile '%s' on endpoint '%s' doesn't exist\n",
+ endpoint->geoloc_outgoing_call_profile, ast_sorcery_object_get_id(endpoint));
+ return -1;
+ }
+ ao2_cleanup(profile);
+ }
+ }
+
return 0;
}
@@ -2008,6 +2039,8 @@
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ignore_183_without_sdp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, ignore_183_without_sdp));
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "stir_shaken", "off", stir_shaken_handler, stir_shaken_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_unauthenticated_options", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_unauthenticated_options));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "geoloc_incoming_call_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, geoloc_incoming_call_profile));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "geoloc_outgoing_call_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, geoloc_outgoing_call_profile));
if (ast_sip_initialize_sorcery_transport()) {
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
@@ -2168,6 +2201,12 @@
return NULL;
}
+ if (ast_string_field_init_extended(endpoint, geoloc_incoming_call_profile) ||
+ ast_string_field_init_extended(endpoint, geoloc_outgoing_call_profile)) {
+ ao2_cleanup(endpoint);
+ return NULL;
+ }
+
if (!(endpoint->media.codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
ao2_cleanup(endpoint);
return NULL;
diff --git a/res/res_pjsip_geolocation.c b/res/res_pjsip_geolocation.c
new file mode 100644
index 0000000..cd8ba79
--- /dev/null
+++ b/res/res_pjsip_geolocation.c
@@ -0,0 +1,365 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2022, Sangoma Technologies Corporation
+ *
+ * George Joseph <gjoseph at sangoma.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <depend>res_geolocation</depend>
+ <depend>pjproject</depend>
+ <depend>res_pjsip</depend>
+ <depend>res_pjsip_session</depend>
+ <depend>chan_pjsip</depend>
+ <depend>libxml2</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+#include "asterisk/module.h"
+#include "asterisk/xml.h"
+#include "asterisk/res_geolocation.h"
+
+#include <pjsip_ua.h>
+#include "asterisk/res_pjsip.h"
+#include "asterisk/res_pjsip_session.h"
+
+static pj_str_t GEOLOCATION_HDR;
+
+static int find_pidf(const char *session_name, struct pjsip_rx_data *rdata, char *geoloc_uri,
+ char **pidf_body, unsigned int *pidf_len)
+{
+ /*
+ * If the URI is "cid" then we're going to search for a pidf document
+ * in the body of the message. If there's no body, there's no point.
+ */
+ if (!rdata->msg_info.msg->body) {
+ ast_log(LOG_WARNING, "%s: There's no message body in which to search for '%s'. Skipping\n",
+ session_name, geoloc_uri);
+ return -1;
+ }
+
+ /*
+ * If the message content type is 'application/pidf+xml', then the pidf is
+ * the only document in the message and we'll just parse the entire body
+ * as xml. If it's 'multipart/mixed' then we have to find the part that
+ * has a Content-ID heder value matching the URI.
+ */
+ if (ast_sip_are_media_types_equal(&rdata->msg_info.ctype->media,
+ &pjsip_media_type_application_pidf_xml)) {
+ *pidf_body = rdata->msg_info.msg->body->data;
+ *pidf_len = rdata->msg_info.msg->body->len;
+ } else if (ast_sip_are_media_types_equal(&rdata->msg_info.ctype->media,
+ &pjsip_media_type_multipart_mixed)) {
+ pj_str_t cid = pj_str(geoloc_uri);
+ pjsip_multipart_part *mp = pjsip_multipart_find_part_by_cid_str(
+ rdata->tp_info.pool, rdata->msg_info.msg->body, &cid);
+
+ if (!mp) {
+ ast_log(LOG_WARNING, "%s: A Geolocation header was found with URI '%s'"
+ " but the associated multipart part was not found in the message body. Skipping URI",
+ session_name, geoloc_uri);
+ return -1;
+ }
+ *pidf_body = mp->body->data;
+ *pidf_len = mp->body->len;
+ } else {
+ ast_log(LOG_WARNING, "%s: A Geolocation header was found with URI '%s'"
+ " but no pidf document with that content id was found. Skipping URI",
+ session_name, geoloc_uri);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int handle_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
+{
+ const char *session_name = ast_sip_session_get_name(session);
+ struct ast_sip_endpoint *endpoint = session->endpoint;
+ struct ast_channel *channel = session->channel;
+ RAII_VAR(struct ast_geoloc_profile *, config_profile, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_geoloc_eprofile *, config_eprofile, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_datastore *, ds, NULL, ast_datastore_free);
+ size_t eprofile_count = 0;
+ char *geoloc_hdr_value = NULL;
+ char *duped_geoloc_hdr_value = NULL;
+ char *geoloc_uri = NULL;
+ int rc = 0;
+ pjsip_generic_string_hdr *geoloc_hdr =
+ pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &GEOLOCATION_HDR, NULL);
+ SCOPE_ENTER(3, "%s\n", session_name);
+
+ if (!endpoint) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING, "%s: Session has no endpoint. Skipping.\n",
+ session_name);
+ }
+
+ if (!channel) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING, "%s: Session has no channel. Skipping.\n",
+ session_name);
+ }
+
+ if (!geoloc_hdr) {
+ ast_trace(4, "%s: Message has no Geolocation header\n", session_name);
+ } else {
+ ast_trace(4, "%s: Geolocation: " PJSTR_PRINTF_SPEC, session_name,
+ PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));
+ }
+
+ if (ast_strlen_zero(endpoint->geoloc_incoming_call_profile)) {
+ if (geoloc_hdr) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Message has Geolocation header '"
+ PJSTR_PRINTF_SPEC "' but endpoint has no geoloc_incoming_call_profile. "
+ "Geolocation info discarded.\n", session_name,
+ PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));
+ } else {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Endpoint has no geoloc_incoming_call_profile. "
+ "Skipping.\n", session_name);
+ }
+ }
+
+ config_profile = ast_geoloc_get_profile(endpoint->geoloc_incoming_call_profile);
+ if (!config_profile) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Message has Geolocation header '"
+ PJSTR_PRINTF_SPEC "' but endpoint's geoloc_incoming_call_profile doesn't exist. "
+ "Geolocation info discarded.\n", session_name,
+ PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));
+ }
+
+ ds = ast_geoloc_datastore_create(session_name);
+ if (!ds) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,
+ "%s: Couldn't allocate a geoloc datastore\n", session_name);
+ }
+
+ if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_DISCARD) {
+ ast_trace(4, "%s: Profile '%s' location_disposition is 'discard' so "
+ "discarding Geolocation: " PJSTR_PRINTF_SPEC, session_name,
+ ast_sorcery_object_get_id(config_profile),
+ PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));
+
+ config_eprofile = ast_geoloc_eprofile_create_from_profile(config_profile);
+ if (!config_eprofile) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING, "%s: Unable to create eprofile from "
+ "profile '%s'\n", session_name, ast_sorcery_object_get_id(config_profile));
+ }
+
+ rc = ast_geoloc_datastore_add_eprofile(ds, config_eprofile);
+ if (rc != 0) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,
+ "%s: Couldn't add eprofile '%s' to datastore\n", session_name,
+ config_eprofile->id);
+ }
+
+ ast_channel_datastore_add(channel, ds);
+ /*
+ * We gave our eprofile reference to the datastore and the
+ * datastore to the channel so don't let RAII_VAR clean them up.
+ */
+ config_eprofile = NULL;
+ ds = NULL;
+
+ SCOPE_EXIT_RTN_VALUE(0, "%s: Added geoloc datastore with 1 eprofile\n",
+ session_name);
+ } else if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_PREPEND) {
+ ast_trace(4, "%s: Profile '%s' location_disposition is 'prepend' so "
+ "adding to datastore first", session_name, ast_sorcery_object_get_id(config_profile));
+
+ config_eprofile = ast_geoloc_eprofile_create_from_profile(config_profile);
+ if (!config_eprofile) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING, "%s: Unable to create eprofile from"
+ " profile '%s'\n", session_name, ast_sorcery_object_get_id(config_profile));
+ }
+
+ rc = ast_geoloc_datastore_add_eprofile(ds, config_eprofile);
+ if (rc != 0) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,
+ "%s: Couldn't add eprofile '%s' to datastore\n", session_name,
+ config_eprofile->id);
+ }
+ config_eprofile = NULL;
+
+ if (!geoloc_hdr) {
+ ast_channel_datastore_add(channel, ds);
+ ds = NULL;
+
+ SCOPE_EXIT_RTN_VALUE(0, "%s: No Geolocation header so just adding config profile "
+ "'%s' to datastore\n", session_name, ast_sorcery_object_get_id(config_profile));
+ }
+ } else if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_REPLACE) {
+ if (geoloc_hdr) {
+ ast_trace(4, "%s: Profile '%s' location_disposition is 'replace' so "
+ "we don't need to do anything with the configured profile", session_name,
+ ast_sorcery_object_get_id(config_profile));
+ } else {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,
+ "%s: Profile '%s' location_disposition is 'replace' but there's"
+ "no Geolocation header and therefore no location info to replace"
+ "it with\n", session_name, ast_sorcery_object_get_id(config_profile));
+ }
+ }
+
+ geoloc_hdr_value = ast_alloca(geoloc_hdr->hvalue.slen + 1);
+ ast_copy_pj_str(geoloc_hdr_value, &geoloc_hdr->hvalue, geoloc_hdr->hvalue.slen + 1);
+ duped_geoloc_hdr_value = ast_strdupa(geoloc_hdr_value);
+
+ /*
+ * From RFC-6442:
+ * Geolocation-header = "Geolocation" HCOLON locationValue
+ * *( COMMA locationValue )
+ * locationValue = LAQUOT locationURI RAQUOT
+ * *(SEMI geoloc-param)
+ * locationURI = sip-URI / sips-URI / pres-URI
+ * / http-URI / https-URI
+ * / cid-url ; (from RFC 2392)
+ * / absoluteURI ; (from RFC 3261)
+ */
+ while((geoloc_uri = ast_strsep(&duped_geoloc_hdr_value, ',', AST_STRSEP_TRIM))) {
+ /* geoloc_uri should now be <scheme:location> */
+ int uri_len = strlen(geoloc_uri);
+ char *pidf_body = NULL;
+ unsigned int pidf_len = 0;
+ struct ast_xml_doc *incoming_doc = NULL;
+
+ struct ast_geoloc_eprofile *eprofile = NULL;
+ int rc = 0;
+
+ ast_trace(4, "Processing URI '%s'\n", geoloc_uri);
+
+ if (geoloc_uri[0] != '<' || geoloc_uri[uri_len - 1] != '>') {
+ ast_log(LOG_WARNING, "%s: Geolocation header has bad URI '%s'. Skipping\n", session_name,
+ geoloc_uri);
+ continue;
+ }
+ /* Trim the trailing '>' and skip the leading '<' */
+ geoloc_uri[uri_len - 1] = '\0';
+ geoloc_uri++;
+ /*
+ * If the URI isn't "cid" then we're just going to pass it through.
+ */
+ if (!ast_begins_with(geoloc_uri, "cid:")) {
+ ast_trace(4, "Processing URI '%s'. Reference\n", geoloc_uri);
+
+ eprofile = ast_geoloc_eprofile_create_from_uri(geoloc_uri, session_name);
+ if (!eprofile) {
+ ast_log(LOG_WARNING, "%s: Unable to create effective profile for URI '%s'. Skipping\n",
+ session_name, geoloc_uri);
+ continue;
+ }
+ } else {
+ ast_trace(4, "Processing URI '%s'. PIDF\n", geoloc_uri);
+ rc = find_pidf(session_name, rdata, geoloc_uri, &pidf_body, &pidf_len);
+ if (rc != 0 || !pidf_body || pidf_len == 0) {
+ continue;
+ }
+
+ incoming_doc = ast_xml_read_memory(pidf_body, pidf_len);
+ if (!incoming_doc) {
+ ast_log(LOG_WARNING, "%s: Unable to parse pidf document for URI '%s'\n",
+ session_name, geoloc_uri);
+ continue;
+ }
+
+ eprofile = ast_geoloc_eprofile_create_from_pidf(incoming_doc, session_name);
+ }
+ eprofile->location_disposition = config_profile->location_disposition;
+ eprofile->send_location = config_profile->send_location;
+
+ ast_trace(4, "Processing URI '%s'. Adding to datastore\n", geoloc_uri);
+ rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
+ if (rc != 0) {
+ ao2_ref(eprofile, -1);
+ ast_log(LOG_WARNING, "%s: Unable to add effective profile for URI '%s' to datastore. Skipping\n",
+ session_name, geoloc_uri);
+ }
+ }
+
+ if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_APPEND) {
+ ast_trace(4, "%s: Profile '%s' location_disposition is 'prepend' so "
+ "adding to datastore first", session_name, ast_sorcery_object_get_id(config_profile));
+
+ config_eprofile = ast_geoloc_eprofile_create_from_profile(config_profile);
+ if (!config_eprofile) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING, "%s: Unable to create eprofile from"
+ " profile '%s'\n", session_name, ast_sorcery_object_get_id(config_profile));
+ }
+
+ rc = ast_geoloc_datastore_add_eprofile(ds, config_eprofile);
+ if (rc != 0) {
+ SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,
+ "%s: Couldn't add eprofile '%s' to datastore\n", session_name,
+ config_eprofile->id);
+ }
+ config_eprofile = NULL;
+ }
+
+ eprofile_count = ast_geoloc_datastore_size(ds);
+ if (eprofile_count == 0) {
+ SCOPE_EXIT_RTN_VALUE(0,
+ "%s: Unable to add any effective profiles. Not adding datastore to channel.\n",
+ session_name);
+ }
+
+ ast_channel_datastore_add(channel, ds);
+ ds = NULL;
+
+ SCOPE_EXIT_RTN_VALUE(0, "%s: Added geoloc datastore with %" PRIu64 " eprofiles\n",
+ session_name, eprofile_count);
+}
+
+static void handle_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)
+{
+
+}
+
+static struct ast_sip_session_supplement geolocation_supplement = {
+ .method = "INVITE",
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 10,
+ .incoming_request = handle_incoming_request,
+ .outgoing_request = handle_outgoing_request,
+};
+
+static int reload_module(void)
+{
+ return 0;
+}
+
+static int unload_module(void)
+{
+ int res = 0;
+ ast_sip_session_unregister_supplement(&geolocation_supplement);
+
+ return res;
+}
+
+static int load_module(void)
+{
+ int res = 0;
+ GEOLOCATION_HDR = pj_str("Geolocation");
+
+ ast_sip_session_register_supplement(&geolocation_supplement);
+
+ return res;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "res_pjsip_geolocation Module for Asterisk",
+ .support_level = AST_MODULE_SUPPORT_CORE,
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload_module,
+ .load_pri = AST_MODPRI_CHANNEL_DEPEND - 1,
+ .requires = "res_geolocation,res_pjsip,res_pjsip_session,chan_pjsip",
+);
--
To view, visit https://gerrit.asterisk.org/c/asterisk/+/18191
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: development/16/geolocation
Gerrit-Change-Id: I6ccb5108a5eec060efb8116502fbff3cc63d7554
Gerrit-Change-Number: 18191
Gerrit-PatchSet: 4
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at sangoma.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>
Gerrit-Reviewer: Michael Bradeen <mbradeen at sangoma.com>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20220325/c37404b7/attachment-0001.html>
More information about the asterisk-code-review
mailing list