xcap_functions.c

Go to the documentation of this file.
00001 /*
00002  * $Id: xcap_functions.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 #include "../../mem/mem.h"
00039 #include "../../db/db.h"
00040 #include "xcap_functions.h"
00041 #include "xcap_client.h"
00042 #include "../presence/hash.h"
00043 
00044 
00045 #define ETAG_HDR          "Etag: "
00046 #define ETAG_HDR_LEN      strlen("Etag: ")
00047 
00048 size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream);
00049 char* get_xcap_path(xcap_get_req_t req);
00050 
00051 int bind_xcap(xcap_api_t* api)
00052 {
00053    if (!api) 
00054    {
00055       LM_ERR("Invalid parameter value\n");
00056       return -1;
00057    }
00058    api->get_elem= xcapGetElem;
00059    api->int_node_sel= xcapInitNodeSel;
00060    api->add_step= xcapNodeSelAddStep;
00061    api->add_terminal= xcapNodeSelAddTerminal;
00062    api->free_node_sel= xcapFreeNodeSel;
00063    api->register_xcb= register_xcapcb;
00064    api->getNewDoc= xcapGetNewDoc;
00065    
00066    return 0;
00067 }
00068 
00069 void xcapFreeNodeSel(xcap_node_sel_t* node)
00070 {
00071    step_t* s, *p;
00072    ns_list_t* n, *m;
00073 
00074    s= node->steps;
00075    while(s)
00076    {
00077       p= s;
00078       s= s->next;
00079       pkg_free(p->val.s);
00080       pkg_free(p);
00081    }
00082 
00083    n= node->ns_list;
00084    while(n)
00085    {
00086       m= n;
00087       n= n->next;
00088       pkg_free(n->value.s);
00089       pkg_free(n);
00090    }
00091 
00092    pkg_free(node);
00093 
00094 }
00095 
00096 xcap_node_sel_t* xcapInitNodeSel(void)
00097 {
00098    xcap_node_sel_t* nsel= NULL;
00099 
00100    nsel= (xcap_node_sel_t*)pkg_malloc(sizeof(xcap_node_sel_t));
00101    if(nsel== NULL)
00102    {
00103       ERR_MEM(PKG_MEM_STR);
00104    }
00105    memset(nsel, 0, sizeof(xcap_node_sel_t));
00106    nsel->steps= (step_t*)pkg_malloc(sizeof(step_t));
00107    if(nsel->steps== NULL)
00108    {
00109       ERR_MEM(PKG_MEM_STR);
00110    }
00111    memset(nsel->steps, 0, sizeof(step_t));
00112    nsel->last_step= nsel->steps;
00113 
00114    nsel->ns_list= (ns_list_t*)pkg_malloc(sizeof(ns_list_t));
00115    if(nsel->ns_list== NULL)
00116    {
00117       ERR_MEM(PKG_MEM_STR);
00118    }
00119    memset(nsel->ns_list, 0, sizeof(ns_list_t));
00120    nsel->last_ns= nsel->ns_list;
00121 
00122    return nsel;
00123 
00124 error:
00125    if(nsel)
00126    {
00127       if(nsel->steps)
00128          pkg_free(nsel->steps);
00129       if(nsel->ns_list)
00130          pkg_free(nsel->ns_list);
00131       pkg_free(nsel);
00132    }
00133 
00134    return NULL;
00135 }
00136 
00137 xcap_node_sel_t* xcapNodeSelAddStep(xcap_node_sel_t* curr_sel, str* name,
00138       str* namespace, int pos, attr_test_t*  attr_test, str* extra_sel)
00139 {
00140    int size= 0;
00141    str new_step= {NULL, 0};
00142    step_t* s= NULL;
00143    char ns_card= 'a';
00144    ns_list_t* ns= NULL;
00145 
00146    if(name)
00147       size+= name->len;
00148    else
00149       size+= 1;
00150 
00151    if(namespace)
00152       size+= 2;
00153    if(pos> 0)
00154       size+= 7;
00155    if(attr_test)
00156       size+= 2+ attr_test->name.len+ attr_test->value.len;
00157    if(extra_sel)
00158       size+= 2+ extra_sel->len;
00159    
00160    new_step.s= (char*)pkg_malloc(size* sizeof(char));
00161    if(new_step.s== NULL)
00162    {
00163       ERR_MEM(PKG_MEM_STR);
00164    }
00165    if(name)
00166    {
00167       if(namespace)
00168       {
00169          ns_card= curr_sel->ns_no+ 'a';
00170          curr_sel->ns_no++;
00171 
00172          if(ns_card> 'z')
00173          {
00174             LM_ERR("Insuficient name cards for namespaces\n");
00175             goto error;
00176          }
00177          new_step.len= sprintf(new_step.s, "%c:", ns_card);    
00178       }
00179       memcpy(new_step.s+new_step.len, name->s, name->len);
00180       new_step.len+= name->len;
00181    }
00182    else
00183       memcpy(new_step.s+new_step.len, "*", 1);
00184 
00185    if(attr_test)
00186    {
00187       new_step.len+= sprintf(new_step.s+ new_step.len, "[%.*s=%.*s]", attr_test->name.len,
00188             attr_test->name.s, attr_test->value.len, attr_test->value.s);
00189    }
00190    if(pos> 0)
00191       new_step.len+= sprintf(new_step.s+ new_step.len, "[%d]", pos);
00192 
00193    if(extra_sel)
00194    {
00195       memcpy(new_step.s+ new_step.len, extra_sel->s, extra_sel->len);
00196       new_step.len= extra_sel->len;
00197    }
00198 
00199    s= (step_t*)pkg_malloc(sizeof(step_t));
00200    if(s== NULL)
00201    {
00202       ERR_MEM(PKG_MEM_STR);
00203    }
00204    s->val= new_step;
00205    s->next= NULL;
00206 
00207    curr_sel->last_step->next= s;
00208    curr_sel->last_step= s;
00209 
00210    /* add the namespace binding if present */
00211    if(namespace)
00212    {
00213       ns= (ns_list_t*)pkg_malloc(sizeof(ns_list_t));
00214       if(ns== NULL)
00215       {
00216          ERR_MEM(PKG_MEM_STR);
00217       }
00218       ns->name= ns_card;
00219       ns->value.s= (char*)pkg_malloc(namespace->len* sizeof(char));
00220       if(ns->value.s== NULL)
00221       {
00222          ERR_MEM(PKG_MEM_STR);
00223       }
00224       memcpy(ns->value.s, namespace->s, namespace->len);
00225       ns->value.len= namespace->len;
00226 
00227       curr_sel->last_ns->next= ns;
00228       curr_sel->last_ns= ns;
00229    }
00230 
00231    curr_sel->size+= 1+ new_step.len;
00232    if(namespace->len)
00233    {
00234       curr_sel->size+= namespace->len+ 3;
00235    }
00236    
00237    return curr_sel;
00238 
00239 error:
00240    if(new_step.s)
00241       pkg_free(new_step.s);
00242    if(s)
00243       pkg_free(s);
00244    if(ns)
00245    {
00246       if(ns->value.s)
00247          pkg_free(ns->value.s);
00248       pkg_free(ns);
00249    }
00250 
00251    return NULL;
00252 }
00253 
00254 xcap_node_sel_t* xcapNodeSelAddTerminal(xcap_node_sel_t* curr_sel, 
00255       char* attr_sel, char* namespace_sel, char* extra_sel )
00256 {
00257 
00258    return NULL;
00259 }
00260 
00261 char* get_node_selector(xcap_node_sel_t* node_sel)
00262 {
00263    char* buf= NULL;
00264    step_t* s;
00265    int len= 0;
00266    ns_list_t* ns_elem;
00267 
00268    buf= (char*)pkg_malloc((node_sel->size+ 10)* sizeof(char));
00269    if(buf== NULL)
00270    {
00271       ERR_MEM(PKG_MEM_STR);
00272    }
00273 
00274    s= node_sel->steps->next;
00275 
00276    while(1)
00277    {
00278       memcpy(buf+ len, s->val.s, s->val.len);
00279       len+= s->val.len;
00280       s= s->next;
00281       if(s)
00282          buf[len++]= '/';
00283       else
00284          break;
00285    }
00286    ns_elem= node_sel->ns_list;
00287 
00288    if(ns_elem)
00289       buf[len++]= '?';
00290    
00291    while(ns_elem)
00292    {
00293       len+= sprintf(buf+ len, "xmlns(%c=%.*s)", ns_elem->name,
00294             ns_elem->value.len, ns_elem->value.s);
00295       ns_elem= ns_elem->next;
00296    }
00297    
00298    buf[len]= '\0';
00299 
00300    return buf;
00301 
00302 error:
00303    return NULL;
00304 }
00305 
00306 char* xcapGetNewDoc(xcap_get_req_t req, str user, str domain)
00307 {
00308    char* etag= NULL;
00309    char* doc= NULL;
00310    db_key_t query_cols[9];
00311    db_val_t query_vals[9];
00312    int n_query_cols = 0;
00313    char* path= NULL;
00314 
00315    path= get_xcap_path(req);
00316    if(path== NULL)
00317    {
00318       LM_ERR("while constructing xcap path\n");
00319       return NULL;
00320    }
00321    /* send HTTP request */
00322    doc= send_http_get(path, req.port, NULL, 0, &etag);
00323    if(doc== NULL)
00324    {
00325       LM_DBG("the searched document was not found\n");
00326       goto done;
00327    }
00328 
00329    if(etag== NULL)
00330    {
00331       LM_ERR("no etag found\n");
00332       pkg_free(doc); 
00333       doc= NULL;
00334       goto done;
00335    }
00336    /* insert in xcap table*/
00337    query_cols[n_query_cols] = &str_username_col;
00338    query_vals[n_query_cols].type = DB_STR;
00339    query_vals[n_query_cols].nul = 0;
00340    query_vals[n_query_cols].val.str_val = user;
00341    n_query_cols++;
00342    
00343    query_cols[n_query_cols] = &str_domain_col;
00344    query_vals[n_query_cols].type = DB_STR;
00345    query_vals[n_query_cols].nul = 0;
00346    query_vals[n_query_cols].val.str_val = domain;
00347    n_query_cols++;
00348    
00349    query_cols[n_query_cols] = &str_doc_type_col;
00350    query_vals[n_query_cols].type = DB_INT;
00351    query_vals[n_query_cols].nul = 0;
00352    query_vals[n_query_cols].val.int_val= req.doc_sel.doc_type;
00353    n_query_cols++;
00354 
00355    query_cols[n_query_cols] = &str_doc_col;
00356    query_vals[n_query_cols].type = DB_STRING;
00357    query_vals[n_query_cols].nul = 0;
00358    query_vals[n_query_cols].val.string_val= doc;
00359    n_query_cols++;
00360 
00361    query_cols[n_query_cols] = &str_etag_col;
00362    query_vals[n_query_cols].type = DB_STRING;
00363    query_vals[n_query_cols].nul = 0;
00364    query_vals[n_query_cols].val.string_val= etag;
00365    n_query_cols++;
00366 
00367    query_cols[n_query_cols] = &str_source_col;
00368    query_vals[n_query_cols].type = DB_INT;
00369    query_vals[n_query_cols].nul = 0;
00370    query_vals[n_query_cols].val.int_val= XCAP_CL_MOD;
00371    n_query_cols++;
00372 
00373    query_cols[n_query_cols] = &str_doc_uri_col;
00374    query_vals[n_query_cols].type = DB_STRING;
00375    query_vals[n_query_cols].nul = 0;
00376    query_vals[n_query_cols].val.string_val= path;
00377    n_query_cols++;
00378    
00379    query_cols[n_query_cols] = &str_port_col;
00380    query_vals[n_query_cols].type = DB_INT;
00381    query_vals[n_query_cols].nul = 0;
00382    query_vals[n_query_cols].val.int_val= req.port;
00383    n_query_cols++;
00384 
00385    if (xcap_dbf.use_table(xcap_db, &xcap_db_table) < 0) 
00386    {
00387       LM_ERR("in use_table-[table]= %.*s\n", xcap_db_table.len, xcap_db_table.s);
00388       goto done;
00389    }
00390    
00391    if(xcap_dbf.insert(xcap_db, query_cols, query_vals, n_query_cols)< 0)
00392    {
00393       LM_ERR("in sql insert\n");
00394       goto done;
00395    }
00396 
00397 done:
00398    pkg_free(path);
00399    return doc;
00400 }
00401 
00402 char* get_xcap_path(xcap_get_req_t req)
00403 {
00404    int len= 0, size;
00405    char* path= NULL;
00406    char* node_selector= NULL;
00407 
00408    len= (strlen(req.xcap_root)+ 1+ req.doc_sel.auid.len+ 5+
00409          req.doc_sel.xid.len+ req.doc_sel.filename.len+ 50)* sizeof(char);
00410    
00411    if(req.node_sel)
00412       len+= req.node_sel->size;
00413 
00414    path= (char*)pkg_malloc(len);
00415    if(path== NULL)
00416    {
00417       ERR_MEM(PKG_MEM_STR);
00418    }
00419 
00420    if(req.node_sel)
00421    {
00422       node_selector= get_node_selector(req.node_sel);
00423       if(node_selector== NULL)
00424       {
00425          LM_ERR("while constructing node selector\n");
00426          goto error;
00427       }
00428    }
00429    
00430    size= sprintf(path, "%s/%.*s/", req.xcap_root, req.doc_sel.auid.len,
00431          req.doc_sel.auid.s);
00432 
00433    if(req.doc_sel.type==USERS_TYPE)
00434       size+= sprintf(path+ size, "%s/%.*s/", "users", req.doc_sel.xid.len,
00435             req.doc_sel.xid.s);
00436    else
00437       size+= sprintf(path+ size, "%s/", "global");
00438    size+= sprintf(path+ size, "%.*s", req.doc_sel.filename.len,
00439          req.doc_sel.filename.s);
00440    
00441    if(node_selector)
00442    {
00443       size+= sprintf(path+ size, "/~~%s", node_selector);
00444    }
00445 
00446    if(size> len)
00447    {
00448       LM_ERR("buffer size overflow\n");
00449       goto error;
00450    }
00451    pkg_free(node_selector);
00452 
00453    return path;
00454    
00455 error:
00456    if(path)
00457       pkg_free(path);
00458    if(node_selector)
00459       pkg_free(node_selector);
00460    return NULL;
00461 }
00462 
00463 /* xcap_root must be a NULL terminated string */
00464 
00465 char* xcapGetElem(xcap_get_req_t req, char** etag)
00466 {
00467    char* path= NULL;
00468    char* stream= NULL;
00469    
00470    path= get_xcap_path(req);
00471    if(path== NULL)
00472    {
00473       LM_ERR("while constructing xcap path\n");
00474       return NULL;
00475    }
00476 
00477    stream= send_http_get(path, req.port, req.etag, req.match_type, etag);
00478    if(stream== NULL)
00479    {
00480       LM_DBG("the serched element was not found\n");
00481    }
00482    
00483    if(etag== NULL)
00484    {
00485       LM_ERR("no etag found\n");
00486       pkg_free(stream);
00487       stream= NULL;
00488    }
00489 
00490    if(path)
00491       pkg_free(path);
00492    
00493    return stream;
00494 }
00495 
00496 size_t get_xcap_etag( void *ptr, size_t size, size_t nmemb, void *stream)
00497 {
00498    int len= 0;
00499    char* etag= NULL;
00500 
00501    if(strncasecmp(ptr, ETAG_HDR, ETAG_HDR_LEN)== 0)
00502    {
00503       len= size* nmemb- ETAG_HDR_LEN;
00504       etag= (char*)pkg_malloc((len+ 1)* sizeof(char));
00505       if(etag== NULL)
00506       {
00507          ERR_MEM(PKG_MEM_STR);
00508       }
00509       memcpy(etag, ptr+ETAG_HDR_LEN, len);
00510       etag[len]= '\0';
00511       *((char**)stream)= etag;
00512    }
00513    return len;
00514 
00515 error:
00516    return -1;
00517 }
00518 
00519 char* send_http_get(char* path, unsigned int xcap_port, char* match_etag,
00520       int match_type, char** etag)
00521 {
00522    int len;
00523    char* stream= NULL;
00524    CURLcode ret_code;
00525    CURL* curl_handle= NULL;
00526    static char buf[128];
00527    char* match_header= NULL;
00528    *etag= NULL;
00529    
00530    if(match_etag)
00531    {
00532       char* hdr_name= NULL;
00533       
00534       memset(buf, 128* sizeof(char), 0);
00535       match_header= buf;
00536       
00537       hdr_name= (match_type==IF_MATCH)?"If-Match":"If-None-Match"; 
00538       
00539       len=sprintf(match_header, "%s: %s\n", hdr_name, match_etag);
00540       
00541       match_header[len]= '\0';   
00542    }
00543 
00544    curl_handle = curl_easy_init();
00545    
00546    curl_easy_setopt(curl_handle, CURLOPT_URL, path);
00547    
00548    curl_easy_setopt(curl_handle, CURLOPT_PORT, xcap_port);
00549 
00550    curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1); 
00551 
00552    curl_easy_setopt(curl_handle,  CURLOPT_STDERR, stdout);  
00553    
00554    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_function);
00555    
00556    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &stream);
00557 
00558    curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, get_xcap_etag);
00559    
00560    curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, &etag);
00561 
00562    if(match_header)
00563       curl_easy_setopt(curl_handle, CURLOPT_HEADER, (long)match_header);
00564 
00565    /* non-2xx => error */
00566    curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
00567 
00568    ret_code= curl_easy_perform(curl_handle );
00569    
00570    if( ret_code== CURLE_WRITE_ERROR)
00571    {
00572       LM_ERR("while performing curl option\n");
00573       if(stream)
00574          pkg_free(stream);
00575       stream= NULL;
00576       return NULL;
00577    }
00578 
00579    curl_global_cleanup();
00580    return stream;
00581 }
00582 
00583 size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream)
00584 {
00585    /* allocate memory and copy */
00586    char* data;
00587 
00588    data= (char*)pkg_malloc(size* nmemb);
00589    if(data== NULL)
00590    {
00591       ERR_MEM(PKG_MEM_STR);
00592    }
00593 
00594    memcpy(data, (char*)ptr, size* nmemb);
00595    
00596    *((char**) stream)= data;
00597 
00598    return size* nmemb;
00599 
00600 error:
00601    return CURLE_WRITE_ERROR;
00602 }

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