dlg_hash.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dlg_hash.c 5529 2009-01-28 21:51:20Z miconda $
00003  *
00004  * Copyright (C) 2006 Voice System 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  * 2006-04-14  initial version (bogdan)
00025  * 2007-03-06  syncronized state machine added for dialog state. New tranzition
00026  *             design based on events; removed num_1xx and num_2xx (bogdan)
00027  * 2007-04-30  added dialog matching without DID (dialog ID), but based only
00028  *             on RFC3261 elements - based on an original patch submitted 
00029  *             by Michel Bensoussan <michel@extricom.com> (bogdan)
00030  * 2007-07-06  additional information stored in order to save it in the db:
00031  *             cseq, route_set, contact and sock_info for both caller and 
00032  *             callee (ancuta)
00033  * 2007-07-10  Optimized dlg_match_mode 2 (DID_NONE), it now employs a proper
00034  *             hash table lookup and isn't dependant on the is_direction 
00035  *             function (which requires an RR param like dlg_match_mode 0 
00036  *             anyways.. ;) ; based on a patch from 
00037  *             Tavis Paquette <tavis@galaxytelecom.net> 
00038  *             and Peter Baer <pbaer@galaxytelecom.net>  (bogdan)
00039  * 2008-04-17  added new type of callback to be triggered right before the
00040  *              dialog is destroyed (deleted from memory) (bogdan)
00041  * 2008-04-17  added new dialog flag to avoid state tranzitions from DELETED to
00042  *             CONFIRMED_NA due delayed "200 OK" (bogdan)
00043  */
00044 
00045 #include <stdlib.h>
00046 #include <string.h>
00047 
00048 #include "../../dprint.h"
00049 #include "../../ut.h"
00050 #include "../../hash_func.h"
00051 #include "../../mi/mi.h"
00052 #include "dlg_timer.h"
00053 #include "dlg_hash.h"
00054 #include "dlg_profile.h"
00055 
00056 #define MAX_LDG_LOCKS  2048
00057 #define MIN_LDG_LOCKS  2
00058 
00059 
00060 struct dlg_table *d_table = 0;
00061 
00062 int init_dlg_table(unsigned int size)
00063 {
00064    unsigned int n;
00065    unsigned int i;
00066 
00067    d_table = (struct dlg_table*)shm_malloc
00068       ( sizeof(struct dlg_table) + size*sizeof(struct dlg_entry));
00069    if (d_table==0) {
00070       LM_ERR("no more shm mem (1)\n");
00071       goto error0;
00072    }
00073 
00074    memset( d_table, 0, sizeof(struct dlg_table) );
00075    d_table->size = size;
00076    d_table->entries = (struct dlg_entry*)(d_table+1);
00077 
00078    n = (size<MAX_LDG_LOCKS)?size:MAX_LDG_LOCKS;
00079    for(  ; n>=MIN_LDG_LOCKS ; n-- ) {
00080       d_table->locks = lock_set_alloc(n);
00081       if (d_table->locks==0)
00082          continue;
00083       if (lock_set_init(d_table->locks)==0) {
00084          lock_set_dealloc(d_table->locks);
00085          d_table->locks = 0;
00086          continue;
00087       }
00088       d_table->locks_no = n;
00089       break;
00090    }
00091 
00092    if (d_table->locks==0) {
00093       LM_ERR("unable to allocted at least %d locks for the hash table\n",
00094          MIN_LDG_LOCKS);
00095       goto error1;
00096    }
00097 
00098    for( i=0 ; i<size; i++ ) {
00099       memset( &(d_table->entries[i]), 0, sizeof(struct dlg_entry) );
00100       d_table->entries[i].next_id = rand();
00101       d_table->entries[i].lock_idx = i % d_table->locks_no;
00102    }
00103 
00104    return 0;
00105 error1:
00106    shm_free( d_table );
00107 error0:
00108    return -1;
00109 }
00110 
00111 
00112 
00113 inline void destroy_dlg(struct dlg_cell *dlg)
00114 {
00115    int ret = 0;
00116 
00117    LM_DBG("destroing dialog %p\n",dlg);
00118 
00119    ret = remove_dialog_timer(&dlg->tl);
00120    if (ret < 0) {
00121       LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
00122          "with clid '%.*s' and tags '%.*s' '%.*s'\n",
00123          dlg, dlg->h_entry, dlg->h_id,
00124          dlg->callid.len, dlg->callid.s,
00125          dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00126          dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00127    } else if (ret > 0) {
00128       LM_DBG("removed timer for dlg %p [%u:%u] "
00129          "with clid '%.*s' and tags '%.*s' '%.*s'\n",
00130          dlg, dlg->h_entry, dlg->h_id,
00131          dlg->callid.len, dlg->callid.s,
00132          dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00133          dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00134    }
00135 
00136    run_dlg_callbacks( DLGCB_DESTROY , dlg, 0, DLG_DIR_NONE, 0);
00137 
00138    if (dlg->cbs.first)
00139       destroy_dlg_callbacks_list(dlg->cbs.first);
00140 
00141    if (dlg->profile_links)
00142       destroy_linkers(dlg->profile_links);
00143 
00144    if (dlg->tag[DLG_CALLER_LEG].s)
00145       shm_free(dlg->tag[DLG_CALLER_LEG].s);
00146 
00147    if (dlg->tag[DLG_CALLEE_LEG].s)
00148       shm_free(dlg->tag[DLG_CALLEE_LEG].s);
00149 
00150    if (dlg->cseq[DLG_CALLER_LEG].s)
00151       shm_free(dlg->cseq[DLG_CALLER_LEG].s);
00152 
00153    if (dlg->cseq[DLG_CALLEE_LEG].s)
00154       shm_free(dlg->cseq[DLG_CALLEE_LEG].s);
00155 
00156    shm_free(dlg);
00157 }
00158 
00159 
00160 
00161 void destroy_dlg_table(void)
00162 {
00163    struct dlg_cell *dlg, *l_dlg;
00164    unsigned int i;
00165 
00166    if (d_table==0)
00167       return;
00168 
00169    if (d_table->locks) {
00170       lock_set_destroy(d_table->locks);
00171       lock_set_dealloc(d_table->locks);
00172    }
00173 
00174    for( i=0 ; i<d_table->size; i++ ) {
00175       dlg = d_table->entries[i].first;
00176       while (dlg) {
00177          l_dlg = dlg;
00178          dlg = dlg->next;
00179          destroy_dlg(l_dlg);
00180       }
00181 
00182    }
00183 
00184    shm_free(d_table);
00185    d_table = 0;
00186 
00187    return;
00188 }
00189 
00190 
00191 
00192 struct dlg_cell* build_new_dlg( str *callid, str *from_uri, str *to_uri,
00193                                                 str *from_tag)
00194 {
00195    struct dlg_cell *dlg;
00196    int len;
00197    char *p;
00198 
00199    len = sizeof(struct dlg_cell) + callid->len + from_uri->len +
00200       to_uri->len;
00201    dlg = (struct dlg_cell*)shm_malloc( len );
00202    if (dlg==0) {
00203       LM_ERR("no more shm mem (%d)\n",len);
00204       return 0;
00205    }
00206 
00207    memset( dlg, 0, len);
00208    dlg->state = DLG_STATE_UNCONFIRMED;
00209 
00210    dlg->h_entry = core_hash( callid, from_tag->len?from_tag:0, d_table->size);
00211    LM_DBG("new dialog on hash %u\n",dlg->h_entry);
00212 
00213    p = (char*)(dlg+1);
00214 
00215    dlg->callid.s = p;
00216    dlg->callid.len = callid->len;
00217    memcpy( p, callid->s, callid->len);
00218    p += callid->len;
00219 
00220    dlg->from_uri.s = p;
00221    dlg->from_uri.len = from_uri->len;
00222    memcpy( p, from_uri->s, from_uri->len);
00223    p += from_uri->len;
00224 
00225    dlg->to_uri.s = p;
00226    dlg->to_uri.len = to_uri->len;
00227    memcpy( p, to_uri->s, to_uri->len);
00228    p += to_uri->len;
00229 
00230    if ( p!=(((char*)dlg)+len) ) {
00231       LM_CRIT("buffer overflow\n");
00232       shm_free(dlg);
00233       return 0;
00234    }
00235 
00236    return dlg;
00237 }
00238 
00239 
00240 
00241 int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
00242                str *cseq, unsigned int leg)
00243 {
00244    char *p;
00245 
00246    dlg->tag[leg].s = (char*)shm_malloc( tag->len + rr->len + contact->len );
00247    dlg->cseq[leg].s = (char*)shm_malloc( cseq->len );
00248    if ( dlg->tag[leg].s==NULL || dlg->cseq[leg].s==NULL) {
00249       LM_ERR("no more shm mem\n");
00250       if (dlg->tag[leg].s) shm_free(dlg->tag[leg].s);
00251       if (dlg->cseq[leg].s) shm_free(dlg->cseq[leg].s);
00252       return -1;
00253    }
00254    p = dlg->tag[leg].s;
00255 
00256    /* tag */
00257    dlg->tag[leg].len = tag->len;
00258    memcpy( p, tag->s, tag->len);
00259    p += tag->len;
00260    /* contact */
00261    dlg->contact[leg].s = p;
00262    dlg->contact[leg].len = contact->len;
00263    memcpy( p, contact->s, contact->len);
00264    p += contact->len;
00265    /* rr */
00266    if (rr->len) {
00267       dlg->route_set[leg].s = p;
00268       dlg->route_set[leg].len = rr->len;
00269       memcpy( p, rr->s, rr->len);
00270    }
00271 
00272    /* cseq */
00273    dlg->cseq[leg].len = cseq->len;
00274    memcpy( dlg->cseq[leg].s, cseq->s, cseq->len);
00275 
00276    return 0;
00277 }
00278 
00279 
00280 
00281 int dlg_update_cseq(struct dlg_cell * dlg, unsigned int leg, str *cseq)
00282 {
00283    if ( dlg->cseq[leg].s ) {
00284       if (dlg->cseq[leg].len < cseq->len) {
00285          shm_free(dlg->cseq[leg].s);
00286          dlg->cseq[leg].s = (char*)shm_malloc(cseq->len);
00287          if (dlg->cseq[leg].s==NULL)
00288             goto error;
00289       }
00290    } else {
00291       dlg->cseq[leg].s = (char*)shm_malloc(cseq->len);
00292       if (dlg->cseq[leg].s==NULL)
00293          goto error;
00294    }
00295 
00296    memcpy( dlg->cseq[leg].s, cseq->s, cseq->len );
00297    dlg->cseq[leg].len = cseq->len;
00298 
00299    LM_DBG("cseq is %.*s\n", dlg->cseq[leg].len, dlg->cseq[leg].s);
00300    return 0;
00301 error:
00302    LM_ERR("not more shm mem\n");
00303    return -1;
00304 }
00305 
00306 
00307 
00308 struct dlg_cell* lookup_dlg( unsigned int h_entry, unsigned int h_id)
00309 {
00310    struct dlg_cell *dlg;
00311    struct dlg_entry *d_entry;
00312 
00313    if (h_entry>=d_table->size)
00314       goto not_found;
00315 
00316    d_entry = &(d_table->entries[h_entry]);
00317 
00318    dlg_lock( d_table, d_entry);
00319 
00320    for( dlg=d_entry->first ; dlg ; dlg=dlg->next ) {
00321       if (dlg->h_id == h_id) {
00322          if (dlg->state==DLG_STATE_DELETED) {
00323             dlg_unlock( d_table, d_entry);
00324             goto not_found;
00325          }
00326          dlg->ref++;
00327          LM_DBG("ref dlg %p with 1 -> %d\n", dlg, dlg->ref);
00328          dlg_unlock( d_table, d_entry);
00329          LM_DBG("dialog id=%u found on entry %u\n", h_id, h_entry);
00330          return dlg;
00331       }
00332    }
00333 
00334    dlg_unlock( d_table, d_entry);
00335 not_found:
00336    LM_DBG("no dialog id=%u found on entry %u\n", h_id, h_entry);
00337    return 0;
00338 }
00339 
00340 
00341 
00342 static inline struct dlg_cell* internal_get_dlg(unsigned int h_entry,
00343                   str *callid, str *ftag, str *ttag, unsigned int *dir)
00344 {
00345    struct dlg_cell *dlg;
00346    struct dlg_entry *d_entry;
00347 
00348    d_entry = &(d_table->entries[h_entry]);
00349 
00350    dlg_lock( d_table, d_entry);
00351 
00352    for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
00353       /* Check callid / fromtag / totag */
00354       if (match_dialog( dlg, callid, ftag, ttag, dir)==1) {
00355          if (dlg->state==DLG_STATE_DELETED) {
00356             dlg_unlock( d_table, d_entry);
00357             goto not_found;
00358          }
00359          dlg->ref++;
00360          LM_DBG("ref dlg %p with 1 -> %d\n", dlg, dlg->ref);
00361          dlg_unlock( d_table, d_entry);
00362          LM_DBG("dialog callid='%.*s' found\n on entry %u, dir=%d\n",
00363             callid->len, callid->s,h_entry,*dir);
00364          return dlg;
00365       }
00366    }
00367 
00368    dlg_unlock( d_table, d_entry);
00369 
00370 not_found:
00371    LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
00372    return 0;
00373 }
00374 
00375 
00376 
00377 /* Get dialog that correspond to CallId, From Tag and To Tag         */
00378 /* See RFC 3261, paragraph 4. Overview of Operation:                 */
00379 /* "The combination of the To tag, From tag, and Call-ID completely  */
00380 /* defines a peer-to-peer SIP relationship between [two UAs] and is  */
00381 /* referred to as a dialog."*/
00382 struct dlg_cell* get_dlg( str *callid, str *ftag, str *ttag, unsigned int *dir)
00383 {
00384    struct dlg_cell *dlg;
00385 
00386    if ((dlg = internal_get_dlg(core_hash(callid, ftag->len?ftag:0,
00387          d_table->size), callid, ftag, ttag, dir)) == 0 &&
00388          (dlg = internal_get_dlg(core_hash(callid, ttag->len
00389          ?ttag:0, d_table->size), callid, ftag, ttag, dir)) == 0) {
00390       LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
00391       return 0;
00392    }
00393    return dlg;
00394 }
00395 
00396 
00397 
00398 void link_dlg(struct dlg_cell *dlg, int n)
00399 {
00400    struct dlg_entry *d_entry;
00401 
00402    d_entry = &(d_table->entries[dlg->h_entry]);
00403 
00404    dlg_lock( d_table, d_entry);
00405 
00406    dlg->h_id = d_entry->next_id++;
00407    if (d_entry->first==0) {
00408       d_entry->first = d_entry->last = dlg;
00409    } else {
00410       d_entry->last->next = dlg;
00411       dlg->prev = d_entry->last;
00412       d_entry->last = dlg;
00413    }
00414 
00415    dlg->ref += 1 + n;
00416 
00417    LM_DBG("ref dlg %p with %d -> %d\n", dlg, n+1, dlg->ref);
00418 
00419    dlg_unlock( d_table, d_entry);
00420    return;
00421 }
00422 
00423 
00424 
00425 inline void unlink_unsafe_dlg(struct dlg_entry *d_entry,
00426                                        struct dlg_cell *dlg)
00427 {
00428    if (dlg->next)
00429       dlg->next->prev = dlg->prev;
00430    else
00431       d_entry->last = dlg->prev;
00432    if (dlg->prev)
00433       dlg->prev->next = dlg->next;
00434    else
00435       d_entry->first = dlg->next;
00436 
00437    dlg->next = dlg->prev = 0;
00438 
00439    return;
00440 }
00441 
00442 
00443 void ref_dlg(struct dlg_cell *dlg, unsigned int cnt)
00444 {
00445    struct dlg_entry *d_entry;
00446 
00447    d_entry = &(d_table->entries[dlg->h_entry]);
00448 
00449    dlg_lock( d_table, d_entry);
00450    ref_dlg_unsafe( dlg, cnt);
00451    dlg_unlock( d_table, d_entry);
00452 }
00453 
00454 
00455 void unref_dlg(struct dlg_cell *dlg, unsigned int cnt)
00456 {
00457    struct dlg_entry *d_entry;
00458 
00459    d_entry = &(d_table->entries[dlg->h_entry]);
00460 
00461    dlg_lock( d_table, d_entry);
00462    unref_dlg_unsafe( dlg, cnt, d_entry);
00463    dlg_unlock( d_table, d_entry);
00464 }
00465 
00466 
00467 /**
00468  * Small logging helper functions for next_state_dlg.
00469  * \param event logged event
00470  * \param dlg dialog data
00471  * \see next_state_dlg
00472  */
00473 static inline void log_next_state_dlg(const int event, const struct dlg_cell *dlg) {
00474    LM_CRIT("bogus event %d in state %d for dlg %p [%u:%u] with clid '%.*s' and tags "
00475       "'%.*s' '%.*s'\n", event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
00476       dlg->callid.len, dlg->callid.s,
00477       dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00478       dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00479 }
00480 
00481 
00482 void next_state_dlg(struct dlg_cell *dlg, int event,
00483                         int *old_state, int *new_state, int *unref)
00484 {
00485    struct dlg_entry *d_entry;
00486 
00487    d_entry = &(d_table->entries[dlg->h_entry]);
00488 
00489    *unref = 0;
00490 
00491    dlg_lock( d_table, d_entry);
00492 
00493    *old_state = dlg->state;
00494 
00495    switch (event) {
00496       case DLG_EVENT_TDEL:
00497          switch (dlg->state) {
00498             case DLG_STATE_UNCONFIRMED:
00499             case DLG_STATE_EARLY:
00500                dlg->state = DLG_STATE_DELETED;
00501                unref_dlg_unsafe(dlg,1,d_entry);
00502                *unref = 1;
00503                break;
00504             case DLG_STATE_CONFIRMED_NA:
00505             case DLG_STATE_CONFIRMED:
00506                unref_dlg_unsafe(dlg,1,d_entry);
00507                break;
00508             case DLG_STATE_DELETED:
00509                *unref = 1;
00510                break;
00511             default:
00512                log_next_state_dlg(event, dlg);
00513          }
00514          break;
00515       case DLG_EVENT_RPL1xx:
00516          switch (dlg->state) {
00517             case DLG_STATE_UNCONFIRMED:
00518             case DLG_STATE_EARLY:
00519                dlg->state = DLG_STATE_EARLY;
00520                break;
00521             default:
00522                log_next_state_dlg(event, dlg);
00523          }
00524          break;
00525       case DLG_EVENT_RPL3xx:
00526          switch (dlg->state) {
00527             case DLG_STATE_UNCONFIRMED:
00528             case DLG_STATE_EARLY:
00529                dlg->state = DLG_STATE_DELETED;
00530                *unref = 1;
00531                break;
00532             default:
00533                log_next_state_dlg(event, dlg);
00534          }
00535          break;
00536       case DLG_EVENT_RPL2xx:
00537          switch (dlg->state) {
00538             case DLG_STATE_DELETED:
00539                if (dlg->dflags&DLG_FLAG_HASBYE) {
00540                   LM_CRIT("bogus event %d in state %d (with BYE) "
00541                      "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n",
00542                      event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
00543                      dlg->callid.len, dlg->callid.s,
00544                      dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00545                      dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00546                   break;
00547                }
00548                ref_dlg_unsafe(dlg,1);
00549             case DLG_STATE_UNCONFIRMED:
00550             case DLG_STATE_EARLY:
00551                dlg->state = DLG_STATE_CONFIRMED_NA;
00552                break;
00553             case DLG_STATE_CONFIRMED_NA:
00554             case DLG_STATE_CONFIRMED:
00555                break;
00556             default:
00557                log_next_state_dlg(event, dlg);
00558          }
00559          break;
00560       case DLG_EVENT_REQACK:
00561          switch (dlg->state) {
00562             case DLG_STATE_CONFIRMED_NA:
00563                dlg->state = DLG_STATE_CONFIRMED;
00564                break;
00565             case DLG_STATE_CONFIRMED:
00566                break;
00567             case DLG_STATE_DELETED:
00568                break;
00569             default:
00570                log_next_state_dlg(event, dlg);
00571          }
00572          break;
00573       case DLG_EVENT_REQBYE:
00574          switch (dlg->state) {
00575             case DLG_STATE_CONFIRMED_NA:
00576             case DLG_STATE_CONFIRMED:
00577                dlg->dflags |= DLG_FLAG_HASBYE;
00578                dlg->state = DLG_STATE_DELETED;
00579                *unref = 1;
00580                break;
00581             case DLG_STATE_DELETED:
00582                break;
00583             default:
00584                log_next_state_dlg(event, dlg);
00585          }
00586          break;
00587       case DLG_EVENT_REQPRACK:
00588          switch (dlg->state) {
00589             case DLG_STATE_EARLY:
00590             case DLG_STATE_CONFIRMED_NA:
00591                break;
00592             default:
00593                log_next_state_dlg(event, dlg);
00594          }
00595          break;
00596       case DLG_EVENT_REQ:
00597          switch (dlg->state) {
00598             case DLG_STATE_CONFIRMED_NA:
00599             case DLG_STATE_CONFIRMED:
00600                break;
00601             default:
00602                log_next_state_dlg(event, dlg);
00603          }
00604          break;
00605       default:
00606          LM_CRIT("unknown event %d in state %d "
00607             "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n",
00608             event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
00609             dlg->callid.len, dlg->callid.s,
00610             dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00611             dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00612    }
00613    *new_state = dlg->state;
00614 
00615    dlg_unlock( d_table, d_entry);
00616 
00617    LM_DBG("dialog %p changed from state %d to "
00618       "state %d, due event %d\n",dlg,*old_state,*new_state,event);
00619 }
00620 
00621 
00622 /**************************** MI functions ******************************/
00623 static inline int internal_mi_print_dlg(struct mi_node *rpl,
00624                            struct dlg_cell *dlg, int with_context)
00625 {
00626    struct mi_node* node= NULL;
00627    struct mi_node* node1 = NULL;
00628    struct mi_attr* attr= NULL;
00629    int len;
00630    char* p;
00631 
00632    node = add_mi_node_child(rpl, 0, "dialog",6 , 0, 0 );
00633    if (node==0)
00634       goto error;
00635 
00636    attr = addf_mi_attr( node, 0, "hash", 4, "%u:%u",
00637          dlg->h_entry, dlg->h_id );
00638    if (attr==0)
00639       goto error;
00640 
00641    p= int2str((unsigned long)dlg->state, &len);
00642    node1 = add_mi_node_child( node, MI_DUP_VALUE, "state", 5, p, len);
00643    if (node1==0)
00644       goto error;
00645 
00646    p= int2str((unsigned long)dlg->start_ts, &len);
00647    node1 = add_mi_node_child(node,MI_DUP_VALUE,"timestart",9, p, len);
00648    if (node1==0)
00649       goto error;
00650 
00651    p= int2str((unsigned long)dlg->tl.timeout, &len);
00652    node1 = add_mi_node_child(node,MI_DUP_VALUE, "timeout", 7, p, len);
00653    if (node1==0)
00654       goto error;
00655 
00656    node1 = add_mi_node_child(node, MI_DUP_VALUE, "callid", 6,
00657          dlg->callid.s, dlg->callid.len);
00658    if(node1 == 0)
00659       goto error;
00660 
00661    node1 = add_mi_node_child(node, MI_DUP_VALUE, "from_uri", 8,
00662          dlg->from_uri.s, dlg->from_uri.len);
00663    if(node1 == 0)
00664       goto error;
00665 
00666    node1 = add_mi_node_child(node, MI_DUP_VALUE, "from_tag", 8,
00667          dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLER_LEG].len);
00668    if(node1 == 0)
00669       goto error;
00670 
00671    node1 = add_mi_node_child(node, MI_DUP_VALUE, "caller_contact", 14,
00672          dlg->contact[DLG_CALLER_LEG].s,
00673          dlg->contact[DLG_CALLER_LEG].len);
00674    if(node1 == 0)
00675       goto error;
00676 
00677    node1 = add_mi_node_child(node, MI_DUP_VALUE, "caller_cseq", 11,
00678          dlg->cseq[DLG_CALLER_LEG].s,
00679          dlg->cseq[DLG_CALLER_LEG].len);
00680    if(node1 == 0)
00681       goto error;
00682 
00683    node1 = add_mi_node_child(node, MI_DUP_VALUE,"caller_route_set",16,
00684          dlg->route_set[DLG_CALLER_LEG].s,
00685          dlg->route_set[DLG_CALLER_LEG].len);
00686    if(node1 == 0)
00687       goto error;
00688 
00689    node1 = add_mi_node_child(node, 0,"caller_bind_addr",16,
00690          dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s, 
00691          dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len);
00692    if(node1 == 0)
00693       goto error;
00694 
00695    node1 = add_mi_node_child(node, MI_DUP_VALUE, "to_uri", 6,
00696          dlg->to_uri.s, dlg->to_uri.len);
00697    if(node1 == 0)
00698       goto error;
00699 
00700    node1 = add_mi_node_child(node, MI_DUP_VALUE, "to_tag", 6,
00701          dlg->tag[DLG_CALLEE_LEG].s, dlg->tag[DLG_CALLEE_LEG].len);
00702    if(node1 == 0)
00703       goto error;
00704 
00705    node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_contact", 14,
00706          dlg->contact[DLG_CALLEE_LEG].s,
00707          dlg->contact[DLG_CALLEE_LEG].len);
00708    if(node1 == 0)
00709       goto error;
00710 
00711    node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_cseq", 11,
00712          dlg->cseq[DLG_CALLEE_LEG].s,
00713          dlg->cseq[DLG_CALLEE_LEG].len);
00714    if(node1 == 0)
00715       goto error;
00716 
00717    node1 = add_mi_node_child(node, MI_DUP_VALUE,"callee_route_set",16,
00718          dlg->route_set[DLG_CALLEE_LEG].s,
00719          dlg->route_set[DLG_CALLEE_LEG].len);
00720    if(node1 == 0)
00721       goto error;
00722 
00723    if (dlg->bind_addr[DLG_CALLEE_LEG]) {
00724       node1 = add_mi_node_child(node, 0,
00725          "callee_bind_addr",16,
00726          dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s, 
00727          dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len);
00728    } else {
00729       node1 = add_mi_node_child(node, 0,
00730          "callee_bind_addr",16,0,0);
00731    }
00732    if(node1 == 0)
00733       goto error;
00734 
00735    if (with_context) {
00736       node1 = add_mi_node_child(node, 0, "context", 7, 0, 0);
00737       if(node1 == 0)
00738          goto error;
00739       run_dlg_callbacks( DLGCB_MI_CONTEXT, dlg, NULL, 
00740          DLG_DIR_NONE, (void *)node1);
00741    }
00742    return 0;
00743 
00744 error:
00745    LM_ERR("failed to add node\n");
00746    return -1;
00747 }
00748 
00749 
00750 int mi_print_dlg(struct mi_node *rpl, struct dlg_cell *dlg, int with_context)
00751 {
00752    return internal_mi_print_dlg( rpl, dlg, with_context);
00753 }
00754 
00755 
00756 static int internal_mi_print_dlgs(struct mi_node *rpl, int with_context)
00757 {
00758    struct dlg_cell *dlg;
00759    unsigned int i;
00760 
00761    LM_DBG("printing %i dialogs\n", d_table->size);
00762 
00763    for( i=0 ; i<d_table->size ; i++ ) {
00764       dlg_lock( d_table, &(d_table->entries[i]) );
00765 
00766       for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
00767          if (internal_mi_print_dlg(rpl, dlg, with_context)!=0)
00768             goto error;
00769       }
00770       dlg_unlock( d_table, &(d_table->entries[i]) );
00771    }
00772    return 0;
00773 
00774 error:
00775    dlg_unlock( d_table, &(d_table->entries[i]) );
00776    LM_ERR("failed to print dialog\n");
00777    return -1;
00778 }
00779 
00780 
00781 static inline struct mi_root* process_mi_params(struct mi_root *cmd_tree,
00782                                        struct dlg_cell **dlg_p)
00783 {
00784    struct mi_node* node;
00785    struct dlg_entry *d_entry;
00786    struct dlg_cell *dlg;
00787    str *callid;
00788    str *from_tag;
00789    unsigned int h_entry;
00790 
00791    node = cmd_tree->node.kids;
00792    if (node == NULL) {
00793       /* no parameters at all */
00794       *dlg_p = NULL;
00795       return NULL;
00796    }
00797 
00798    /* we have params -> get callid and fromtag */
00799    callid = &node->value;
00800    LM_DBG("callid='%.*s'\n", callid->len, callid->s);
00801 
00802    node = node->next;
00803    if ( !node || !node->value.s || !node->value.len) {
00804       from_tag = NULL;
00805    } else {
00806       from_tag = &node->value;
00807       LM_DBG("from_tag='%.*s'\n", from_tag->len, from_tag->s);
00808       if ( node->next!=NULL )
00809          return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
00810    }
00811 
00812    h_entry = core_hash( callid, from_tag, d_table->size);
00813 
00814    d_entry = &(d_table->entries[h_entry]);
00815    dlg_lock( d_table, d_entry);
00816 
00817    for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
00818       if (match_downstream_dialog( dlg, callid, from_tag)==1) {
00819          if (dlg->state==DLG_STATE_DELETED) {
00820             *dlg_p = NULL;
00821             break;
00822          } else {
00823             *dlg_p = dlg;
00824             dlg_unlock( d_table, d_entry);
00825             return 0;
00826          }
00827       }
00828    }
00829    dlg_unlock( d_table, d_entry);
00830 
00831    return init_mi_tree( 404, MI_SSTR("Nu such dialog"));
00832 }
00833 
00834 
00835 struct mi_root * mi_print_dlgs(struct mi_root *cmd_tree, void *param )
00836 {
00837    struct mi_root* rpl_tree= NULL;
00838    struct mi_node* rpl = NULL;
00839    struct dlg_cell* dlg = NULL;
00840 
00841    rpl_tree = process_mi_params( cmd_tree, &dlg);
00842    if (rpl_tree)
00843       /* param error */
00844       return rpl_tree;
00845 
00846    rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
00847    if (rpl_tree==0)
00848       return 0;
00849    rpl = &rpl_tree->node;
00850 
00851    if (dlg==NULL) {
00852       if ( internal_mi_print_dlgs(rpl,0)!=0 )
00853          goto error;
00854    } else {
00855       if ( internal_mi_print_dlg(rpl,dlg,0)!=0 )
00856          goto error;
00857    }
00858 
00859    return rpl_tree;
00860 error:
00861    free_mi_tree(rpl_tree);
00862    return NULL;
00863 }
00864 
00865 
00866 struct mi_root * mi_print_dlgs_ctx(struct mi_root *cmd_tree, void *param )
00867 {
00868    struct mi_root* rpl_tree= NULL;
00869    struct mi_node* rpl = NULL;
00870    struct dlg_cell* dlg = NULL;
00871 
00872    rpl_tree = process_mi_params( cmd_tree, &dlg);
00873    if (rpl_tree)
00874       /* param error */
00875       return rpl_tree;
00876 
00877    rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
00878    if (rpl_tree==0)
00879       return 0;
00880    rpl = &rpl_tree->node;
00881 
00882    if (dlg==NULL) {
00883       if ( internal_mi_print_dlgs(rpl,1)!=0 )
00884          goto error;
00885    } else {
00886       if ( internal_mi_print_dlg(rpl,dlg,1)!=0 )
00887          goto error;
00888    }
00889 
00890    return rpl_tree;
00891 error:
00892    free_mi_tree(rpl_tree);
00893    return NULL;
00894 }
00895 
00896 
00897 

Generated on Tue May 22 16:00:26 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6