/* * $Id: avp_db.c,v 1.2.2.1 2005/04/20 19:56:26 bogdan Exp $ * * Copyright (C) 2004 FhG Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "../../sr_module.h" #include "../../mem/mem.h" #include "../../parser/msg_parser.h" #include "../../parser/hf.h" #include "../../parser/parse_from.h" #include "../../parser/parse_to.h" #include "../../parser/parse_uri.h" #include "../../str.h" #include "../../db/db.h" #include "../../config.h" #include "../../usr_avp.h" MODULE_VERSION #define CALLER_PREFIX "caller_" #define CALLER_PREFIX_LEN (sizeof(CALLER_PREFIX) - 1) #define CALLEE_PREFIX "callee_" #define CALLEE_PREFIX_LEN (sizeof(CALLEE_PREFIX) - 1) typedef enum load_avp_param { LOAD_CALLER_UUID, /* Use the caller's UUID as the key */ LOAD_CALLEE_UUID, /* Use the callee's UUID as the key */ LOAD_CALLER, /* Use the caller's username and domain as the key */ LOAD_CALLEE /* Use the callee's username and domain as the key */ } load_avp_param_t; static char* db_url = DEFAULT_RODB_URL; /* Database URL */ static char* db_table = "usr_preferences"; static char* uuid_column = "uuid"; static char* username_column = "username"; static char* domain_column = "domain"; static char* attr_column = "attribute"; static char* val_column = "value"; static str caller_prefix = {CALLER_PREFIX, CALLER_PREFIX_LEN}; static str callee_prefix = {CALLEE_PREFIX, CALLEE_PREFIX_LEN}; static int caller_uuid_avp = 1; static int callee_uuid_avp = 2; static int use_domain = 0; static db_con_t* db_handle; static db_func_t dbf; static int load_avp(struct sip_msg*, char*, char*); static int mod_init(void); static int child_init(int); static int load_avp_fixup(void**, int); /* * Exported functions */ static cmd_export_t cmds[] = { {"avp_load", load_avp, 1, load_avp_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, {0, 0, 0, 0, 0} }; /* * Exported parameters */ static param_export_t params[] = { {"caller_uuid_avp", INT_PARAM, &caller_uuid_avp}, {"callee_uuid_avp", INT_PARAM, &callee_uuid_avp}, {"db_url", STR_PARAM, &db_url }, {"pref_table", STR_PARAM, &db_table }, {"uuid_column", STR_PARAM, &uuid_column }, {"username_column", STR_PARAM, &username_column}, {"domain_column", STR_PARAM, &domain_column }, {"attr_column", STR_PARAM, &attr_column }, {"val_column", INT_PARAM, &val_column }, {"use_domain", INT_PARAM, &use_domain }, {0, 0, 0} }; struct module_exports exports = { "avp_db", cmds, /* Exported commands */ params, /* Exported parameters */ mod_init, /* module initialization function */ 0, /* response function*/ 0, /* destroy function */ 0, /* oncancel function */ child_init /* per-child init function */ }; static int mod_init(void) { DBG("avp_db - initializing\n"); if (bind_dbmod(db_url, &dbf) < 0) { LOG(L_ERR, "avpdb_mod_init: Unable to bind a database driver\n"); return -1; } if (!DB_CAPABILITY(dbf, DB_CAP_QUERY)) { LOG(L_ERR, "avpdb_mod_init: Selected database driver does not suppor the query capability\n"); return -1; } caller_prefix.len = strlen(caller_prefix.s); callee_prefix.len = strlen(callee_prefix.s); return 0; } static int child_init(int rank) { DBG("avp_db - Initializing child %i\n", rank); db_handle = dbf.init(db_url); if (!db_handle) { LOG(L_ERR, "avpdb_init_child: could not initialize connection to %s\n", db_url); return -1; } return 0; } static int query_db(str* prefix, str* uuid, str* username, str* domain) { int name_len, err = -1; db_key_t cols[2], keys[2]; db_val_t vals[2]; db_res_t* res; db_row_t* cur_row; int_str name, val; str name_str, val_str; cols[0] = attr_column; cols[1] = val_column; if (uuid) { keys[0] = uuid_column; VAL_TYPE(vals) = DB_STR; VAL_NULL(vals) = 0; VAL_STR(vals) = *uuid; } else { keys[0] = username_column; VAL_TYPE(vals) = DB_STR; VAL_NULL(vals) = 0; VAL_STR(vals) = *username; } if (use_domain) { keys[1] = domain_column; VAL_TYPE(vals + 1) = DB_STR; VAL_NULL(vals + 1) = 0; VAL_STR(vals + 1) = *domain; } if (dbf.use_table(db_handle, db_table) < 0) { LOG(L_ERR, "query_db: Unable to change the table\n"); } err = dbf.query(db_handle, keys, 0, vals, cols, (use_domain ? 2 : 1), 2, 0, &res); if (err) { LOG(L_ERR,"query_db: db_query failed."); return -1; } name.s = &name_str; val.s = &val_str; for (cur_row = res->rows; cur_row < res->rows + res->n; cur_row++) { if (VAL_NULL(ROW_VALUES(cur_row)) || VAL_NULL(ROW_VALUES(cur_row) + 1)) { continue; } name_len = strlen((char*)VAL_STRING(ROW_VALUES(cur_row))); name_str.len = prefix->len + name_len; name_str.s = pkg_malloc(name_str.len); if (name_str.s == 0) { LOG(L_ERR, "query_db: Out of memory"); dbf.free_result(db_handle, res); return -1; } memcpy(name_str.s, prefix->s, prefix->len); memcpy(name_str.s + prefix->len, (char*)VAL_STRING(ROW_VALUES(cur_row)), name_len); val_str.len = strlen((char*)VAL_STRING(ROW_VALUES(cur_row) + 1)); val_str.s = (char*)VAL_STRING(ROW_VALUES(cur_row) + 1); err = add_avp(AVP_NAME_STR | AVP_VAL_STR, name, val); if (err != 0) { LOG(L_ERR, "query_db: add_avp failed\n"); pkg_free(name_str.s); dbf.free_result(db_handle, res); } DBG("query_db: AVP '%.*s'='%.*s' has been added\n", name_str.len, name_str.s, val_str.len, val_str.s); } dbf.free_result(db_handle, res); return 1; } static int load_avp_uuid(struct sip_msg* msg, str* prefix, int avp_id) { struct usr_avp *uuid; int_str attr_istr, val_istr; attr_istr.n = avp_id; uuid = search_first_avp(AVP_NAME_STR, attr_istr, &val_istr); if (!uuid) { LOG(L_ERR, "load_avp_uuid: no AVP with id %d was found\n", avp_id); return -1; } if (!(uuid->flags & AVP_VAL_STR)) { LOG(L_ERR, "load_avp_uuid: value for <%d> should " "be of type string\n", avp_id); return -1; } return query_db(prefix, val_istr.s, 0, 0); } static int load_avp_user(struct sip_msg* msg, str* prefix, load_avp_param_t param) { str* uri; struct sip_uri puri; if (param == LOAD_CALLER) { if (parse_from_header(msg) < 0) { LOG(L_ERR, "load_avp_user: Error while parsing From header field\n"); return -1; } uri = &get_from(msg)->uri; if (parse_uri(uri->s, uri->len, &puri) == -1) { LOG(L_ERR, "load_avp_user: Error while parsing From URI\n"); return -1; } return query_db(prefix, 0, &puri.user, &puri.host); } else if (param == LOAD_CALLEE) { if (parse_sip_msg_uri(msg) < 0) { LOG(L_ERR, "load_avp_user: Request-URI parsing failed\n"); return -1; } if (msg->parsed_uri_ok != 1) { LOG(L_ERR, "load_avp_user: Unable to parse Request-URI\n"); return -1; } return query_db(prefix, 0, &msg->parsed_uri.user, &msg->parsed_uri.host); } else { LOG(L_ERR, "load_avp_user: Unknown header field type\n"); return -1; } } static int load_avp(struct sip_msg* msg, char* attr, char* _dummy) { switch((load_avp_param_t)attr) { case LOAD_CALLER_UUID: return load_avp_uuid(msg, &caller_prefix, caller_uuid_avp); break; case LOAD_CALLEE_UUID: return load_avp_uuid(msg, &callee_prefix, callee_uuid_avp); break; case LOAD_CALLER: return load_avp_user(msg, &caller_prefix, LOAD_CALLER); break; case LOAD_CALLEE: return load_avp_user(msg, &callee_prefix, LOAD_CALLEE); break; default: LOG(L_ERR, "load_avp: Unknown parameter value\n"); return -1; } } static int load_avp_fixup(void** param, int param_no) { long id = 0; if (param_no == 1) { if (!strcasecmp(*param, "caller_uuid")) { id = LOAD_CALLER_UUID; } else if (!strcasecmp(*param, "callee_uuid")) { id = LOAD_CALLEE_UUID; } else if (!strcasecmp(*param, "caller")) { id = LOAD_CALLER; } else if (!strcasecmp(*param, "callee")) { id = LOAD_CALLEE; } else { LOG(L_ERR, "load_avp_fixup: Unknown parameter\n"); return -1; } } pkg_free(*param); *param=(void*)id; return 0; }