Author: gtjoseph
Date: Fri Nov 21 11:41:15 2014
New Revision: 428543

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=428543
Log:
sorcery: Make is_object_field_registered handle field names that are regexes.

As a result of https://reviewboard.asterisk.org/r/3305, res_sorcery_realtime
was tossing database fields that didn't have an exact match to a sorcery
registered field.  This broke the ability to use regexes as field names which
manifested itself as a failure of res_pjsip_phoneprov_provider which uses
this capability.  It also broke handling of fields that start with '@' in
realtime but I don't think anyone noticed.

This patch does the following...
* Modifies ast_sorcery_fields_register to pre-compile the name regex.
* Modifies ast_sorcery_is_object_field_registered to test the regex if it
  exists instead of doing an exact strcmp.
* Modifies res_pjsip_phoneprov_provider with a few tweaks to get it to work
  with realtime.

Tested-by: George Joseph

Review: https://reviewboard.asterisk.org/r/4185/


Modified:
    branches/12/main/sorcery.c
    branches/12/res/res_pjsip_phoneprov_provider.c
    branches/12/tests/test_sorcery.c

Modified: branches/12/main/sorcery.c
URL: 
http://svnview.digium.com/svn/asterisk/branches/12/main/sorcery.c?view=diff&rev=428543&r1=428542&r2=428543
==============================================================================
--- branches/12/main/sorcery.c (original)
+++ branches/12/main/sorcery.c Fri Nov 21 11:41:15 2014
@@ -141,6 +141,9 @@
        /*! \brief Name of the field */
        char name[MAX_OBJECT_FIELD];
 
+       /*! \brief The compiled name regex if name is a regex */
+       regex_t *name_regex;
+
        /*! \brief Callback function for translation of a single value */
        sorcery_field_handler handler;
 
@@ -871,17 +874,40 @@
        object_type->diff = diff;
 }
 
+static void sorcery_object_field_destructor(void *obj)
+{
+       struct ast_sorcery_object_field *object_field = obj;
+
+       if (object_field->name_regex) {
+               regfree(object_field->name_regex);
+       }
+}
+
 int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char 
