prefix_route.c

00001 /*
00002  * Prefix Route Module
00003  *
00004  * Copyright (C) 2007 Alfred E. Heggestad
00005  * Copyright (C) 2008 Telio Telecom AS
00006  *
00007  * This file is part of ser, a free SIP server.
00008  *
00009  * ser is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * For a license to use the ser software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact iptel.org by e-mail at the following addresses:
00017  *    info@iptel.org
00018  *
00019  * ser is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027  */
00028 
00029 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include "../../lib/srdb2/db.h"
00033 #include "../../rpc.h"
00034 #include "../../sr_module.h"
00035 #include "../../mem/mem.h"
00036 #include "../../data_lump_rpl.h"
00037 #include "../../parser/parse_uri.h"
00038 #include "../../parser/msg_parser.h"
00039 #include "../../locking.h"
00040 #include "../../action.h"
00041 #include "../../route.h"
00042 #include "tree.h"
00043 #include "pr.h"
00044 
00045 
00046 MODULE_VERSION
00047 
00048 
00049 /* Modules parameters */
00050 static char *db_url   = DEFAULT_DB_URL;
00051 static char *db_table = "prefix_route";
00052 
00053 
00054 static int add_route(struct tree_item *root, const char *prefix,
00055                      const char *route)
00056 {
00057         int ix, err;
00058 
00059         /* We cache the route index here so we can avoid route_lookup()
00060          * in the prefix_route() routing function.
00061          */
00062         ix = route_lookup(&main_rt, (char *)route);
00063         if (ix < 0) {
00064                 LOG(L_CRIT, "prefix_route: db_load(): "
00065                     "route name '%s' is not defined\n", route);
00066                 return -1;
00067         }
00068 
00069         if (ix >= main_rt.entries) {
00070                 LOG(L_CRIT, "prefix_route: route %d > n_entries (%d)\n",
00071                     ix, main_rt.entries);
00072                 return -1;
00073         }
00074 
00075         err = tree_item_add(root, prefix, route, ix);
00076         if (0 != err) {
00077                 LOG(L_CRIT, "prefix_route: db_load(): "
00078                     "tree_item_add() failed (%d)\n", err);
00079                 return err;
00080         }
00081 
00082         return 0;
00083 }
00084 
00085 
00089 int pr_db_load(void)
00090 {
00091         db_ctx_t *ctx;
00092         db_cmd_t *cmd = NULL;
00093         db_res_t* res = NULL;
00094         db_rec_t* rec;
00095         struct tree_item *root;
00096         int err = -1;
00097         int count = 0;
00098         db_fld_t match[] = {
00099                 { .name = "prefix",  .type = DB_CSTR },
00100                 { .name = "route",   .type = DB_CSTR },
00101                 { .name = "comment", .type = DB_CSTR },
00102                 { .name = NULL,      .type = DB_NONE }
00103         };
00104 
00105         ctx = db_ctx("prefix_route");
00106         if (!ctx) {
00107                 LOG(L_ERR, "prefix_route: db_load(): db_ctx() failed\n");
00108                 return -1;
00109         }
00110         if (db_add_db(ctx, db_url) < 0) {
00111                 LOG(L_ERR, "prefix_route: db_load(): could not add db\n");
00112                 goto out;
00113         }
00114         if (db_connect(ctx) < 0) {
00115                 LOG(L_ERR, "prefix_route: db_load(): could not connect\n");
00116                 goto out;
00117         }
00118 
00119         cmd = db_cmd(DB_GET, ctx, db_table, match, NULL, NULL);
00120         if (!cmd) {
00121                 LOG(L_ERR, "prefix_route: db_load(): db_cmd() failed\n");
00122                 goto out;
00123         }
00124 
00125         if (db_exec(&res, cmd) < 0) {
00126                 LOG(L_ERR, "prefix_route: db_load(): db_exec() failed\n");
00127                 goto out;
00128         }
00129 
00130         root = tree_item_alloc();
00131         if (NULL == root) {
00132                 LOG(L_ERR, "prefix_route: db_load() tree alloc failed\n");
00133                 err = -1;
00134                 goto out;
00135         }
00136 
00137         /* Assume Success */
00138         err = 0;
00139 
00140         /* Read from DB and build tree */
00141         for (rec = db_first(res); rec != NULL && !err; rec = db_next(res)) {
00142                 const char *prefix, *route, *comment;
00143 
00144                 ++count;
00145 
00146                 if (rec->fld[0].flags & DB_NULL) {
00147                         LOG(L_CRIT, "prefix_route: ERROR: bad 'prefix' "
00148                             "record in table %s, skipping...\n", db_table);
00149                         continue;
00150                 }
00151                 if (rec->fld[1].flags & DB_NULL) {
00152                         LOG(L_CRIT, "prefix_route: ERROR: bad 'route' "
00153                             "record in table %s, skipping...\n", db_table);
00154                         continue;
00155                 }
00156 
00157                 prefix  = rec->fld[0].v.cstr;
00158                 route   = rec->fld[1].v.cstr;
00159                 comment = rec->fld[2].v.cstr;
00160 
00161                 LOG(L_INFO, "  %d: prefix=%-10s  route=%-15s  comment=%s\n",
00162                     count, prefix, route, comment);
00163 
00164                 err = add_route(root, prefix, route);
00165         }
00166 
00167         LOG(L_NOTICE, "prefix_route: Total prefix routes loaded: %d\n", count);
00168 
00169         /* Error */
00170         if (0 != err) {
00171                 LOG(L_ERR, "prefix_route: db_load(): error, flushing tree\n");
00172                 tree_item_free(root);
00173                 goto out;
00174         }
00175 
00176         /* Swap trees */
00177         err = tree_swap(root);
00178         if (0 != err)
00179                 goto out;
00180 
00181  out:
00182         /* Free database results */
00183         if (res)
00184                 db_res_free(res);
00185         if (cmd)
00186                 db_cmd_free(cmd);
00187 
00188         /* Close database connection */
00189         if (ctx)
00190                 db_ctx_free(ctx);
00191 
00192         return err;
00193 }
00194 
00195 
00199 static int mod_init(void)
00200 {
00201         /* Initialise tree */
00202         if (0 != tree_init()) {
00203                 LOG(L_CRIT, "prefix_route: tree_init() failed\n\n");
00204                 return -1;
00205         }
00206 
00207         /* Populate database */
00208         if (0 != pr_db_load()) {
00209                 LOG(L_CRIT, "prefix_route: db_load() failed\n\n");
00210                 return -1;
00211         }
00212 
00213         return 0;
00214 }
00215 
00216 
00220 static void mod_destroy(void)
00221 {
00222         tree_close();
00223 }
00224 
00225 
00231 static int get_username(struct sip_msg* msg, str *user)
00232 {
00233         if (!msg || !user)
00234                 return -1;
00235 
00236         if (parse_sip_msg_uri(msg) < 0){
00237                 LOG(L_ERR, "get_username(): bad uri\n");
00238                 return -1; /* error, bad uri */
00239         }
00240 
00241         if (msg->parsed_uri.user.s == 0){
00242                 /* no user in uri */
00243                 LOG(L_ERR, "get_username(): no user in uri\n");
00244                 return -2;
00245         }
00246 
00247         *user = msg->parsed_uri.user;
00248 
00249         return 0;
00250 }
00251 
00252 
00256 static int prefix_route(struct sip_msg *msg, char *p1, char *p2)
00257 {
00258         struct run_act_ctx ra_ctx;
00259         str user;
00260         int err;
00261         int route;
00262 
00263         /* Unused */
00264         (void)p1;
00265         (void)p2;
00266 
00267         /* Get request URI */
00268         err = get_username(msg, &user);
00269         if (0 != err) {
00270                 LOG(L_ERR, "prefix_route: could not get username in"
00271                     " Request URI (%d)\n", err);
00272                 return err;
00273         }
00274 
00275         route = tree_route_get(&user);
00276         if (route <= 0)
00277                 return -1;
00278 
00279         /* If match send to route[x] */
00280         init_run_actions_ctx(&ra_ctx);
00281 
00282         err = run_actions(&ra_ctx, main_rt.rlist[route], msg);
00283         if (err < 0) {
00284                 LOG(L_ERR, "prefix_route: run_actions failed (%d)\n", err);
00285                 return -1;
00286         }
00287 
00288         /* Success */
00289         return 0;
00290 }
00291 
00292 
00293 /*
00294  * Exported functions
00295  */
00296 static cmd_export_t cmds[] = {
00297         {"prefix_route", prefix_route, 0, 0, REQUEST_ROUTE},
00298         {0,              0,            0, 0, 0            }
00299 };
00300 
00301 /*
00302  * Exported parameters
00303  */
00304 static param_export_t params[] = {
00305         {"db_url",       STR_PARAM, &db_url  },
00306         {"db_table",     STR_PARAM, &db_table},
00307         {0,              0,         0        }
00308 };
00309 
00310 /*
00311  * Module description
00312  */
00313 struct module_exports exports = {
00314         "prefix_route",  /* Module name             */
00315         cmds,            /* Exported functions      */
00316         pr_rpc,          /* RPC methods             */
00317         params,          /* Exported parameters     */
00318         mod_init,        /* Initialization function */
00319         0,               /* Response function       */
00320         mod_destroy,     /* Destroy function        */
00321         0,               /* OnCancel function       */
00322         0                /* Child init function     */
00323 };