ul_mi.c

Go to the documentation of this file.
00001 /*
00002  * $Id: ul_mi.c 5194 2008-11-13 10:38:11Z henningw $
00003  *
00004  * Copyright (C) 2006 Voice Sistem SRL
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * ---------
00024  *
00025  * 2006-12-01  created (bogdan)
00026  */
00027 
00028 /*! \file
00029  *  \brief USRLOC - Usrloc MI functions
00030  *  \ingroup usrloc
00031  *
00032  * - Module: \ref usrloc
00033  */
00034 
00035 #include <string.h>
00036 #include <stdio.h>
00037 #include "../../mi/mi.h"
00038 #include "../../dprint.h"
00039 #include "../../ut.h"
00040 #include "../../qvalue.h"
00041 #include "../../ip_addr.h"
00042 #include "ul_mi.h"
00043 #include "dlist.h"
00044 #include "udomain.h"
00045 #include "utime.h"
00046 #include "ul_mod.h"
00047 
00048 
00049 /*! CSEQ nr used */
00050 #define MI_UL_CSEQ 1
00051 /*! call-id used for ul_add and ul_rm_contact */
00052 static str mi_ul_cid = str_init("dfjrewr12386fd6-343@openser.mi");
00053 /*! user agent used for ul_add */
00054 static str mi_ul_ua  = str_init("Kamailio MI Server");
00055 
00056 
00057 /************************ helper functions ****************************/
00058 
00059 /*!
00060  * \brief Search a domain in the global domain list
00061  * \param table domain (table) name
00062  * \return pointer to domain if found, 0 if not found
00063  */
00064 static inline udomain_t* mi_find_domain(str* table)
00065 {
00066    dlist_t* dom;
00067 
00068    for( dom=root ; dom ; dom=dom->next ) {
00069       if ((dom->name.len == table->len) &&
00070       !memcmp(dom->name.s, table->s, table->len))
00071          return dom->d;
00072    }
00073    return 0;
00074 }
00075 
00076 
00077 /*!
00078  * \brief Convert address of record
00079  *
00080  * Convert an address of record string to lower case, and truncate
00081  * it when use_domain is not set.
00082  * \param aor address of record
00083  * \return 0 on success, -1 on error
00084  */
00085 static inline int mi_fix_aor(str *aor)
00086 {
00087    char *p;
00088 
00089    p = memchr( aor->s, '@', aor->len);
00090    if (use_domain) {
00091       if (p==NULL)
00092          return -1;
00093    } else {
00094       if (p)
00095          aor->len = p - aor->s;
00096    }
00097    strlower(aor);
00098 
00099    return 0;
00100 }
00101 
00102 
00103 /*!
00104  * \brief Add a node for a address of record
00105  * \param parent parent node
00106  * \param r printed record
00107  * \param t actual time
00108  * \param short_dump 0 means that all informations will be included, 1 that only the AOR is printed
00109  * \return 0 on success, -1 on failure
00110  */
00111 static inline int mi_add_aor_node(struct mi_node *parent, urecord_t* r, time_t t, int short_dump)
00112 {
00113    struct mi_node *anode, *cnode, *node;
00114    struct mi_attr *attr;
00115    ucontact_t* c;
00116    char *p;
00117    int len;
00118 
00119    anode = add_mi_node_child( parent, MI_DUP_VALUE, "AOR", 3,
00120          r->aor.s, r->aor.len);
00121    if (anode==0)
00122       return -1;
00123 
00124    if (short_dump)
00125       return 0;
00126 
00127    for( c=r->contacts ; c ; c=c->next) {
00128       /* contact */
00129       cnode = add_mi_node_child( anode, MI_DUP_VALUE, "Contact", 7,
00130          c->c.s, c->c.len);
00131       if (cnode==0)
00132          return -1;
00133 
00134       /* expires */
00135       if (c->expires == 0) {
00136          node = add_mi_node_child( cnode, 0, "Expires", 7, "permanent", 9);
00137       } else if (c->expires == UL_EXPIRED_TIME) {
00138          node = add_mi_node_child( cnode, 0, "Expires", 7, "deleted", 7);
00139       } else if (t > c->expires) {
00140          node = add_mi_node_child( cnode, 0, "Expires", 7, "expired", 7);
00141       } else {
00142          p = int2str((unsigned long)(c->expires - t), &len);
00143          node = add_mi_node_child( cnode, MI_DUP_VALUE, "Expires", 7,p,len);
00144       }
00145       if (node==0)
00146          return -1;
00147 
00148       /* q */
00149       p = q2str(c->q, (unsigned int*)&len);
00150       attr = add_mi_attr( cnode, MI_DUP_VALUE, "Q", 1, p, len);
00151       if (attr==0)
00152          return -1;
00153 
00154       /* callid */
00155       node = add_mi_node_child( cnode, MI_DUP_VALUE, "Callid", 6,
00156          c->callid.s, c->callid.len);
00157       if (node==0)
00158          return -1;
00159 
00160       /* cseq */
00161       p = int2str((unsigned long)c->cseq, &len);
00162       node = add_mi_node_child( cnode, MI_DUP_VALUE, "Cseq", 4, p, len);
00163       if (node==0)
00164          return -1;
00165 
00166       /* User-Agent */
00167       if (c->user_agent.len) {
00168          node = add_mi_node_child( cnode, MI_DUP_VALUE, "User-agent", 10,
00169             c->user_agent.s, c->user_agent.len);
00170          if (node==0)
00171             return -1;
00172       }
00173 
00174       /* received */
00175       if (c->received.len) {
00176          node = add_mi_node_child( cnode, MI_DUP_VALUE, "Received", 8,
00177             c->received.s, c->received.len);
00178          if (node==0)
00179             return -1;
00180       }
00181 
00182       /* path */
00183       if (c->path.len) {
00184          node = add_mi_node_child( cnode, MI_DUP_VALUE, "Path", 4,
00185             c->path.s, c->path.len);
00186          if (node==0)
00187             return -1;
00188       }
00189 
00190       /* state */
00191       if (c->state == CS_NEW) {
00192          node = add_mi_node_child( cnode, 0, "State", 5, "CS_NEW", 6);
00193       } else if (c->state == CS_SYNC) {
00194          node = add_mi_node_child( cnode, 0, "State", 5, "CS_SYNC", 7);
00195       } else if (c->state== CS_DIRTY) {
00196          node = add_mi_node_child( cnode, 0, "State", 5, "CS_DIRTY", 8);
00197       } else {
00198          node = add_mi_node_child( cnode, 0, "State", 5, "CS_UNKNOWN", 10);
00199       }
00200       if (node==0)
00201          return -1;
00202 
00203       /* flags */
00204       p = int2str((unsigned long)c->flags, &len);
00205       node = add_mi_node_child( cnode, MI_DUP_VALUE, "Flags", 5, p, len);
00206       if (node==0)
00207          return -1;
00208 
00209       /* cflags */
00210       p = int2str((unsigned long)c->cflags, &len);
00211       node = add_mi_node_child( cnode, MI_DUP_VALUE, "Cflags", 5, p, len);
00212       if (node==0)
00213          return -1;
00214 
00215       /* socket */
00216       if (c->sock) {
00217          node = add_mi_node_child( cnode, 0, "Socket", 6,
00218             c->sock->sock_str.s, c->sock->sock_str.len);
00219          if (node==0)
00220             return -1;
00221       }
00222 
00223       /* methods */
00224       p = int2str((unsigned long)c->methods, &len);
00225       node = add_mi_node_child( cnode, MI_DUP_VALUE, "Methods", 7, p, len);
00226       if (node==0)
00227          return -1;
00228 
00229    } /* for */
00230 
00231    return 0;
00232 }
00233 
00234 
00235 /*************************** MI functions *****************************/
00236 
00237 /*!
00238  * \brief Delete a address of record including its contacts
00239  * \param cmd mi_root containing the parameter
00240  * \param param not used
00241  * \note expects 2 nodes: the table name and the AOR
00242  * \return mi_root with the result
00243  */
00244 struct mi_root* mi_usrloc_rm_aor(struct mi_root *cmd, void *param)
00245 {
00246    struct mi_node *node;
00247    udomain_t *dom;
00248    str *aor;
00249 
00250    node = cmd->node.kids;
00251    if (node==NULL || node->next==NULL || node->next->next!=NULL)
00252       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00253 
00254    /* look for table */
00255    dom = mi_find_domain( &node->value );
00256    if (dom==NULL)
00257       return init_mi_tree( 404, "Table not found", 15);
00258 
00259    /* process the aor */
00260    aor = &node->next->value;
00261    if ( mi_fix_aor(aor)!=0 )
00262       return init_mi_tree( 400, "Domain missing in AOR", 21);
00263 
00264    lock_udomain( dom, aor);
00265    if (delete_urecord( dom, aor, 0) < 0) {
00266       unlock_udomain( dom, aor);
00267       return init_mi_tree( 500, "Failed to delete AOR", 20);
00268    }
00269 
00270    unlock_udomain( dom, aor);
00271    return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00272 }
00273 
00274 
00275 /*!
00276  * \brief Delete a contact from an AOR record
00277  * \param cmd mi_root containing the parameter
00278  * \param param not used
00279  * \note expects 3 nodes: the table name, the AOR and contact
00280  * \return mi_root with the result or 0 on failure
00281  */
00282 struct mi_root* mi_usrloc_rm_contact(struct mi_root *cmd, void *param)
00283 {
00284    struct mi_node *node;
00285    udomain_t *dom;
00286    urecord_t *rec;
00287    ucontact_t* con;
00288    str *aor, *contact;
00289    int ret;
00290 
00291    node = cmd->node.kids;
00292    if (node==NULL || node->next==NULL || node->next->next==NULL ||
00293    node->next->next->next!=NULL)
00294       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00295 
00296    /* look for table */
00297    dom = mi_find_domain( &node->value );
00298    if (dom==NULL)
00299       return init_mi_tree( 404, "Table not found", 15);
00300 
00301    /* process the aor */
00302    aor = &node->next->value;
00303    if ( mi_fix_aor(aor)!=0 )
00304       return init_mi_tree( 400, "Domain missing in AOR", 21);
00305 
00306    lock_udomain( dom, aor);
00307 
00308    ret = get_urecord( dom, aor, &rec);
00309    if (ret == 1) {
00310       unlock_udomain( dom, aor);
00311       return init_mi_tree( 404, "AOR not found", 13);
00312    }
00313 
00314    contact = &node->next->next->value;
00315    ret = get_ucontact( rec, contact, &mi_ul_cid, MI_UL_CSEQ+1, &con);
00316    if (ret < 0) {
00317       unlock_udomain( dom, aor);
00318       return 0;
00319    }
00320    if (ret > 0) {
00321       unlock_udomain( dom, aor);
00322       return init_mi_tree( 404, "Contact not found", 17);
00323    }
00324 
00325    if (delete_ucontact(rec, con) < 0) {
00326       unlock_udomain( dom, aor);
00327       return 0;
00328    }
00329 
00330    release_urecord(rec);
00331    unlock_udomain( dom, aor);
00332    return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00333 }
00334 
00335 
00336 /*!
00337  * \brief Dump the content of the usrloc
00338  * \param cmd mi_root containing the parameter
00339  * \param param not used
00340  * \return mi_root with the result or 0 on failure
00341  */
00342 struct mi_root* mi_usrloc_dump(struct mi_root *cmd, void *param)
00343 {
00344    struct mi_root *rpl_tree;
00345    struct mi_node *rpl, *node;
00346    struct mi_attr *attr;
00347    struct urecord* r;
00348    dlist_t* dl;
00349    udomain_t* dom;
00350    time_t t;
00351    char *p;
00352    int max, len, n, i, short_dump;
00353 
00354    node = cmd->node.kids;
00355    if (node && node->next)
00356       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00357 
00358    if (node && node->value.len==5 && !strncasecmp(node->value.s, "brief", 5)){
00359       /* short version */
00360       short_dump = 1;
00361    } else {
00362       short_dump = 0;
00363    }
00364 
00365    rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00366    if (rpl_tree==NULL)
00367       return 0;
00368    rpl = &rpl_tree->node;
00369    t = time(0);
00370 
00371    for( dl=root ; dl ; dl=dl->next ) {
00372       /* add a domain node */
00373       node = add_mi_node_child( rpl, 0, "Domain", 6,
00374                dl->name.s, dl->name.len);
00375       if (node==0)
00376          goto error;
00377 
00378       dom = dl->d;
00379       /* add some attributes to the domain node */
00380       p= int2str((unsigned long)dom->size, &len);
00381       attr = add_mi_attr( node, MI_DUP_VALUE, "table", 5, p, len);
00382       if (attr==0)
00383          goto error;
00384 
00385       /* add the entries per hash */
00386       for(i=0,n=0,max=0; i<dom->size; i++) {
00387          lock_ulslot( dom, i);
00388 
00389          n += dom->table[i].n;
00390          if(max<dom->table[i].n)
00391             max= dom->table[i].n;
00392          for( r = dom->table[i].first ; r ; r=r->next ) {
00393             /* add entry */
00394             if (mi_add_aor_node( node, r, t, short_dump)!=0) {
00395                unlock_ulslot( dom, i);
00396                goto error;
00397             }
00398          }
00399 
00400          unlock_ulslot( dom, i);
00401       }
00402 
00403       /* add more attributes to the domain node */
00404       p= int2str((unsigned long)n, &len);
00405       attr = add_mi_attr( node, MI_DUP_VALUE, "records", 7, p, len);
00406       if (attr==0)
00407          goto error;
00408 
00409       p= int2str((unsigned long)max, &len);
00410       attr = add_mi_attr( node, MI_DUP_VALUE, "max_slot", 8, p, len);
00411       if (attr==0)
00412          goto error;
00413 
00414    }
00415 
00416    return rpl_tree;
00417 error:
00418    free_mi_tree(rpl_tree);
00419    return 0;
00420 }
00421 
00422 
00423 /*!
00424  * \brief Flush the usrloc memory cache to DB
00425  * \param cmd mi_root containing the parameter
00426  * \param param not used
00427  * \return mi_root with the result or 0 on failure
00428  */
00429 struct mi_root* mi_usrloc_flush(struct mi_root *cmd, void *param)
00430 {
00431    struct mi_root *rpl_tree;
00432 
00433    rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00434    if (rpl_tree==NULL)
00435       return 0;
00436 
00437    synchronize_all_udomains();
00438    return rpl_tree;
00439 }
00440 
00441 
00442 /*!
00443  * \brief Add a new contact for an address of record
00444  * \param cmd mi_root containing the parameter
00445  * \param param not used
00446  * \note Expects 7 nodes: table name, AOR, contact, expires, Q,
00447  * useless - backward compatible, flags, cflags, methods
00448  * \return mi_root with the result
00449  */
00450 struct mi_root* mi_usrloc_add(struct mi_root *cmd, void *param)
00451 {
00452    ucontact_info_t ci;
00453    urecord_t* r;
00454    ucontact_t* c;
00455    struct mi_node *node;
00456    udomain_t *dom;
00457    str *aor, *contact;
00458    unsigned int ui_val;
00459    int n;
00460 
00461    for( n=0,node = cmd->node.kids; n<9 && node ; n++,node=node->next );
00462    if (n!=9 || node!=0)
00463       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00464 
00465    node = cmd->node.kids;
00466 
00467    /* look for table (param 1) */
00468    dom = mi_find_domain( &node->value );
00469    if (dom==NULL)
00470       return init_mi_tree( 404, "Table not found", 15);
00471 
00472    /* process the aor (param 2) */
00473    node = node->next;
00474    aor = &node->value;
00475    if ( mi_fix_aor(aor)!=0 )
00476       return init_mi_tree( 400, "Domain missing in AOR", 21);
00477 
00478    /* contact (param 3) */
00479    node = node->next;
00480    contact = &node->value;
00481 
00482    memset( &ci, 0, sizeof(ucontact_info_t));
00483 
00484    /* expire (param 4) */
00485    node = node->next;
00486    if (str2int( &node->value, &ui_val) < 0)
00487       goto bad_syntax;
00488    ci.expires = ui_val;
00489 
00490    /* q value (param 5) */
00491    node = node->next;
00492    if (str2q( &ci.q, node->value.s, node->value.len) < 0)
00493       goto bad_syntax;
00494 
00495    /* unused value (param 6) FIXME */
00496    node = node->next;
00497 
00498    /* flags value (param 7) */
00499    node = node->next;
00500    if (str2int( &node->value, (unsigned int*)&ci.flags) < 0)
00501       goto bad_syntax;
00502 
00503    /* branch flags value (param 8) */
00504    node = node->next;
00505    if (str2int( &node->value, (unsigned int*)&ci.cflags) < 0)
00506       goto bad_syntax;
00507 
00508    /* methods value (param 9) */
00509    node = node->next;
00510    if (str2int( &node->value, (unsigned int*)&ci.methods) < 0)
00511       goto bad_syntax;
00512 
00513    lock_udomain( dom, aor);
00514 
00515    n = get_urecord( dom, aor, &r);
00516    if ( n==1) {
00517       if (insert_urecord( dom, aor, &r) < 0)
00518          goto lock_error;
00519       c = 0;
00520    } else {
00521       if (get_ucontact( r, contact, &mi_ul_cid, MI_UL_CSEQ+1, &c) < 0)
00522          goto lock_error;
00523    }
00524 
00525    get_act_time();
00526 
00527    ci.callid = &mi_ul_cid;
00528    ci.user_agent = &mi_ul_ua;
00529    ci.cseq = MI_UL_CSEQ;
00530    /* 0 expires means permanent contact */
00531    if (ci.expires!=0)
00532       ci.expires += act_time;
00533 
00534    if (c) {
00535       if (update_ucontact( r, c, &ci) < 0)
00536          goto release_error;
00537    } else {
00538       if ( insert_ucontact( r, contact, &ci, &c) < 0 )
00539          goto release_error;
00540    }
00541 
00542    release_urecord(r);
00543 
00544    unlock_udomain( dom, aor);
00545 
00546    return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00547 bad_syntax:
00548    return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00549 release_error:
00550    release_urecord(r);
00551 lock_error:
00552    unlock_udomain( dom, aor);
00553    return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
00554 }
00555 
00556 
00557 /*!
00558  * \brief Dumps the contacts of an AOR
00559  * \param cmd mi_root containing the parameter
00560  * \param param not used
00561  * \note expects 2 nodes: the table name and the AOR
00562  * \return mi_root with the result or 0 on failure
00563  */
00564 struct mi_root* mi_usrloc_show_contact(struct mi_root *cmd, void *param)
00565 {
00566    struct mi_root *rpl_tree;
00567    struct mi_node *rpl, *node;
00568    udomain_t *dom;
00569    urecord_t *rec;
00570    ucontact_t* con;
00571    str *aor;
00572    int ret;
00573 
00574    node = cmd->node.kids;
00575    if (node==NULL || node->next==NULL || node->next->next!=NULL)
00576       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00577 
00578    /* look for table */
00579    dom = mi_find_domain( &node->value );
00580    if (dom==NULL)
00581       return init_mi_tree( 404, "Table not found", 15);
00582 
00583    /* process the aor */
00584    aor = &node->next->value;
00585    if ( mi_fix_aor(aor)!=0 )
00586       return init_mi_tree( 400, "Domain missing in AOR", 21);
00587 
00588    lock_udomain( dom, aor);
00589 
00590    ret = get_urecord( dom, aor, &rec);
00591    if (ret == 1) {
00592       unlock_udomain( dom, aor);
00593       return init_mi_tree( 404, "AOR not found", 13);
00594    }
00595 
00596    get_act_time();
00597    rpl_tree = 0;
00598    rpl = 0;
00599 
00600    for( con=rec->contacts ; con ; con=con->next) {
00601       if (VALID_CONTACT( con, act_time)) {
00602          if (rpl_tree==0) {
00603             rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00604             if (rpl_tree==0)
00605                goto error;
00606             rpl = &rpl_tree->node;
00607          }
00608 
00609          node = addf_mi_node_child( rpl, 0, "Contact", 7,
00610             "<%.*s>;q=%s;expires=%d;flags=0x%X;cflags=0x%X;socket=<%.*s>;"
00611             "methods=0x%X"
00612             "%s%.*s%s" /*received*/
00613             "%s%.*s%s" /*user-agent*/
00614             "%s%.*s%s", /*path*/
00615             con->c.len, ZSW(con->c.s),
00616             q2str(con->q, 0), (int)(con->expires - act_time),
00617             con->flags, con->cflags,
00618             con->sock?con->sock->sock_str.len:3,
00619                con->sock?con->sock->sock_str.s:"NULL",
00620             con->methods,
00621             con->received.len?";received=<":"",con->received.len,
00622                ZSW(con->received.s), con->received.len?">":"",
00623             con->user_agent.len?";user_agent=<":"",con->user_agent.len,
00624                ZSW(con->user_agent.s), con->user_agent.len?">":"",
00625             con->path.len?";path=<":"", con->path.len,
00626                ZSW(con->path.s), con->path.len?">":""
00627             );
00628          if (node==0)
00629             goto error;
00630       }
00631    }
00632 
00633    unlock_udomain( dom, aor);
00634 
00635    if (rpl_tree==0)
00636       return init_mi_tree( 404 , "AOR has no contacts", 18);
00637 
00638    return rpl_tree;
00639 error:
00640    if (rpl_tree)
00641       free_mi_tree( rpl_tree );
00642    unlock_udomain( dom, aor);
00643    return 0;
00644 }

Generated on Thu May 24 22:00:35 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6