changing the syntax of cfg_register_ctx() function
[sip-router] / cfg / cfg_ctx.c
index 73f38c8..c62273e 100644 (file)
  */
 
 #include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
 
+#include "../ut.h"
 #include "cfg_struct.h"
 #include "cfg_ctx.h"
 
+
 /* linked list of all the registered cfg contexts */
 static cfg_ctx_t       *cfg_ctx_list = NULL;
 
 /* creates a new config context that is an interface to the
  * cfg variables with write permission
  */
-cfg_ctx_t *cfg_register_ctx(cfg_on_declare on_declare_cb)
+int cfg_register_ctx(cfg_ctx_t **handle, cfg_on_declare on_declare_cb)
 {
        cfg_ctx_t       *ctx;
        cfg_group_t     *group;
@@ -52,20 +56,23 @@ cfg_ctx_t *cfg_register_ctx(cfg_on_declare on_declare_cb)
        ctx = (cfg_ctx_t *)shm_malloc(sizeof(cfg_ctx_t));
        if (!ctx) {
                LOG(L_ERR, "ERROR: cfg_register_ctx(): not enough shm memory\n");
-               return NULL;
+               return -1;
        }
        memset(ctx, 0, sizeof(cfg_ctx_t));
        if (lock_init(&ctx->lock) == 0) {
                LOG(L_ERR, "ERROR: cfg_register_ctx(): failed to init lock\n");
                shm_free(ctx);
-               return NULL;
+               return -1;
        }
 
        /* add the new ctx to the beginning of the list */
        ctx->next = cfg_ctx_list;
        cfg_ctx_list = ctx;
 
-       /* let the driver know about the already registered groups */
+       /* let the driver know about the already registered groups
+        * The handle of the context must be set before calling the
+        * on_declare callbacks. */
+       *handle = ctx;
        if (on_declare_cb) {
                ctx->on_declare_cb = on_declare_cb;
 
@@ -73,13 +80,17 @@ cfg_ctx_t *cfg_register_ctx(cfg_on_declare on_declare_cb)
                        group;
                        group = group->next
                ) {
+                       /* dynamic groups are not ready, the callback
+                       will be called later when the group is fixed-up */
+                       if (group->dynamic) continue;
+
                        gname.s = group->name;
                        gname.len = group->name_len;
                        on_declare_cb(&gname, group->mapping->def);
                }
        }
 
-       return ctx;
+       return 0;
 }
 
 /* free the memory allocated for the contexts */
@@ -98,13 +109,13 @@ void cfg_ctx_destroy(void)
 }
 
 /* notify the drivers about the new config definition */