*type, const char *regex, aco_option_handler config_handler, 
sorcery_fields_handler sorcery_handler)
 {
+#define MAX_REGEX_ERROR_LEN 128
        RAII_VAR(struct ast_sorcery_object_type *, object_type, 
ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
        RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, 
ao2_cleanup);
-
-       if (!object_type || !object_type->type.item_alloc || !config_handler || 
!(object_field = ao2_alloc(sizeof(*object_field), NULL))) {
+       int rc;
+
+       if (!object_type || !object_type->type.item_alloc || !config_handler
+               || !(object_field = ao2_alloc(sizeof(*object_field), 
sorcery_object_field_destructor))) {
                return -1;
        }
 
        ast_copy_string(object_field->name, regex, sizeof(object_field->name));
        object_field->multiple_handler = sorcery_handler;
+
+       if (!(object_field->name_regex = ast_calloc(1, sizeof(regex_t)))) {
+               return -1;
+       }
+
+       if ((rc = regcomp(object_field->name_regex, regex, REG_EXTENDED | 
REG_NOSUB))) {
+               char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
+               regerror(rc, object_field->name_regex, regerr, 
MAX_REGEX_ERROR_LEN);
+               ast_log(LOG_ERROR, "Regular expression '%s' failed to compile: 
%s\n", regex, regerr);
+               return -1;
+       }
 
        ao2_link(object_type->fields, object_field);
        __aco_option_register(object_type->info, regex, ACO_REGEX, 
object_type->file->types, "", OPT_CUSTOM_T, config_handler, 0, 1, 0);
@@ -1928,6 +1954,20 @@
        return ao2_find(sorcery->types, type, OBJ_SEARCH_KEY);
 }
 
+static int is_registered_cb(void *obj, void *arg, int flags)
+{
+       struct ast_sorcery_object_field *object_field = obj;
+       char *name = arg;
+       int rc = 0;
+
+       if (object_field->name_regex
+               && !regexec(object_field->name_regex, name, 0, NULL, 0)) {
+               rc = CMP_MATCH | CMP_STOP;
+       }
+
+       return rc;
+}
+
 int ast_sorcery_is_object_field_registered(const struct 
ast_sorcery_object_type *object_type,
                const char *field_name)
 {
@@ -1937,6 +1977,11 @@
        ast_assert(object_type != NULL);
 
        object_field = ao2_find(object_type->fields, field_name, 
OBJ_SEARCH_KEY);
+
+       if (!object_field) {
+               object_field = ao2_callback(object_type->fields, 0, 
is_registered_cb, (char *)field_name);
+       }
+
        if (!object_field) {
                res = 0;
        }

Modified: branches/12/res/res_pjsip_phoneprov_provider.c
URL: 
http://svnview.digium.com/svn/asterisk/branches/12/res/res_pjsip_phoneprov_provider.c?view=diff&rev=428543&r1=428542&r2=428543
==============================================================================
--- branches/12/res/res_pjsip_phoneprov_provider.c (original)
+++ branches/12/res/res_pjsip_phoneprov_provider.c Fri Nov 21 11:41:15 2014
@@ -289,7 +289,7 @@
        int user_count = 0;
        char port_string[6];
 
-       c = ast_sorcery_retrieve_by_regex(sorcery, "phoneprov", "");
+       c = ast_sorcery_retrieve_by_fields(sorcery, "phoneprov", 
AST_RETRIEVE_FLAG_MULTIPLE, NULL);
        if (!c) {
                ast_log(LOG_ERROR, "Retrieve by regex failed to allocate a 
container.\n");
                return -1;
@@ -377,12 +377,7 @@
                return AST_MODULE_LOAD_DECLINE;
        }
 
-       if (ast_sorcery_apply_default(sorcery, "phoneprov", "config",
-               "pjsip.conf,criteria=type=phoneprov")) {
-               ast_log(LOG_ERROR, "Unable to register object phoneprov.\n");
-               ast_sorcery_unref(sorcery);
-               return AST_MODULE_LOAD_DECLINE;
-       }
+       ast_sorcery_apply_default(sorcery, "phoneprov", "config", 
"pjsip.conf,criteria=type=phoneprov");
 
        ast_sorcery_object_register(sorcery, "phoneprov", phoneprov_alloc, NULL,
                users_apply_handler);

Modified: branches/12/tests/test_sorcery.c
URL: 
http://svnview.digium.com/svn/asterisk/branches/12/tests/test_sorcery.c?view=diff&rev=428543&r1=428542&r2=428543
==============================================================================
--- branches/12/tests/test_sorcery.c (original)
+++ branches/12/tests/test_sorcery.c Fri Nov 21 11:41:15 2014
@@ -2991,6 +2991,48 @@
        }
 
        ast_free(buf);
+
+       return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(object_field_registered)
+{
+       RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+       RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, 
ao2_cleanup);
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "object_field_registered";
+               info->category = "/main/sorcery/";
+               info->summary = "ast_sorcery_is_object_field_registered unit 
test";
+               info->description =
+                       "Test ast_sorcery_is_object_field_registered in 
sorcery";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       if (!(sorcery = alloc_and_initialize_sorcery())) {
+               ast_test_status_update(test, "Failed to open sorcery 
structure\n");
+               return AST_TEST_FAIL;
+       }
+
+       object_type = ast_sorcery_get_object_type(sorcery, "test");
+
+       ast_sorcery_object_fields_register(sorcery, "test", "^prefix/.", 
test_sorcery_regex_handler, test_sorcery_regex_fields);
+
+       ast_test_validate(test, 
ast_sorcery_is_object_field_registered(object_type, "joe"));
+       ast_test_validate(test, 
ast_sorcery_is_object_field_registered(object_type, "bob"));
+       ast_test_validate(test, 
ast_sorcery_is_object_field_registered(object_type, "@joebob"));
+       ast_test_validate(test, 
ast_sorcery_is_object_field_registered(object_type, "prefix/goober"));
+
+       ast_test_validate(test, 
!ast_sorcery_is_object_field_registered(object_type, "joebob"));
+       ast_test_validate(test, 
!ast_sorcery_is_object_field_registered(object_type, "prefix/"));
+       ast_test_validate(test, 
!ast_sorcery_is_object_field_registered(object_type, "goober"));
+
+       ast_sorcery_object_fields_register(sorcery, "test", "^", 
test_sorcery_regex_handler, test_sorcery_regex_fields);
+
+       ast_test_validate(test, 
ast_sorcery_is_object_field_registered(object_type, "goober"));
 
        return AST_TEST_PASS;
 }
@@ -3041,6 +3083,8 @@
        AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple);
        AST_TEST_UNREGISTER(configuration_file_wizard_retrieve_multiple_all);
        AST_TEST_UNREGISTER(dialplan_function);
+       AST_TEST_UNREGISTER(object_field_registered);
+
        return 0;
 }
 
@@ -3090,6 +3134,8 @@
        AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple);
        AST_TEST_REGISTER(configuration_file_wizard_retrieve_multiple_all);
        AST_TEST_REGISTER(dialplan_function);
+       AST_TEST_REGISTER(object_field_registered);
+
        return AST_MODULE_LOAD_SUCCESS;
 }
 


-- 
_____________________________________________________________________
-- Bandwidth and Colocation Provided by http://www.api-digital.com --

svn-commits mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/svn-commits

Reply via email to