00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
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
00103 struct module_exports exports= {
00104 "xcap_client",
00105 DEFAULT_DLFLAGS,
00106 cmds,
00107 params,
00108 0,
00109 mi_cmds,
00110 0,
00111 0,
00112 mod_init,
00113 0,
00114 (destroy_function) destroy,
00115 0
00116 };
00117
00118
00119
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
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
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
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
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
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
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
00324
00325
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
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
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 }