usrloc/ul_mi.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
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 
00035 #include <string.h>
00036 #include <stdio.h>
00037 #include "../../lib/kmi/mi.h"
00038 #include "../../lib/srutils/sruid.h"
00039 #include "../../dprint.h"
00040 #include "../../ut.h"
00041 #include "../../qvalue.h"
00042 #include "../../ip_addr.h"
00043 #include "ul_mi.h"
00044 #include "dlist.h"
00045 #include "udomain.h"
00046 #include "utime.h"
00047 #include "ul_mod.h"
00048 #include "usrloc.h"
00049 
00051 #define MI_UL_CSEQ 1
00052 
00053 static str mi_ul_cid = str_init("dfjrewr12386fd6-343@kamailio.mi");
00055 static str mi_ul_ua  = str_init("SIP Router MI Server");
00057 static str mi_ul_path = str_init("dummypath");
00058 
00059 extern sruid_t _ul_sruid;
00060 
00061 /************************ helper functions ****************************/
00062 
00068 static inline udomain_t* mi_find_domain(str* table)
00069 {
00070         dlist_t* dom;
00071 
00072         for( dom=root ; dom ; dom=dom->next ) {
00073                 if ((dom->name.len == table->len) &&
00074                 !memcmp(dom->name.s, table->s, table->len))
00075                         return dom->d;
00076         }
00077         return 0;
00078 }
00079 
00080 
00089 static inline int mi_fix_aor(str *aor)
00090 {
00091         char *p;
00092 
00093         p = memchr( aor->s, '@', aor->len);
00094         if (use_domain) {
00095                 if (p==NULL)
00096                         return -1;
00097         } else {
00098                 if (p)
00099                         aor->len = p - aor->s;
00100         }
00101         strlower(aor);
00102 
00103         return 0;
00104 }
00105 
00106 
00115 static inline int mi_add_aor_node(struct mi_node *parent, urecord_t* r, time_t t, int short_dump)
00116 {
00117         struct mi_node *anode, *cnode, *node;
00118         struct mi_attr *attr;
00119         ucontact_t* c;
00120         char *p;
00121         int len;
00122 
00123         anode = add_mi_node_child( parent, MI_DUP_VALUE, "AOR", 3,
00124                         r->aor.s, r->aor.len);
00125         if (anode==0)
00126                 return -1;
00127 
00128         if (short_dump)
00129                 return 0;
00130 
00131 #if 0
00132         /* aor hash */
00133         p = int2str((unsigned long)r->aorhash, &len);
00134         node = add_mi_node_child( anode, MI_DUP_VALUE, "HashID", 6, p, len);
00135         if (node==0)
00136                 return -1;
00137 #endif
00138 
00139         for( c=r->contacts ; c ; c=c->next) {
00140                 /* contact */
00141                 cnode = add_mi_node_child( anode, MI_DUP_VALUE, "Contact", 7,
00142                         c->c.s, c->c.len);
00143                 if (cnode==0)
00144                         return -1;
00145 
00146                 /* expires */
00147                 if (c->expires == 0) {
00148                         node = add_mi_node_child( cnode, 0, "Expires", 7, "permanent", 9);
00149                 } else if (c->expires == UL_EXPIRED_TIME) {
00150                         node = add_mi_node_child( cnode, 0, "Expires", 7, "deleted", 7);
00151                 } else if (t > c->expires) {
00152                         node = add_mi_node_child( cnode, 0, "Expires", 7, "expired", 7);
00153                 } else {
00154                         p = int2str((unsigned long)(c->expires - t), &len);
00155                         node = add_mi_node_child( cnode, MI_DUP_VALUE, "Expires", 7,p,len);
00156                 }
00157                 if (node==0)
00158                         return -1;
00159 
00160                 /* q */
00161                 p = q2str(c->q, (unsigned int*)&len);
00162                 attr = add_mi_attr( cnode, MI_DUP_VALUE, "Q", 1, p, len);
00163                 if (attr==0)
00164                         return -1;
00165 
00166                 /* callid */
00167                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Callid", 6,
00168                         c->callid.s, c->callid.len);
00169                 if (node==0)
00170                         return -1;
00171 
00172                 /* cseq */
00173                 p = int2str((unsigned long)c->cseq, &len);
00174                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Cseq", 4, p, len);
00175                 if (node==0)
00176                         return -1;
00177 
00178                 /* User-Agent */
00179                 if (c->user_agent.len) {
00180                         node = add_mi_node_child( cnode, MI_DUP_VALUE, "User-agent", 10,
00181                                 c->user_agent.s, c->user_agent.len);
00182                         if (node==0)
00183                                 return -1;
00184                 }
00185 
00186                 /* received */
00187                 if (c->received.len) {
00188                         node = add_mi_node_child( cnode, MI_DUP_VALUE, "Received", 8,
00189                                 c->received.s, c->received.len);
00190                         if (node==0)
00191                                 return -1;
00192                 }
00193 
00194                 /* path */
00195                 if (c->path.len) {
00196                         node = add_mi_node_child( cnode, MI_DUP_VALUE, "Path", 4,
00197                                 c->path.s, c->path.len);
00198                         if (node==0)
00199                                 return -1;
00200                 }
00201 
00202                 /* state */
00203                 if (c->state == CS_NEW) {
00204                         node = add_mi_node_child( cnode, 0, "State", 5, "CS_NEW", 6);
00205                 } else if (c->state == CS_SYNC) {
00206                         node = add_mi_node_child( cnode, 0, "State", 5, "CS_SYNC", 7);
00207                 } else if (c->state== CS_DIRTY) {
00208                         node = add_mi_node_child( cnode, 0, "State", 5, "CS_DIRTY", 8);
00209                 } else {
00210                         node = add_mi_node_child( cnode, 0, "State", 5, "CS_UNKNOWN", 10);
00211                 }
00212                 if (node==0)
00213                         return -1;
00214 
00215                 /* flags */
00216                 p = int2str((unsigned long)c->flags, &len);
00217                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Flags", 5, p, len);
00218                 if (node==0)
00219                         return -1;
00220 
00221                 /* cflags */
00222                 p = int2str((unsigned long)c->cflags, &len);
00223                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Cflags", 5, p, len);
00224                 if (node==0)
00225                         return -1;
00226 
00227                 /* socket */
00228                 if (c->sock) {
00229                         node = add_mi_node_child( cnode, 0, "Socket", 6,
00230                                 c->sock->sock_str.s, c->sock->sock_str.len);
00231                         if (node==0)
00232                                 return -1;
00233                 }
00234 
00235                 /* methods */
00236                 p = int2str((unsigned long)c->methods, &len);
00237                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Methods", 7, p, len);
00238                 if (node==0)
00239                         return -1;
00240 
00241                 /* ruid */
00242                 if (c->ruid.len) {
00243                         node = add_mi_node_child( cnode, MI_DUP_VALUE, "Ruid", 4,
00244                                 c->ruid.s, c->ruid.len);
00245                         if (node==0)
00246                                 return -1;
00247                 }
00248 
00249                 /* instance */
00250                 if (c->instance.len) {
00251                         node = add_mi_node_child( cnode, MI_DUP_VALUE, "Instance", 8,
00252                                 c->instance.s, c->instance.len);
00253                         if (node==0)
00254                                 return -1;
00255                 }
00256 
00257                 /* reg-id */
00258                 p = int2str((unsigned long)c->reg_id, &len);
00259                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Reg-Id", 6, p, len);
00260                 if (node==0)
00261                         return -1;
00262         } /* for */
00263 
00264         return 0;
00265 }
00266 
00267 
00268 /*************************** MI functions *****************************/
00269 
00277 struct mi_root* mi_usrloc_rm_aor(struct mi_root *cmd, void *param)
00278 {
00279         struct mi_node *node;
00280         udomain_t *dom;
00281         str *aor;
00282 
00283         node = cmd->node.kids;
00284         if (node==NULL || node->next==NULL || node->next->next!=NULL)
00285                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00286 
00287         /* look for table */
00288         dom = mi_find_domain( &node->value );
00289         if (dom==NULL)
00290                 return init_mi_tree( 404, "Table not found", 15);
00291 
00292         /* process the aor */
00293         aor = &node->next->value;
00294         if ( mi_fix_aor(aor)!=0 )
00295                 return init_mi_tree( 400, "Domain missing in AOR", 21);
00296 
00297         lock_udomain( dom, aor);
00298         if (delete_urecord( dom, aor, 0) < 0) {
00299                 unlock_udomain( dom, aor);
00300                 return init_mi_tree( 500, "Failed to delete AOR", 20);
00301         }
00302 
00303         unlock_udomain( dom, aor);
00304         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00305 }
00306 
00307 
00315 struct mi_root* mi_usrloc_rm_contact(struct mi_root *cmd, void *param)
00316 {
00317         struct mi_node *node;
00318         udomain_t *dom;
00319         urecord_t *rec;
00320         ucontact_t* con;
00321         str *aor, *contact;
00322         int ret;
00323 
00324         node = cmd->node.kids;
00325         if (node==NULL || node->next==NULL || node->next->next==NULL ||
00326         node->next->next->next!=NULL)
00327                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00328 
00329         /* look for table */
00330         dom = mi_find_domain( &node->value );
00331         if (dom==NULL)
00332                 return init_mi_tree( 404, "Table not found", 15);
00333 
00334         /* process the aor */
00335         aor = &node->next->value;
00336         if ( mi_fix_aor(aor)!=0 )
00337                 return init_mi_tree( 400, "Domain missing in AOR", 21);
00338 
00339         lock_udomain( dom, aor);
00340 
00341         ret = get_urecord( dom, aor, &rec);
00342         if (ret == 1) {
00343                 unlock_udomain( dom, aor);
00344                 return init_mi_tree( 404, "AOR not found", 13);
00345         }
00346 
00347         contact = &node->next->next->value;
00348         ret = get_ucontact( rec, contact, &mi_ul_cid, &mi_ul_path, MI_UL_CSEQ+1, &con);
00349         if (ret < 0) {
00350                 unlock_udomain( dom, aor);
00351                 return 0;
00352         }
00353         if (ret > 0) {
00354                 unlock_udomain( dom, aor);
00355                 return init_mi_tree( 404, "Contact not found", 17);
00356         }
00357 
00358         if (delete_ucontact(rec, con) < 0) {
00359                 unlock_udomain( dom, aor);
00360                 return 0;
00361         }
00362 
00363         release_urecord(rec);
00364         unlock_udomain( dom, aor);
00365         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00366 }
00367 
00368 
00375 struct mi_root* mi_usrloc_dump(struct mi_root *cmd, void *param)
00376 {
00377         struct mi_root *rpl_tree;
00378         struct mi_node *rpl, *node;
00379         struct mi_attr *attr;
00380         struct urecord* r;
00381         dlist_t* dl;
00382         udomain_t* dom;
00383         time_t t;
00384         char *p;
00385         int max, len, n, i, short_dump;
00386 
00387         node = cmd->node.kids;
00388         if (node && node->next)
00389                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00390 
00391         if (node && node->value.len==5 && !strncasecmp(node->value.s, "brief", 5)){
00392                 /* short version */
00393                 short_dump = 1;
00394         } else {
00395                 short_dump = 0;
00396         }
00397 
00398         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00399         if (rpl_tree==NULL)
00400                 return 0;
00401         rpl = &rpl_tree->node;
00402         t = time(0);
00403 
00404         for( dl=root ; dl ; dl=dl->next ) {
00405                 /* add a domain node */
00406                 node = add_mi_node_child( rpl, 0, "Domain", 6,
00407                                         dl->name.s, dl->name.len);
00408                 if (node==0)
00409                         goto error;
00410 
00411                 dom = dl->d;
00412                 /* add some attributes to the domain node */
00413                 p= int2str((unsigned long)dom->size, &len);
00414                 attr = add_mi_attr( node, MI_DUP_VALUE, "table", 5, p, len);
00415                 if (attr==0)
00416                         goto error;
00417 
00418                 /* add the entries per hash */
00419                 for(i=0,n=0,max=0; i<dom->size; i++) {
00420                         lock_ulslot( dom, i);
00421 
00422                         n += dom->table[i].n;
00423                         if(max<dom->table[i].n)
00424                                 max= dom->table[i].n;
00425                         for( r = dom->table[i].first ; r ; r=r->next ) {
00426                                 /* add entry */
00427                                 if (mi_add_aor_node( node, r, t, short_dump)!=0) {
00428                                         unlock_ulslot( dom, i);
00429                                         goto error;
00430                                 }
00431                         }
00432 
00433                         unlock_ulslot( dom, i);
00434                 }
00435 
00436                 /* add more attributes to the domain node */
00437                 p= int2str((unsigned long)n, &len);
00438                 attr = add_mi_attr( node, MI_DUP_VALUE, "records", 7, p, len);
00439                 if (attr==0)
00440                         goto error;
00441 
00442                 p= int2str((unsigned long)max, &len);
00443                 attr = add_mi_attr( node, MI_DUP_VALUE, "max_slot", 8, p, len);
00444                 if (attr==0)
00445                         goto error;
00446 
00447         }
00448 
00449         return rpl_tree;
00450 error:
00451         free_mi_tree(rpl_tree);
00452         return 0;
00453 }
00454 
00455 
00462 struct mi_root* mi_usrloc_flush(struct mi_root *cmd, void *param)
00463 {
00464         struct mi_root *rpl_tree;
00465 
00466         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00467         if (rpl_tree==NULL)
00468                 return 0;
00469 
00470         synchronize_all_udomains(0, 1);
00471         return rpl_tree;
00472 }
00473 
00474 
00483 struct mi_root* mi_usrloc_add(struct mi_root *cmd, void *param)
00484 {
00485         ucontact_info_t ci;
00486         urecord_t* r;
00487         ucontact_t* c;
00488         struct mi_node *node;
00489         udomain_t *dom;
00490         str *aor, *contact;
00491         unsigned int ui_val;
00492         int n;
00493 
00494         for( n=0,node = cmd->node.kids; n<9 && node ; n++,node=node->next );
00495         if (n!=9 || node!=0)
00496                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00497 
00498         node = cmd->node.kids;
00499 
00500         /* look for table (param 1) */
00501         dom = mi_find_domain( &node->value );
00502         if (dom==NULL)
00503                 return init_mi_tree( 404, "Table not found", 15);
00504 
00505         /* process the aor (param 2) */
00506         node = node->next;
00507         aor = &node->value;
00508         if ( mi_fix_aor(aor)!=0 )
00509                 return init_mi_tree( 400, "Domain missing in AOR", 21);
00510 
00511         /* contact (param 3) */
00512         node = node->next;
00513         contact = &node->value;
00514 
00515         memset( &ci, 0, sizeof(ucontact_info_t));
00516 
00517         /* expire (param 4) */
00518         node = node->next;
00519         if (str2int( &node->value, &ui_val) < 0)
00520                 goto bad_syntax;
00521         ci.expires = ui_val;
00522 
00523         /* q value (param 5) */
00524         node = node->next;
00525         if (str2q( &ci.q, node->value.s, node->value.len) < 0)
00526                 goto bad_syntax;
00527 
00528         /* unused value (param 6) FIXME */
00529         node = node->next;
00530 
00531         /* flags value (param 7) */
00532         node = node->next;
00533         if (str2int( &node->value, (unsigned int*)&ci.flags) < 0)
00534                 goto bad_syntax;
00535 
00536         /* branch flags value (param 8) */
00537         node = node->next;
00538         if (str2int( &node->value, (unsigned int*)&ci.cflags) < 0)
00539                 goto bad_syntax;
00540 
00541         /* methods value (param 9) */
00542         node = node->next;
00543         if (str2int( &node->value, (unsigned int*)&ci.methods) < 0)
00544                 goto bad_syntax;
00545 
00546         if(sruid_next(&_ul_sruid)<0)
00547                 goto error;
00548         ci.ruid = _ul_sruid.uid;
00549 
00550         lock_udomain( dom, aor);
00551 
00552         n = get_urecord( dom, aor, &r);
00553         if ( n==1) {
00554                 if (insert_urecord( dom, aor, &r) < 0)
00555                         goto lock_error;
00556                 c = 0;
00557         } else {
00558                 if (get_ucontact( r, contact, &mi_ul_cid, &mi_ul_path, MI_UL_CSEQ+1, &c) < 0)
00559                         goto lock_error;
00560         }
00561 
00562         get_act_time();
00563 
00564         ci.callid = &mi_ul_cid;
00565         ci.user_agent = &mi_ul_ua;
00566         ci.cseq = MI_UL_CSEQ;
00567         /* 0 expires means permanent contact */
00568         if (ci.expires!=0)
00569                 ci.expires += act_time;
00570 
00571         if (c) {
00572                 if (update_ucontact( r, c, &ci) < 0)
00573                         goto release_error;
00574         } else {
00575                 if ( insert_ucontact( r, contact, &ci, &c) < 0 )
00576                         goto release_error;
00577         }
00578 
00579         release_urecord(r);
00580 
00581         unlock_udomain( dom, aor);
00582 
00583         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00584 bad_syntax:
00585         return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00586 release_error:
00587         release_urecord(r);
00588 lock_error:
00589         unlock_udomain( dom, aor);
00590 error:
00591         return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
00592 }
00593 
00594 
00602 struct mi_root* mi_usrloc_show_contact(struct mi_root *cmd, void *param)
00603 {
00604         struct mi_root *rpl_tree;
00605         struct mi_node *rpl, *node;
00606         udomain_t *dom;
00607         urecord_t *rec;
00608         ucontact_t* con;
00609         str *aor;
00610         int ret;
00611 
00612         node = cmd->node.kids;
00613         if (node==NULL || node->next==NULL || node->next->next!=NULL)
00614                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00615 
00616         /* look for table */
00617         dom = mi_find_domain( &node->value );
00618         if (dom==NULL)
00619                 return init_mi_tree( 404, "Table not found", 15);
00620 
00621         /* process the aor */
00622         aor = &node->next->value;
00623         if ( mi_fix_aor(aor)!=0 )
00624                 return init_mi_tree( 400, "Domain missing in AOR", 21);
00625 
00626         lock_udomain( dom, aor);
00627 
00628         ret = get_urecord( dom, aor, &rec);
00629         if (ret == 1) {
00630                 unlock_udomain( dom, aor);
00631                 return init_mi_tree( 404, "AOR not found", 13);
00632         }
00633 
00634         get_act_time();
00635         rpl_tree = 0;
00636         rpl = 0;
00637 
00638         for( con=rec->contacts ; con ; con=con->next) {
00639                 if (VALID_CONTACT( con, act_time)) {
00640                         if (rpl_tree==0) {
00641                                 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00642                                 if (rpl_tree==0)
00643                                         goto error;
00644                                 rpl = &rpl_tree->node;
00645                         }
00646 
00647                         node = addf_mi_node_child( rpl, 0, "Contact", 7,
00648                                 "<%.*s>;q=%s;expires=%d;flags=0x%X;cflags=0x%X;socket=<%.*s>;"
00649                                 "methods=0x%X"
00650                                 "%s%.*s%s" /*received*/
00651                                 "%s%.*s%s" /*user-agent*/
00652                                 "%s%.*s%s", /*path*/
00653                                 con->c.len, ZSW(con->c.s),
00654                                 q2str(con->q, 0), (int)(con->expires - act_time),
00655                                 con->flags, con->cflags,
00656                                 con->sock?con->sock->sock_str.len:3,
00657                                         con->sock?con->sock->sock_str.s:"NULL",
00658                                 con->methods,
00659                                 con->received.len?";received=<":"",con->received.len,
00660                                         ZSW(con->received.s), con->received.len?">":"",
00661                                 con->user_agent.len?";user_agent=<":"",con->user_agent.len,
00662                                         ZSW(con->user_agent.s), con->user_agent.len?">":"",
00663                                 con->path.len?";path=<":"", con->path.len,
00664                                         ZSW(con->path.s), con->path.len?">":""
00665                                 );
00666                         if (node==0)
00667                                 goto error;
00668                 }
00669         }
00670 
00671         unlock_udomain( dom, aor);
00672 
00673         if (rpl_tree==0)
00674                 return init_mi_tree( 404 , "AOR has no contacts", 18);
00675 
00676         return rpl_tree;
00677 error:
00678         if (rpl_tree)
00679                 free_mi_tree( rpl_tree );
00680         unlock_udomain( dom, aor);
00681         return 0;
00682 }