cfg_rpc.c

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2007 iptelorg GmbH
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * For a license to use the ser software under conditions
00014  * other than those described here, or to purchase support for this
00015  * software, please contact iptel.org by e-mail at the following addresses:
00016  *    info@iptel.org
00017  *
00018  * ser is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  *
00027  * History
00028  * -------
00029  *  2007-12-03  Initial version (Miklos)
00030  */
00031 
00032 #include "../../sr_module.h"
00033 #include "../../cfg/cfg.h"
00034 #include "../../cfg/cfg_ctx.h"
00035 #include "../../rpc.h"
00036 
00037 static cfg_ctx_t        *ctx = NULL;
00038 
00039 MODULE_VERSION
00040 
00041 /* module initialization function */
00042 static int mod_init(void)
00043 {
00044         if (cfg_register_ctx(&ctx, NULL)) {
00045                 LOG(L_ERR, "cfg_rpc: failed to register cfg context\n");
00046                 return -1;
00047         }
00048 
00049         return 0;
00050 }
00051 
00052 /* Set the group_id pointer based on the group string.
00053  * The string is either "group_name", or "group_name[group_id]"
00054  * *group_id is set to null in the former case.
00055  * Warning: changes the group string
00056  */
00057 static int get_group_id(str *group, unsigned int **group_id)
00058 {
00059         static unsigned int     id;
00060         str     s;
00061 
00062         if (!group->s || (group->s[group->len-1] != ']')) {
00063                 *group_id = NULL;
00064                 return 0;
00065         }
00066 
00067         s.s = group->s + group->len - 2;
00068         s.len = 0;
00069         while ((s.s > group->s) && (*s.s != '[')) {
00070                 s.s--;
00071                 s.len++;
00072         }
00073         if (s.s == group->s) /* '[' not found */
00074                 return -1;
00075         group->len = s.s - group->s;
00076         s.s++;
00077         if (!group->len || !s.len)
00078                 return -1;
00079         if (str2int(&s, &id))
00080                 return -1;
00081 
00082         *group_id = &id;
00083         return 0;
00084 }
00085 
00086 static const char* rpc_set_now_doc[2] = {
00087         "Set the value of a configuration variable and commit the change immediately",
00088         0
00089 };
00090 
00091 static void rpc_set_now_int(rpc_t* rpc, void* c)
00092 {
00093         str     group, var;
00094         int     i;
00095         unsigned int    *group_id;
00096 
00097         if (rpc->scan(c, "SSd", &group, &var, &i) < 3)
00098                 return;
00099 
00100         if (get_group_id(&group, &group_id)) {
00101                 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00102                 return;
00103         }
00104 
00105         if (cfg_set_now_int(ctx, &group, group_id, &var, i)) {
00106                 rpc->fault(c, 400, "Failed to set the variable");
00107                 return;
00108         }
00109 }
00110 
00111 static void rpc_set_now_string(rpc_t* rpc, void* c)
00112 {
00113         str     group, var;
00114         char    *ch;
00115         unsigned int    *group_id;
00116 
00117         if (rpc->scan(c, "SSs", &group, &var, &ch) < 3)
00118                 return;
00119 
00120         if (get_group_id(&group, &group_id)) {
00121                 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00122                 return;
00123         }
00124 
00125         if (cfg_set_now_string(ctx, &group, group_id, &var, ch)) {
00126                 rpc->fault(c, 400, "Failed to set the variable");
00127                 return;
00128         }
00129 }
00130 
00131 static void rpc_set(rpc_t* rpc, void* c)
00132 {
00133         str     group, var;
00134         int     i, err;
00135         char    *ch;
00136         unsigned int    *group_id;
00137 
00138         if (rpc->scan(c, "SS", &group, &var) < 2)
00139                 return;
00140 
00141         if (get_group_id(&group, &group_id)) {
00142                 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00143                 return;
00144         }
00145 
00146         if (rpc->scan(c, "d", &i) == 1)
00147                 err = cfg_set_now_int(ctx, &group, group_id, &var, i);
00148         else if (rpc->scan(c, "s", &ch) == 1)
00149                 err = cfg_set_now_string(ctx, &group, group_id, &var, ch);
00150         else
00151                 return; /* error */
00152 
00153         if (err) {
00154                 rpc->fault(c, 400, "Failed to set the variable");
00155                 return;
00156         }
00157 }
00158 
00159 static const char* rpc_del_now_doc[2] = {
00160         "Delete the value of a configuration variable from a group instance and commit the change immediately",
00161         0
00162 };
00163 
00164 static void rpc_del(rpc_t* rpc, void* c)
00165 {
00166         str     group, var;
00167         unsigned int    *group_id;
00168 
00169         if (rpc->scan(c, "SS", &group, &var) < 2)
00170                 return;
00171 
00172         if (get_group_id(&group, &group_id) || !group_id) {
00173                 rpc->fault(c, 400, "Wrong group syntax. Use \"group[id]\"");
00174                 return;
00175         }
00176 
00177         if (cfg_del_now(ctx, &group, group_id, &var)) {
00178                 rpc->fault(c, 400, "Failed to delete the value");
00179                 return;
00180         }
00181 }
00182 
00183 static const char* rpc_set_delayed_doc[2] = {
00184         "Prepare the change of a configuration variable, but does not commit the new value yet",
00185         0
00186 };
00187 
00188 static void rpc_set_delayed_int(rpc_t* rpc, void* c)
00189 {
00190         str     group, var;
00191         int     i;
00192         unsigned int    *group_id;
00193 
00194         if (rpc->scan(c, "SSd", &group, &var, &i) < 3)
00195                 return;
00196 
00197         if (get_group_id(&group, &group_id)) {
00198                 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00199                 return;
00200         }
00201 
00202         if (cfg_set_delayed_int(ctx, &group, group_id, &var, i)) {
00203                 rpc->fault(c, 400, "Failed to set the variable");
00204                 return;
00205         }
00206 }
00207 
00208 static void rpc_set_delayed_string(rpc_t* rpc, void* c)
00209 {
00210         str     group, var;
00211         char    *ch;
00212         unsigned int    *group_id;
00213 
00214         if (rpc->scan(c, "SSs", &group, &var, &ch) < 3)
00215                 return;
00216 
00217         if (get_group_id(&group, &group_id)) {
00218                 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00219                 return;
00220         }
00221 
00222         if (cfg_set_delayed_string(ctx, &group, group_id, &var, ch)) {
00223                 rpc->fault(c, 400, "Failed to set the variable");
00224                 return;
00225         }
00226 }
00227 
00228 static void rpc_set_delayed(rpc_t* rpc, void* c)
00229 {
00230         str     group, var;
00231         int     i, err;
00232         char    *ch;
00233         unsigned int    *group_id;
00234 
00235         if (rpc->scan(c, "SS", &group, &var) < 2)
00236                 return;
00237 
00238         if (get_group_id(&group, &group_id)) {
00239                 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00240                 return;
00241         }
00242 
00243         if (rpc->scan(c, "d", &i) == 1)
00244                 err = cfg_set_delayed_int(ctx, &group, group_id, &var, i);
00245         else if (rpc->scan(c, "s", &ch) == 1)
00246                 err = cfg_set_delayed_string(ctx, &group, group_id, &var, ch);
00247         else
00248                 return; /* error */
00249 
00250         if (err) {
00251                 rpc->fault(c, 400, "Failed to set the variable");
00252                 return;
00253         }
00254 }
00255 
00256 static const char* rpc_del_delayed_doc[2] = {
00257         "Prepare the deletion of the value of a configuration variable from a group instance, but does not commit the change yet",
00258         0
00259 };
00260 
00261 static void rpc_del_delayed(rpc_t* rpc, void* c)
00262 {
00263         str     group, var;
00264         unsigned int    *group_id;
00265 
00266         if (rpc->scan(c, "SS", &group, &var) < 2)
00267                 return;
00268 
00269         if (get_group_id(&group, &group_id) || !group_id) {
00270                 rpc->fault(c, 400, "Wrong group syntax. Use \"group[id]\"");
00271                 return;
00272         }
00273 
00274         if (cfg_del_delayed(ctx, &group, group_id, &var)) {
00275                 rpc->fault(c, 400, "Failed to delete the value");
00276                 return;
00277         }
00278 }
00279 
00280 static const char* rpc_commit_doc[2] = {
00281         "Commit the previously prepared configuration changes",
00282         0
00283 };
00284 
00285 static void rpc_commit(rpc_t* rpc, void* c)
00286 {
00287         if (cfg_commit(ctx)) {
00288                 rpc->fault(c, 400, "Failed to commit the changes");
00289                 return;
00290         }
00291 }
00292 
00293 static const char* rpc_rollback_doc[2] = {
00294         "Drop the prepared configuration changes",
00295         0
00296 };
00297 
00298 static void rpc_rollback(rpc_t* rpc, void* c)
00299 {
00300         if (cfg_rollback(ctx)) {
00301                 rpc->fault(c, 400, "Failed to drop the changes");
00302                 return;
00303         }
00304 }
00305 
00306 static const char* rpc_get_doc[2] = {
00307         "Get the value of a configuration variable",
00308         0
00309 };
00310 
00311 static void rpc_get(rpc_t* rpc, void* c)
00312 {
00313         str     group, var;
00314         void    *val;
00315         unsigned int    val_type;
00316         int     ret;
00317         unsigned int    *group_id;
00318 
00319         if (rpc->scan(c, "SS", &group, &var) < 2)
00320                 return;
00321 
00322         if (get_group_id(&group, &group_id)) {
00323                 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00324                 return;
00325         }
00326 
00327         ret = cfg_get_by_name(ctx, &group, group_id, &var,
00328                         &val, &val_type);
00329         if (ret < 0) {
00330                 rpc->fault(c, 400, "Failed to get the variable");
00331                 return;
00332                 
00333         } else if (ret > 0) {
00334                 rpc->fault(c, 400, "Variable exists, but it is not readable via RPC interface");
00335                 return;
00336         }
00337 
00338         switch (val_type) {
00339         case CFG_VAR_INT:
00340                 rpc->add(c, "d", (int)(long)val);
00341                 break;
00342 
00343         case CFG_VAR_STRING:
00344                 rpc->add(c, "s", (char *)val);
00345                 break;
00346 
00347         case CFG_VAR_STR:
00348                 rpc->add(c, "S", (str *)val);
00349                 break;
00350 
00351         case CFG_VAR_POINTER:
00352                 rpc->printf(c, "%p", val);
00353                 break;
00354 
00355         }
00356 
00357 }
00358 
00359 static const char* rpc_help_doc[2] = {
00360         "Print the description of a configuration variable",
00361         0
00362 };
00363 
00364 static void rpc_help(rpc_t* rpc, void* c)
00365 {
00366         str     group, var;
00367         char    *ch;
00368         unsigned int    input_type;
00369 
00370         if (rpc->scan(c, "SS", &group, &var) < 2)
00371                 return;
00372 
00373         if (cfg_help(ctx, &group, &var,
00374                         &ch, &input_type)
00375         ) {
00376                 rpc->fault(c, 400, "Failed to get the variable description");
00377                 return;
00378         }
00379         rpc->add(c, "s", ch);
00380 
00381         switch (input_type) {
00382         case CFG_INPUT_INT:
00383                 rpc->printf(c, "(parameter type is integer)");
00384                 break;
00385 
00386         case CFG_INPUT_STRING:
00387         case CFG_INPUT_STR:
00388                 rpc->printf(c, "(parameter type is string)");
00389                 break;
00390         }       
00391 }
00392 
00393 static const char* rpc_list_doc[2] = {
00394         "List the configuration variables",
00395         0
00396 };
00397 
00398 static void rpc_list(rpc_t* rpc, void* c)
00399 {
00400         void            *h;
00401         str             gname;
00402         cfg_def_t       *def;
00403         int             i;
00404         str             group;
00405 
00406         if (rpc->scan(c, "*S", &group) < 1) {
00407                 group.s = NULL;
00408                 group.len = 0;
00409         }
00410 
00411         cfg_get_group_init(&h);
00412         while(cfg_get_group_next(&h, &gname, &def))
00413                 if (!group.len
00414                         || ((gname.len == group.len)
00415                                 && (memcmp(gname.s, group.s, group.len) == 0))
00416                 )
00417                         for (i=0; def[i].name; i++)
00418                                 rpc->printf(c, "%.*s: %s", gname.len, gname.s, def[i].name);
00419 }
00420 
00421 static const char* rpc_diff_doc[2] = {
00422         "List the pending configuration changes that have not been committed yet",
00423         0
00424 };
00425 
00426 static void rpc_diff(rpc_t* rpc, void* c)
00427 {
00428         void            *h;
00429         str             gname, vname;
00430         unsigned int    *gid;
00431         void            *old_val, *new_val;
00432         unsigned int    val_type;
00433         void            *rpc_handle;
00434         int             err;
00435 
00436 
00437         if (cfg_diff_init(ctx, &h)) {
00438                 rpc->fault(c, 400, "Failed to get the changes");
00439                 return;
00440         }
00441         while((err = cfg_diff_next(&h,
00442                         &gname, &gid, &vname,
00443                         &old_val, &new_val,
00444                         &val_type)) > 0
00445         ) {
00446                 rpc->add(c, "{", &rpc_handle);
00447                 if (gid)
00448                         rpc->struct_add(rpc_handle, "SdS",
00449                                         "group name", &gname,
00450                                         "group id", *gid,
00451                                         "variable name", &vname);
00452                 else
00453                         rpc->struct_add(rpc_handle, "SS",
00454                                         "group name", &gname,
00455                                         "variable name", &vname);
00456 
00457                 switch (val_type) {
00458                 case CFG_VAR_INT:
00459                         rpc->struct_add(rpc_handle, "dd",
00460                                         "old value", (int)(long)old_val,
00461                                         "new value", (int)(long)new_val);
00462                         break;
00463 
00464                 case CFG_VAR_STRING:
00465                         rpc->struct_add(rpc_handle, "ss",
00466                                         "old value", (char *)old_val,
00467                                         "new value", (char *)new_val);
00468                         break;
00469 
00470                 case CFG_VAR_STR:
00471                         rpc->struct_add(rpc_handle, "SS",
00472                                         "old value", (str *)old_val,
00473                                         "new value", (str *)new_val);
00474                         break;
00475 
00476                 case CFG_VAR_POINTER:
00477                         /* cannot print out pointer value with struct_add() */
00478                         break;
00479 
00480                 }
00481         }
00482         cfg_diff_release(ctx);
00483         if (err)
00484                 rpc->fault(c, 400, "Failed to get the changes");
00485 }
00486 
00487 static const char* rpc_add_group_inst_doc[2] = {
00488         "Add a new instance to an existing configuration group",
00489         0
00490 };
00491 
00492 static void rpc_add_group_inst(rpc_t* rpc, void* c)
00493 {
00494         str     group;
00495         unsigned int    *group_id;
00496 
00497         if (rpc->scan(c, "S", &group) < 1)
00498                 return;
00499 
00500         if (get_group_id(&group, &group_id) || !group_id) {
00501                 rpc->fault(c, 400, "Wrong group syntax. Use \"group[id]\"");
00502                 return;
00503         }
00504 
00505         if (cfg_add_group_inst(ctx, &group, *group_id)) {
00506                 rpc->fault(c, 400, "Failed to add the group instance");
00507                 return;
00508         }
00509 }
00510 
00511 static const char* rpc_del_group_inst_doc[2] = {
00512         "Delte an instance of a configuration group",
00513         0
00514 };
00515 
00516 static void rpc_del_group_inst(rpc_t* rpc, void* c)
00517 {
00518         str     group;
00519         unsigned int    *group_id;
00520 
00521         if (rpc->scan(c, "S", &group) < 1)
00522                 return;
00523 
00524         if (get_group_id(&group, &group_id) || !group_id) {
00525                 rpc->fault(c, 400, "Wrong group syntax. Use \"group[id]\"");
00526                 return;
00527         }
00528 
00529         if (cfg_del_group_inst(ctx, &group, *group_id)) {
00530                 rpc->fault(c, 400, "Failed to delete the group instance");
00531                 return;
00532         }
00533 }
00534 
00535 static rpc_export_t rpc_calls[] = {
00536         {"cfg.set",             rpc_set,                rpc_set_now_doc,        0},
00537         {"cfg.set_now_int",     rpc_set_now_int,        rpc_set_now_doc,        0},
00538         {"cfg.seti",    rpc_set_now_int,        rpc_set_now_doc,        0},
00539         {"cfg.set_now_string",  rpc_set_now_string,     rpc_set_now_doc,        0},
00540         {"cfg.sets",    rpc_set_now_string,     rpc_set_now_doc,        0},
00541         {"cfg.del",             rpc_del,                rpc_del_now_doc,        0},
00542         {"cfg.set_delayed",     rpc_set_delayed,        rpc_set_delayed_doc,    0},
00543         {"cfg.set_delayed_int", rpc_set_delayed_int,    rpc_set_delayed_doc,    0},
00544         {"cfg.set_delayed_string",      rpc_set_delayed_string, rpc_set_delayed_doc,    0},
00545         {"cfg.del_delayed",     rpc_del_delayed,        rpc_del_delayed_doc,    0},
00546         {"cfg.commit",          rpc_commit,             rpc_commit_doc,         0},
00547         {"cfg.rollback",        rpc_rollback,           rpc_rollback_doc,       0},
00548         {"cfg.get",             rpc_get,                rpc_get_doc,            0},
00549         {"cfg.help",            rpc_help,               rpc_help_doc,           0},
00550         {"cfg.list",            rpc_list,               rpc_list_doc,           0},
00551         {"cfg.diff",            rpc_diff,               rpc_diff_doc,           0},
00552         {"cfg.add_group_inst",  rpc_add_group_inst,     rpc_add_group_inst_doc, 0},     
00553         {"cfg.del_group_inst",  rpc_del_group_inst,     rpc_del_group_inst_doc, 0},     
00554         {0, 0, 0, 0}
00555 };
00556 
00557 /* Module interface */
00558 struct module_exports exports = {
00559         "cfg_rpc",
00560         0,              /* Exported functions */
00561         rpc_calls,      /* RPC methods */
00562         0,              /* Exported parameters */
00563         mod_init,       /* module initialization function */
00564         0,              /* response function */
00565         0,              /* destroy function */
00566         0,              /* oncancel function */
00567         0               /* child initialization function */
00568 };