xcap_client.c

Go to the documentation of this file.
00001 /*
00002  * $Id: xcap_client.c 2230 2007-06-06 07:13:20Z anca_vamanu $
00003  *
00004  * xcap_client module - XCAP client for openser
00005  *
00006  * Copyright (C) 2007 Voice Sistem S.R.L.
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * --------
00026  *  2007-08-20  initial version (anca)
00027  */
00028 
00029 #include <stdio.h>
00030 #include <string.h>
00031 #include <stdlib.h>
00032 #include <sys/types.h>
00033 #include <sys/ipc.h>
00034 #include <unistd.h>
00035 #include <fcntl.h>
00036 #include <time.h>
00037 #include <curl/curl.h>
00038 
00039 #include "../../pt.h"
00040 #include "../../db/db.h"
00041 #include "../../sr_module.h"
00042 #include "../../dprint.h"
00043 #include "../../error.h"
00044 #include "../../ut.h"
00045 #include "../../mem/mem.h"
00046 #include "../../mem/shm_mem.h"
00047 #include "../presence/utils_func.h"
00048 #include "xcap_functions.h"
00049 #include "xcap_client.h"
00050 
00051 MODULE_VERSION
00052 
00053 #define XCAP_TABLE_VERSION   3
00054 
00055 static int mod_init(void);
00056 void destroy(void);
00057 struct mi_root* refreshXcapDoc(struct mi_root* cmd, void* param);
00058 int get_auid_flag(str auid);
00059 str xcap_db_table = str_init("xcap");
00060 str xcap_db_url = str_init(DEFAULT_DB_URL);
00061 xcap_callback_t* xcapcb_list= NULL;
00062 int periodical_query= 1;
00063 unsigned int query_period= 100;
00064 
00065 str str_source_col = str_init("source");
00066 str str_path_col = str_init("path");
00067 str str_doc_col = str_init("doc");
00068 str str_etag_col = str_init("etag");
00069 str str_username_col = str_init("username");
00070 str str_domain_col = str_init("domain");
00071 str str_doc_type_col = str_init("doc_type");
00072 str str_doc_uri_col = str_init("doc_uri");
00073 str str_port_col = str_init("port");
00074 
00075 
00076 /* database connection */
00077 db_con_t *xcap_db = NULL;
00078 db_func_t xcap_dbf;
00079 
00080 void query_xcap_update(unsigned int ticks, void* param);
00081 
00082 static param_export_t params[]={
00083    { "db_url",             STR_PARAM,         &xcap_db_url.s    },
00084    { "xcap_table",            STR_PARAM,         &xcap_db_table.s  },
00085    { "periodical_query",      INT_PARAM,         &periodical_query },
00086    { "query_period",          INT_PARAM,         &query_period     },
00087    {    0,                     0,                      0            }
00088 };
00089 
00090 
00091 static cmd_export_t  cmds[]=
00092 {  
00093    {"bind_xcap",  (cmd_function)bind_xcap,  1,    0, 0,            0},
00094    {    0,                     0,           0,    0, 0,           0}
00095 };
00096 
00097 static mi_export_t mi_cmds[] = {
00098    { "refreshXcapDoc", refreshXcapDoc,      0,  0,  0},
00099    { 0,                 0,                  0,  0,  0}
00100 };
00101 
00102 /** module exports */
00103 struct module_exports exports= {
00104    "xcap_client",          /* module name */
00105    DEFAULT_DLFLAGS,        /* dlopen flags */
00106    cmds,                   /* exported functions */
00107    params,                 /* exported parameters */
00108    0,                   /* exported statistics */
00109    mi_cmds,                /* exported MI functions */
00110    0,                   /* exported pseudo-variables */
00111    0,                   /* extra processes */
00112    mod_init,               /* module initialization function */
00113    0,                   /* response handling function */
00114    (destroy_function) destroy, /* destroy function */
00115    0                    /* per-child init function */
00116 };
00117 
00118 /**
00119  * init module function
00120  */
00121 static int mod_init(void)
00122 {
00123    xcap_db_url.len = xcap_db_url.s ? strlen(xcap_db_url.s) : 0;
00124    xcap_db_table.len = xcap_db_table.s ? strlen(xcap_db_table.s) : 0;
00125    
00126    /* binding to mysql module  */
00127    if (db_bind_mod(&xcap_db_url, &xcap_dbf))
00128    {
00129       LM_ERR("Database module not found\n");
00130       return -1;
00131    }
00132    
00133    if (!DB_CAPABILITY(xcap_dbf, DB_CAP_ALL)) {
00134       LM_ERR("Database module does not implement all functions"
00135             " needed by the module\n");
00136       return -1;
00137    }
00138 
00139    xcap_db = xcap_dbf.init(&xcap_db_url);
00140    if (!xcap_db)
00141    {
00142       LM_ERR("while connecting to database\n");
00143       return -1;
00144    }
00145 
00146    if(db_check_table_version(&xcap_dbf, xcap_db, &xcap_db_table, XCAP_TABLE_VERSION) < 0) {
00147       LM_ERR("error during table version check.\n");
00148       return -1;
00149    }
00150 
00151    curl_global_init(CURL_GLOBAL_ALL);
00152 
00153    if(periodical_query)
00154    {
00155       register_timer(query_xcap_update, 0, query_period);
00156    }
00157    return 0;
00158 }
00159 
00160 void destroy(void)
00161 {
00162    curl_global_cleanup();
00163 }
00164 
00165 void query_xcap_update(unsigned int ticks, void* param)
00166 {
00167    db_key_t query_cols[3], update_cols[3];
00168    db_val_t query_vals[3], update_vals[3];
00169    db_key_t result_cols[7];
00170    int n_result_cols = 0, n_query_cols= 0, n_update_cols= 0;
00171    db_res_t* result= NULL;
00172    int user_col, domain_col, doc_type_col, etag_col, doc_uri_col, port_col; 
00173    db_row_t *row ;   
00174    db_val_t *row_vals ;
00175    unsigned int port;
00176    char* etag, *path, *new_etag= NULL, *doc= NULL;
00177    int u_doc_col, u_etag_col;
00178    str user, domain, uri;
00179    int i;
00180 
00181    /* query the ones I have to handle */
00182    query_cols[n_query_cols] = &str_source_col;
00183    query_vals[n_query_cols].type = DB_INT;
00184    query_vals[n_query_cols].nul = 0;
00185    query_vals[n_query_cols].val.int_val= XCAP_CL_MOD;
00186    n_query_cols++;
00187 
00188    query_cols[n_query_cols] = &str_path_col;
00189    query_vals[n_query_cols].type = DB_STR;
00190    query_vals[n_query_cols].nul = 0;
00191 
00192    update_cols[u_doc_col=n_update_cols] = &str_doc_col;
00193    update_vals[n_update_cols].type = DB_STRING;
00194    update_vals[n_update_cols].nul = 0;
00195    n_update_cols++;
00196 
00197    update_cols[u_etag_col=n_update_cols] = &str_etag_col;
00198    update_vals[n_update_cols].type = DB_STRING;
00199    update_vals[n_update_cols].nul = 0;
00200    n_update_cols++;
00201 
00202    result_cols[user_col= n_result_cols++]     = &str_username_col;
00203    result_cols[domain_col=n_result_cols++]    = &str_domain_col;
00204    result_cols[doc_type_col=n_result_cols++]  = &str_doc_type_col;
00205    result_cols[etag_col=n_result_cols++]      = &str_etag_col;
00206    result_cols[doc_uri_col= n_result_cols++]  = &str_doc_uri_col;
00207    result_cols[port_col= n_result_cols++]     = &str_port_col;
00208    
00209    if (xcap_dbf.use_table(xcap_db, &xcap_db_table) < 0) 
00210    {
00211       LM_ERR("in use_table-[table]= %.*s\n", xcap_db_table.len, xcap_db_table.s);
00212       goto error;
00213    }
00214 
00215    if(xcap_dbf.query(xcap_db, query_cols, 0, query_vals, result_cols, 1,
00216             n_result_cols, 0, &result)< 0)
00217    {
00218       LM_ERR("in sql query\n");
00219       goto error;
00220    }
00221    if(result== NULL)
00222    {
00223       LM_ERR("in sql query- null result\n");
00224       return;
00225    }
00226    if(result->n<= 0)
00227    {
00228       xcap_dbf.free_result(xcap_db, result);
00229       return;
00230    }
00231    n_query_cols++;
00232    
00233    /* ask if updated */
00234    for(i= 0; i< result->n; i++)
00235    {
00236       row = &result->rows[i];
00237       row_vals = ROW_VALUES(row);
00238    
00239       path= (char*)row_vals[doc_uri_col].val.string_val;
00240       port= row_vals[port_col].val.int_val;
00241       etag= (char*)row_vals[etag_col].val.string_val; 
00242 
00243       user.s= (char*)row_vals[user_col].val.string_val;
00244       user.len= strlen(user.s);
00245 
00246       domain.s= (char*)row_vals[domain_col].val.string_val;
00247       domain.len= strlen(domain.s);
00248 
00249       /* send HTTP request */
00250       doc= send_http_get(path, port, etag, IF_NONE_MATCH, &new_etag);
00251       if(doc== NULL)
00252       {
00253          LM_DBG("document not update\n");
00254          continue;
00255       }
00256       if(new_etag== NULL)
00257       {
00258          LM_ERR("etag not found\n");
00259          pkg_free(doc);
00260          goto error;
00261       }
00262       /* update in xcap db table */
00263       update_vals[u_doc_col].val.string_val= doc;
00264       update_vals[u_etag_col].val.string_val= etag;
00265       
00266       if(xcap_dbf.update(xcap_db, query_cols, 0, query_vals, update_cols,
00267                update_vals, n_query_cols, n_update_cols)< 0)
00268       {
00269          LM_ERR("in sql update\n");
00270          pkg_free(doc);
00271          goto error;
00272       }
00273       /* call registered callbacks */
00274       if(uandd_to_uri(user, domain, &uri)< 0)
00275       {
00276          LM_ERR("converting user and domain to uri\n");
00277          pkg_free(doc);
00278          goto error;
00279       }
00280       run_xcap_update_cb(row_vals[doc_type_col].val.int_val, uri, doc);
00281       pkg_free(doc);
00282 
00283    }
00284 
00285    xcap_dbf.free_result(xcap_db, result);
00286    return;
00287 
00288 error:
00289    if(result)
00290       xcap_dbf.free_result(xcap_db, result);
00291 }
00292 
00293 int parse_doc_url(str doc_url, char** serv_addr, xcap_doc_sel_t* doc_sel)
00294 {
00295    char* sl, *str_type; 
00296    
00297    sl= strchr(doc_url.s, '/');
00298    *sl= '\0';
00299    *serv_addr= doc_url.s;
00300    
00301    sl++;
00302    doc_sel->auid.s= sl;
00303    sl= strchr(sl, '/');
00304    doc_sel->auid.len= sl- doc_sel->auid.s;
00305    
00306    sl++;
00307    str_type= sl;
00308    sl= strchr(sl, '/');
00309    *sl= '\0';
00310 
00311    if(strcasecmp(str_type, "users")== 0)
00312       doc_sel->type= USERS_TYPE;
00313    else
00314    if(strcasecmp(str_type, "group")== 0)
00315       doc_sel->type= GLOBAL_TYPE;
00316 
00317    sl++;
00318 
00319    return 0;
00320 
00321 }
00322 /*
00323  * mi cmd: refreshXcapDoc
00324  *       <document uri> 
00325  *       <xcap_port>
00326  * */
00327 
00328 struct mi_root* refreshXcapDoc(struct mi_root* cmd, void* param)
00329 {
00330    struct mi_node* node= NULL;
00331    str doc_url;
00332    xcap_doc_sel_t doc_sel;
00333    char* serv_addr;
00334    char* stream= NULL;
00335    int type;
00336    unsigned int xcap_port;
00337    char* etag= NULL;
00338 
00339    node = cmd->node.kids;
00340    if(node == NULL)
00341       return 0;
00342 
00343    doc_url = node->value;
00344    if(doc_url.s == NULL || doc_url.len== 0)
00345    {
00346       LM_ERR("empty uri\n");
00347       return init_mi_tree(404, "Empty document URL", 20);
00348    }
00349    node= node->next;
00350    if(node== NULL)
00351       return 0;
00352    if(node->value.s== NULL || node->value.len== 0)
00353    {
00354       LM_ERR("port number\n");
00355       return init_mi_tree(404, "Empty document URL", 20);
00356    }
00357    if(str2int(&node->value, &xcap_port)< 0)
00358    {
00359       LM_ERR("while converting string to int\n");
00360       goto error;
00361    }
00362 
00363    if(node->next!= NULL)
00364       return 0;
00365 
00366    /* send GET HTTP request to the server */
00367    stream=  send_http_get(doc_url.s, xcap_port, NULL, 0, &etag);
00368    if(stream== NULL)
00369    {
00370       LM_ERR("in http get\n");
00371       return 0;
00372    }
00373    
00374    /* call registered functions with document argument */
00375    if(parse_doc_url(doc_url, &serv_addr, &doc_sel)< 0)
00376    {
00377       LM_ERR("parsing document url\n");
00378       return 0;
00379    }
00380 
00381    type= get_auid_flag(doc_sel.auid);
00382    if(type< 0)
00383    {
00384       LM_ERR("incorect auid: %.*s\n",
00385             doc_sel.auid.len, doc_sel.auid.s);
00386       goto error;
00387    }
00388 
00389    run_xcap_update_cb(type, doc_sel.xid, stream);
00390 
00391    return init_mi_tree(200, "OK", 2);
00392 
00393 error:
00394    if(stream)
00395       pkg_free(stream);
00396    return 0;
00397 }
00398 
00399 #define STR_MATCH(s1, s2)   ((s1).len==(s2).len && memcmp((s1).s, (s2).s, (s1).len)==0)
00400 
00401 int get_auid_flag(str auid)
00402 {
00403    static str pres_rules = str_init("pres-rules");
00404    static str rls_services = str_init("rls-services");
00405 
00406    if (STR_MATCH(auid, pres_rules))
00407       return PRES_RULES;
00408    else if (STR_MATCH(auid, rls_services))
00409       return RESOURCE_LIST;
00410 
00411    return -1;
00412 }

Generated on Fri May 25 00:00:35 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6