-void cfg_notify_drivers(char *group_name, cfg_def_t *def)
+void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def)
 {
        cfg_ctx_t       *ctx;
        str             gname;
 
        gname.s = group_name;
-       gname.len = strlen(group_name);
+       gname.len = group_name_len;
 
        for (   ctx = cfg_ctx_list;
                ctx;
@@ -114,33 +125,127 @@ void cfg_notify_drivers(char *group_name, cfg_def_t *def)
                        ctx->on_declare_cb(&gname, def);
 }
 
-/* convert the value to the requested type
- * (only string->str is implemented currently) */
+/*
+ * Convert an str into signed integer
+ * this function should be moved to ../ut.h
+ */
+static int str2sint(str* _s, int* _r)
+{
+       int i;
+       int sign;
+
+       if (_s->len == 0) return -1;
+
+       *_r = 0;
+       sign = 1;
+       i = 0;
+       if (_s->s[0] == '+') {
+               i++;
+       } else if (_s->s[0] == '-') {
+               sign = -1;
+               i++;
+       }
+       for(; i < _s->len; i++) {
+               if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
+                       *_r *= 10;
+                       *_r += _s->s[i] - '0';
+               } else {
+                       return -1;
+               }
+       }
+       *_r *= sign;
+
+       return 0;
+}
+
+
+/* placeholder for a temporary string */
+static char    *temp_string = NULL;
+
+/* convert the value to the requested type */
 static int convert_val(unsigned int val_type, void *val,
                        unsigned int var_type, void **new_val)
 {
        static str      s;
+       char            *end;
+       int             i;
+       static char     buf[INT2STR_MAX_LEN];
 
-       switch (val_type) {
-               case CFG_VAR_INT:
-                       if (CFG_INPUT_MASK(var_type) != CFG_INPUT_INT)
-                               goto error;
+       /* we have to convert from val_type to var_type */
+       switch (CFG_INPUT_MASK(var_type)) {
+       case CFG_INPUT_INT:
+               if (val_type == CFG_VAR_INT) {
                        *new_val = val;
                        break;
 
-               case CFG_VAR_STRING:
-                       if (CFG_INPUT_MASK(var_type) == CFG_INPUT_STR) {
-                               s.s = val;
-                               s.len = strlen(s.s);
-                               *new_val = (void *)&s;
-                               break;
+               } else if (val_type == CFG_VAR_STRING) {
+                       *new_val = (void *)(long)strtol((char *)val, &end, 10);
+                       if (*end != '\0') {
+                               LOG(L_ERR, "ERROR: convert_val(): "
+                                       "cannot convert string to integer '%s'\n",
+                                       s.s);
+                               return -1;
                        }
-                       if (CFG_INPUT_MASK(var_type) != CFG_INPUT_STRING)
-                               goto error;
+                       break;
+
+               } else if (val_type == CFG_VAR_STR) {
+                       if (str2sint((str *)val, &i)) {
+                               LOG(L_ERR, "ERROR: convert_val(): "
+                                       "cannot convert string to integer '%.*s'\n",
+                                       ((str *)val)->len, ((str *)val)->s);
+                               return -1;
+                       }
+                       *new_val = (void *)(long)i;
+                       break;
+               }
+               goto error;
+
+       case CFG_INPUT_STRING:
+               if (val_type == CFG_VAR_INT) {
+                       buf[snprintf(buf, sizeof(buf)-1, "%ld", (long)val)] = '\0';
+                       *new_val = buf;
+                       break;
+
+               } else if (val_type == CFG_VAR_STRING) {
                        *new_val = val;
                        break;
-               default:
-                       goto error;
+
+               } else if (val_type == CFG_VAR_STR) {
+                       /* the value may not be zero-terminated, thus,
+                       a new variable has to be allocated with larger memory space */
+                       if (temp_string) pkg_free(temp_string);
+                       temp_string = (char *)pkg_malloc(sizeof(char) * (((str *)val)->len + 1));
+                       if (!temp_string) {
+                               LOG(L_ERR, "ERROR: convert_val(): not enough memory\n");
+                               return -1;
+                       }
+                       memcpy(temp_string, ((str *)val)->s, ((str *)val)->len);
+                       temp_string[((str *)val)->len] = '\0';
+                       *new_val = (void *)temp_string;
+                       break;
+
+               }
+               goto error;
+
+       case CFG_INPUT_STR:
+               if (val_type == CFG_VAR_INT) {
+                       s.len = snprintf(buf, sizeof(buf)-1, "%ld", (long)val);
+                       buf[s.len] = '\0';
+                       s.s = buf;
+                       *new_val = (void *)&s;
+                       break;
+
+               } else if (val_type == CFG_VAR_STRING) {
+                       s.s = (char *)val;
+                       s.len = strlen(s.s);
+                       *new_val = (void *)&s;
+                       break;
+
+               } else if (val_type == CFG_VAR_STR) {
+                       *new_val = val;
+                       break;                  
+               }
+               goto error;
        }
 
        return 0;
@@ -151,6 +256,14 @@ error:
        return -1;
 }
 
+#define convert_val_cleanup() \
+       do { \
+               if (temp_string) { \
+                       pkg_free(temp_string); \
+                       temp_string = NULL; \
+               } \
+       } while(0)
+
 /* sets the value of a variable without the need of commit
  *
  * return value:
@@ -227,8 +340,10 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
 
                p = block->vars+group->offset+var->offset;
        } else {
-               /* we are allowed to rewrite the value on-the-fly */
-               p = group->vars + var->offset;
+               /* we are allowed to rewrite the value on-the-fly
+               The handle either points to group->vars, or to the
+               shared memory block (dynamic group) */
+               p = *(group->handle) + var->offset;
        }
 
        /* set the new value */
@@ -277,6 +392,10 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
                cfg_install_global(block, replaced, child_cb, child_cb);
                CFG_WRITER_UNLOCK();
        } else {
+               /* cfg_set() may be called more than once before forking */
+               if (old_string && (var->flag & cfg_var_shmized))
+                       shm_free(old_string);
+
                /* flag the variable because there is no need
                to shmize it again */
                var->flag |= cfg_var_shmized;
@@ -288,13 +407,22 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
                        group_name->len, group_name->s,
                        var_name->len, var_name->s,
                        (int)(long)val);
-       else
+
+       else if (val_type == CFG_VAR_STRING)
                LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
                        "has been changed to \"%s\"\n",
                        group_name->len, group_name->s,
                        var_name->len, var_name->s,
                        (char *)val);
 
+       else /* str type */
+               LOG(L_INFO, "INFO: cfg_set_now(): %.*s.%.*s "
+                       "has been changed to \"%.*s\"\n",
+                       group_name->len, group_name->s,
+                       var_name->len, var_name->s,
+                       ((str *)val)->len, ((str *)val)->s);
+
+       convert_val_cleanup();
        return 0;
 
 error:
@@ -308,6 +436,7 @@ error0:
                        var_name->len, var_name->s);
 
 
+       convert_val_cleanup();
        return -1;
 }
 
@@ -323,6 +452,12 @@ int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val
        return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
 }
 
+/* wrapper function for cfg_set_now */
+int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
+{
+       return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
+}
+
 /* returns the size of the variable */
 static int cfg_var_size(cfg_mapping_t *var)
 {
@@ -502,7 +637,8 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
                        var_name->len, var_name->s,
                        (int)(long)val,
                        ctx);
-       else
+
+       else if (val_type == CFG_VAR_STRING)
                LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
                        "is going to be changed to \"%s\" "
                        "[context=%p]\n",
@@ -511,6 +647,16 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
                        (char *)val,
                        ctx);
 
+       else /* str type */
+               LOG(L_INFO, "INFO: cfg_set_delayed(): %.*s.%.*s "
+                       "is going to be changed to \"%.*s\" "
+                       "[context=%p]\n",
+                       group_name->len, group_name->s,
+                       var_name->len, var_name->s,
+                       ((str *)val)->len, ((str *)val)->s,
+                       ctx);
+
+       convert_val_cleanup();
        return 0;
 
 error:
@@ -521,6 +667,7 @@ error0:
                        group_name->len, group_name->s,
                        var_name->len, var_name->s);
 
+       convert_val_cleanup();
        return -1;
 }
 
@@ -536,6 +683,12 @@ int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char
        return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
 }
 
+/* wrapper function for cfg_set_delayed */
+int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
+{
+       return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
+}
+
 /* commits the previously prepared changes within the context */
 int cfg_commit(cfg_ctx_t *ctx)
 {