p_usrloc/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 
00035 #include <string.h>
00036 #include <stdio.h>
00037 #include "../../dprint.h"
00038 #include "../../ut.h"
00039 #include "../../qvalue.h"
00040 #include "../../ip_addr.h"
00041 #include "ul_mi.h"
00042 #include "dlist.h"
00043 #include "udomain.h"
00044 #include "utime.h"
00045 #include "p_usrloc_mod.h"
00046 
00047 
00049 #define MI_UL_CSEQ 1
00050 
00051 static str mi_ul_cid = str_init("dfjrewr12386fd6-343@openser.mi");
00053 static str mi_ul_ua  = str_init("Kamailio MI Server");
00054 
00055 static str mi_ul_path = str_init("dummypath");
00056 
00057 /************************ helper functions ****************************/
00058 
00064 static inline udomain_t* mi_find_domain(str* table)
00065 {
00066 
00067         LM_ERR("not available in sp-ul_db mode");
00068         return 0;
00069 }
00070 
00071 
00080 static inline int mi_fix_aor(str *aor)
00081 {
00082         char *p;
00083 
00084         p = memchr( aor->s, '@', aor->len);
00085         if (use_domain) {
00086                 if (p==NULL)
00087                         return -1;
00088         } else {
00089                 if (p)
00090                         aor->len = p - aor->s;
00091         }
00092         strlower(aor);
00093 
00094         return 0;
00095 }
00096 
00097 
00106 static inline int mi_add_aor_node(struct mi_node *parent, urecord_t* r, time_t t, int short_dump)
00107 {
00108         struct mi_node *anode, *cnode, *node;
00109         struct mi_attr *attr;
00110         ucontact_t* c;
00111         char *p;
00112         int len;
00113 
00114         anode = add_mi_node_child( parent, MI_DUP_VALUE, "AOR", 3,
00115                         r->aor.s, r->aor.len);
00116         if (anode==0)
00117                 return -1;
00118 
00119         if (short_dump)
00120                 return 0;
00121 
00122         for( c=r->contacts ; c ; c=c->next) {
00123                 /* contact */
00124                 cnode = add_mi_node_child( anode, MI_DUP_VALUE, "Contact", 7,
00125                         c->c.s, c->c.len);
00126                 if (cnode==0)
00127                         return -1;
00128 
00129                 /* expires */
00130                 if (c->expires == 0) {
00131                         node = add_mi_node_child( cnode, 0, "Expires", 7, "permanent", 9);
00132                 } else if (c->expires == UL_EXPIRED_TIME) {
00133                         node = add_mi_node_child( cnode, 0, "Expires", 7, "deleted", 7);
00134                 } else if (t > c->expires) {
00135                         node = add_mi_node_child( cnode, 0, "Expires", 7, "expired", 7);
00136                 } else {
00137                         p = int2str((unsigned long)(c->expires - t), &len);
00138                         node = add_mi_node_child( cnode, MI_DUP_VALUE, "Expires", 7,p,len);
00139                 }
00140                 if (node==0)
00141                         return -1;
00142 
00143                 /* q */
00144                 p = q2str(c->q, (unsigned int*)&len);
00145                 attr = add_mi_attr( cnode, MI_DUP_VALUE, "Q", 1, p, len);
00146                 if (attr==0)
00147                         return -1;
00148 
00149                 /* callid */
00150                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Callid", 6,
00151                         c->callid.s, c->callid.len);
00152                 if (node==0)
00153                         return -1;
00154 
00155                 /* cseq */
00156                 p = int2str((unsigned long)c->cseq, &len);
00157                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Cseq", 4, p, len);
00158                 if (node==0)
00159                         return -1;
00160 
00161                 /* User-Agent */
00162                 if (c->user_agent.len) {
00163                         node = add_mi_node_child( cnode, MI_DUP_VALUE, "User-agent", 10,
00164                                 c->user_agent.s, c->user_agent.len);
00165                         if (node==0)
00166                                 return -1;
00167                 }
00168 
00169                 /* received */
00170                 if (c->received.len) {
00171                         node = add_mi_node_child( cnode, MI_DUP_VALUE, "Received", 8,
00172                                 c->received.s, c->received.len);
00173                         if (node==0)
00174                                 return -1;
00175                 }
00176 
00177                 /* path */
00178                 if (c->path.len) {
00179                         node = add_mi_node_child( cnode, MI_DUP_VALUE, "Path", 4,
00180                                 c->path.s, c->path.len);
00181                         if (node==0)
00182                                 return -1;
00183                 }
00184 
00185                 /* state */
00186                 if (c->state == CS_NEW) {
00187                         node = add_mi_node_child( cnode, 0, "State", 5, "CS_NEW", 6);
00188                 } else if (c->state == CS_SYNC) {
00189                         node = add_mi_node_child( cnode, 0, "State", 5, "CS_SYNC", 7);
00190                 } else if (c->state== CS_DIRTY) {
00191                         node = add_mi_node_child( cnode, 0, "State", 5, "CS_DIRTY", 8);
00192                 } else {
00193                         node = add_mi_node_child( cnode, 0, "State", 5, "CS_UNKNOWN", 10);
00194                 }
00195                 if (node==0)
00196                         return -1;
00197 
00198                 /* flags */
00199                 p = int2str((unsigned long)c->flags, &len);
00200                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Flags", 5, p, len);
00201                 if (node==0)
00202                         return -1;
00203 
00204                 /* cflags */
00205                 p = int2str((unsigned long)c->cflags, &len);
00206                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Cflags", 5, p, len);
00207                 if (node==0)
00208                         return -1;
00209 
00210                 /* socket */
00211                 if (c->sock) {
00212                         node = add_mi_node_child( cnode, 0, "Socket", 6,
00213                                 c->sock->sock_str.s, c->sock->sock_str.len);
00214                         if (node==0)
00215                                 return -1;
00216                 }
00217 
00218                 /* methods */
00219                 p = int2str((unsigned long)c->methods, &len);
00220                 node = add_mi_node_child( cnode, MI_DUP_VALUE, "Methods", 7, p, len);
00221                 if (node==0)
00222                         return -1;
00223 
00224         } /* for */
00225 
00226         return 0;
00227 }
00228 
00229 
00230 /*************************** MI functions *****************************/
00231 
00239 struct mi_root* mi_usrloc_rm_aor(struct mi_root *cmd, void *param)
00240 {
00241         struct mi_node *node;
00242         udomain_t *dom;
00243         str *aor;
00244 
00245         node = cmd->node.kids;
00246         if (node==NULL || node->next==NULL || node->next->next!=NULL)
00247                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00248 
00249         /* look for table */
00250         dom = mi_find_domain( &node->value );
00251         if (dom==NULL)
00252                 return init_mi_tree( 404, "Table not found", 15);
00253 
00254         /* process the aor */
00255         aor = &node->next->value;
00256         if ( mi_fix_aor(aor)!=0 )
00257                 return init_mi_tree( 400, "Domain missing in AOR", 21);
00258 
00259         lock_udomain( dom, aor);
00260         if (delete_urecord( dom, aor, 0) < 0) {
00261                 unlock_udomain( dom, aor);
00262                 return init_mi_tree( 500, "Failed to delete AOR", 20);
00263         }
00264 
00265         unlock_udomain( dom, aor);
00266         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00267 }
00268 
00269 
00277 struct mi_root* mi_usrloc_rm_contact(struct mi_root *cmd, void *param)
00278 {
00279         struct mi_node *node;
00280         udomain_t *dom;
00281         urecord_t *rec;
00282         ucontact_t* con;
00283         str *aor, *contact;
00284         int ret;
00285 
00286         node = cmd->node.kids;
00287         if (node==NULL || node->next==NULL || node->next->next==NULL ||
00288         node->next->next->next!=NULL)
00289                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00290 
00291         /* look for table */
00292         dom = mi_find_domain( &node->value );
00293         if (dom==NULL)
00294                 return init_mi_tree( 404, "Table not found", 15);
00295 
00296         /* process the aor */
00297         aor = &node->next->value;
00298         if ( mi_fix_aor(aor)!=0 )
00299                 return init_mi_tree( 400, "Domain missing in AOR", 21);
00300 
00301         lock_udomain( dom, aor);
00302 
00303         ret = get_urecord( dom, aor, &rec);
00304         if (ret == 1) {
00305                 unlock_udomain( dom, aor);
00306                 return init_mi_tree( 404, "AOR not found", 13);
00307         }
00308 
00309         contact = &node->next->next->value;
00310         ret = get_ucontact( rec, contact, &mi_ul_cid, &mi_ul_path, MI_UL_CSEQ+1, &con);
00311         if (ret < 0) {
00312                 unlock_udomain( dom, aor);
00313                 return 0;
00314         }
00315         if (ret > 0) {
00316                 unlock_udomain( dom, aor);
00317                 return init_mi_tree( 404, "Contact not found", 17);
00318         }
00319 
00320         if (delete_ucontact(rec, con) < 0) {
00321                 unlock_udomain( dom, aor);
00322                 return 0;
00323         }
00324 
00325         release_urecord(rec);
00326         unlock_udomain( dom, aor);
00327         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00328 }
00329 
00330 
00337 struct mi_root* mi_usrloc_dump(struct mi_root *cmd, void *param)
00338 {
00339         LM_ERR("not available in sp-ul_db mode");
00340         return 0;
00341 }
00342 
00343 
00350 struct mi_root* mi_usrloc_flush(struct mi_root *cmd, void *param)
00351 {
00352         struct mi_root *rpl_tree;
00353 
00354         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00355         if (rpl_tree==NULL)
00356                 return 0;
00357 
00358         synchronize_all_udomains();
00359         return rpl_tree;
00360 }
00361 
00362 
00371 struct mi_root* mi_usrloc_add(struct mi_root *cmd, void *param)
00372 {
00373         ucontact_info_t ci;
00374         urecord_t* r;
00375         ucontact_t* c;
00376         struct mi_node *node;
00377         udomain_t *dom;
00378         str *aor, *contact;
00379         unsigned int ui_val;
00380         int n;
00381 
00382         for( n=0,node = cmd->node.kids; n<9 && node ; n++,node=node->next );
00383         if (n!=9 || node!=0)
00384                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00385 
00386         node = cmd->node.kids;
00387 
00388         /* look for table (param 1) */
00389         dom = mi_find_domain( &node->value );
00390         if (dom==NULL)
00391                 return init_mi_tree( 404, "Table not found", 15);
00392 
00393         /* process the aor (param 2) */
00394         node = node->next;
00395         aor = &node->value;
00396         if ( mi_fix_aor(aor)!=0 )
00397                 return init_mi_tree( 400, "Domain missing in AOR", 21);
00398 
00399         /* contact (param 3) */
00400         node = node->next;
00401         contact = &node->value;
00402 
00403         memset( &ci, 0, sizeof(ucontact_info_t));
00404 
00405         /* expire (param 4) */
00406         node = node->next;
00407         if (str2int( &node->value, &ui_val) < 0)
00408                 goto bad_syntax;
00409         ci.expires = ui_val;
00410 
00411         /* q value (param 5) */
00412         node = node->next;
00413         if (str2q( &ci.q, node->value.s, node->value.len) < 0)
00414                 goto bad_syntax;
00415 
00416         /* unused value (param 6) FIXME */
00417         node = node->next;
00418 
00419         /* flags value (param 7) */
00420         node = node->next;
00421         if (str2int( &node->value, (unsigned int*)&ci.flags) < 0)
00422                 goto bad_syntax;
00423 
00424         /* branch flags value (param 8) */
00425         node = node->next;
00426         if (str2int( &node->value, (unsigned int*)&ci.cflags) < 0)
00427                 goto bad_syntax;
00428 
00429         /* methods value (param 9) */
00430         node = node->next;
00431         if (str2int( &node->value, (unsigned int*)&ci.methods) < 0)
00432                 goto bad_syntax;
00433 
00434         lock_udomain( dom, aor);
00435 
00436         n = get_urecord( dom, aor, &r);
00437         if ( n==1) {
00438                 if (insert_urecord( dom, aor, &r) < 0)
00439                         goto lock_error;
00440                 c = 0;
00441         } else {
00442                 if (get_ucontact( r, contact, &mi_ul_cid, &mi_ul_path, MI_UL_CSEQ+1, &c) < 0)
00443                         goto lock_error;
00444         }
00445 
00446         get_act_time();
00447 
00448         ci.callid = &mi_ul_cid;
00449         ci.user_agent = &mi_ul_ua;
00450         ci.cseq = MI_UL_CSEQ;
00451         /* 0 expires means permanent contact */
00452         if (ci.expires!=0)
00453                 ci.expires += act_time;
00454 
00455         if (c) {
00456                 if (update_ucontact( r, c, &ci) < 0)
00457                         goto release_error;
00458         } else {
00459                 if ( insert_ucontact( r, contact, &ci, &c) < 0 )
00460                         goto release_error;
00461         }
00462 
00463         release_urecord(r);
00464 
00465         unlock_udomain( dom, aor);
00466 
00467         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00468 bad_syntax:
00469         return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00470 release_error:
00471         release_urecord(r);
00472 lock_error:
00473         unlock_udomain( dom, aor);
00474         return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
00475 }
00476 
00477 
00485 struct mi_root* mi_usrloc_show_contact(struct mi_root *cmd, void *param)
00486 {
00487         struct mi_root *rpl_tree;
00488         struct mi_node *rpl, *node;
00489         udomain_t *dom;
00490         urecord_t *rec;
00491         ucontact_t* con;
00492         str *aor;
00493         int ret;
00494 
00495         node = cmd->node.kids;
00496         if (node==NULL || node->next==NULL || node->next->next!=NULL)
00497                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00498 
00499         /* look for table */
00500         dom = mi_find_domain( &node->value );
00501         if (dom==NULL)
00502                 return init_mi_tree( 404, "Table not found", 15);
00503 
00504         /* process the aor */
00505         aor = &node->next->value;
00506         if ( mi_fix_aor(aor)!=0 )
00507                 return init_mi_tree( 400, "Domain missing in AOR", 21);
00508 
00509         lock_udomain( dom, aor);
00510 
00511         ret = get_urecord( dom, aor, &rec);
00512         if (ret == 1) {
00513                 unlock_udomain( dom, aor);
00514                 return init_mi_tree( 404, "AOR not found", 13);
00515         }
00516 
00517         get_act_time();
00518         rpl_tree = 0;
00519         rpl = 0;
00520 
00521         for( con=rec->contacts ; con ; con=con->next) {
00522                 if (VALID_CONTACT( con, act_time)) {
00523                         if (rpl_tree==0) {
00524                                 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00525                                 if (rpl_tree==0)
00526                                         goto error;
00527                                 rpl = &rpl_tree->node;
00528                         }
00529 
00530                         node = addf_mi_node_child( rpl, 0, "Contact", 7,
00531                                 "<%.*s>;q=%s;expires=%d;flags=0x%X;cflags=0x%X;socket=<%.*s>;"
00532                                 "methods=0x%X"
00533                                 "%s%.*s%s" /*received*/
00534                                 "%s%.*s%s" /*user-agent*/
00535                                 "%s%.*s%s", /*path*/
00536                                 con->c.len, ZSW(con->c.s),
00537                                 q2str(con->q, 0), (int)(con->expires - act_time),
00538                                 con->flags, con->cflags,
00539                                 con->sock?con->sock->sock_str.len:3,
00540                                         con->sock?con->sock->sock_str.s:"NULL",
00541                                 con->methods,
00542                                 con->received.len?";received=<":"",con->received.len,
00543                                         ZSW(con->received.s), con->received.len?">":"",
00544                                 con->user_agent.len?";user_agent=<":"",con->user_agent.len,
00545                                         ZSW(con->user_agent.s), con->user_agent.len?">":"",
00546                                 con->path.len?";path=<":"", con->path.len,
00547                                         ZSW(con->path.s), con->path.len?">":""
00548                                 );
00549                         if (node==0)
00550                                 goto error;
00551                 }
00552         }
00553 
00554         unlock_udomain( dom, aor);
00555 
00556         if (rpl_tree==0)
00557                 return init_mi_tree( 404 , "AOR has no contacts", 18);
00558 
00559         return rpl_tree;
00560 error:
00561         if (rpl_tree)
00562                 free_mi_tree( rpl_tree );
00563         unlock_udomain( dom, aor);
00564         return 0;
00565 }