dlg_hash.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Voice System SRL
00003  * Copyright (C) 2011 Carsten Bock, carsten@ng-voice.com
00004  *
00005  * This file is part of Kamailio, a free SIP server.
00006  *
00007  * Kamailio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version
00011  *
00012  * Kamailio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License 
00018  * along with this program; if not, write to the Free Software 
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  * History:
00022  * --------
00023  * 2006-04-14  initial version (bogdan)
00024  * 2007-03-06  syncronized state machine added for dialog state. New tranzition
00025  *             design based on events; removed num_1xx and num_2xx (bogdan)
00026  * 2007-04-30  added dialog matching without DID (dialog ID), but based only
00027  *             on RFC3261 elements - based on an original patch submitted 
00028  *             by Michel Bensoussan <michel@extricom.com> (bogdan)
00029  * 2007-07-06  additional information stored in order to save it in the db:
00030  *             cseq, route_set, contact and sock_info for both caller and 
00031  *             callee (ancuta)
00032  * 2007-07-10  Optimized dlg_match_mode 2 (DID_NONE), it now employs a proper
00033  *             hash table lookup and isn't dependant on the is_direction 
00034  *             function (which requires an RR param like dlg_match_mode 0 
00035  *             anyways.. ;) ; based on a patch from 
00036  *             Tavis Paquette <tavis@galaxytelecom.net> 
00037  *             and Peter Baer <pbaer@galaxytelecom.net>  (bogdan)
00038  * 2008-04-17  added new type of callback to be triggered right before the
00039  *              dialog is destroyed (deleted from memory) (bogdan)
00040  * 2008-04-17  added new dialog flag to avoid state tranzitions from DELETED to
00041  *             CONFIRMED_NA due delayed "200 OK" (bogdan)
00042  */
00043 
00044 
00052 #include <stdlib.h>
00053 #include <string.h>
00054 
00055 #include "../../dprint.h"
00056 #include "../../ut.h"
00057 #include "../../hashes.h"
00058 #include "../../lib/kmi/mi.h"
00059 #include "dlg_timer.h"
00060 #include "dlg_var.h"
00061 #include "dlg_hash.h"
00062 #include "dlg_profile.h"
00063 #include "dlg_req_within.h"
00064 #include "dlg_db_handler.h"
00065 
00066 #define MAX_LDG_LOCKS  2048
00067 #define MIN_LDG_LOCKS  2
00068 
00069 extern int dlg_ka_interval;
00070 
00072 struct dlg_table *d_table = 0;
00073 
00074 dlg_ka_t **dlg_ka_list_head = NULL;
00075 dlg_ka_t **dlg_ka_list_tail = NULL;
00076 gen_lock_t *dlg_ka_list_lock = NULL;
00077 
00083 #define ref_dlg_unsafe(_dlg,_cnt)     \
00084         do { \
00085                 (_dlg)->ref += (_cnt); \
00086                 LM_DBG("ref dlg %p with %d -> %d\n", \
00087                         (_dlg),(_cnt),(_dlg)->ref); \
00088         }while(0)
00089 
00090 
00097 #define unref_dlg_unsafe(_dlg,_cnt,_d_entry)   \
00098         do { \
00099                 if((_dlg)->ref <= 0 ) { \
00100                         LM_WARN("invalid unref'ing dlg %p with ref %d by %d\n",\
00101                                         (_dlg),(_dlg)->ref,(_cnt));\
00102                         break; \
00103                 } \
00104                 (_dlg)->ref -= (_cnt); \
00105                 LM_DBG("unref dlg %p with %d -> %d\n",\
00106                         (_dlg),(_cnt),(_dlg)->ref);\
00107                 if ((_dlg)->ref<0) {\
00108                         LM_CRIT("bogus ref %d with cnt %d for dlg %p [%u:%u] "\
00109                                 "with clid '%.*s' and tags '%.*s' '%.*s'\n",\
00110                                 (_dlg)->ref, _cnt, _dlg,\
00111                                 (_dlg)->h_entry, (_dlg)->h_id,\
00112                                 (_dlg)->callid.len, (_dlg)->callid.s,\
00113                                 (_dlg)->tag[DLG_CALLER_LEG].len,\
00114                                 (_dlg)->tag[DLG_CALLER_LEG].s,\
00115                                 (_dlg)->tag[DLG_CALLEE_LEG].len,\
00116                                 (_dlg)->tag[DLG_CALLEE_LEG].s); \
00117                 }\
00118                 if ((_dlg)->ref<=0) { \
00119                         unlink_unsafe_dlg( _d_entry, _dlg);\
00120                         LM_DBG("ref <=0 for dialog %p\n",_dlg);\
00121                         destroy_dlg(_dlg);\
00122                 }\
00123         }while(0)
00124 
00129 int dlg_ka_add(dlg_cell_t *dlg)
00130 {
00131         dlg_ka_t *dka;
00132 
00133         if(dlg_ka_interval<=0)
00134                 return 0;
00135         if(!(dlg->iflags & (DLG_IFLAG_KA_SRC | DLG_IFLAG_KA_SRC)))
00136                 return 0;
00137 
00138         dka = (dlg_ka_t*)shm_malloc(sizeof(dlg_ka_t));
00139         if(dka==NULL) {
00140                 LM_ERR("no more shm mem\n");
00141                 return -1;
00142         }
00143         memset(dka, 0, sizeof(dlg_ka_t));
00144         dka->katime = get_ticks() + dlg_ka_interval;
00145         dka->iuid.h_entry = dlg->h_entry;
00146         dka->iuid.h_id = dlg->h_id;
00147         dka->iflags = dlg->iflags;
00148 
00149         lock_get(dlg_ka_list_lock);
00150         if(*dlg_ka_list_tail!=NULL)
00151                 (*dlg_ka_list_tail)->next = dka;
00152         if(*dlg_ka_list_head==NULL)
00153                 *dlg_ka_list_head = dka;
00154         *dlg_ka_list_tail = dka;
00155         lock_release(dlg_ka_list_lock);
00156         LM_DBG("added dlg[%d,%d] to KA list\n", dlg->h_entry, dlg->h_id);
00157         return 0;
00158 }
00159 
00164 int dlg_ka_run(ticks_t ti)
00165 {
00166         dlg_ka_t *dka;
00167         dlg_cell_t *dlg;
00168 
00169         if(dlg_ka_interval<=0)
00170                 return 0;
00171 
00172         while(1) {
00173                 /* get head item */
00174                 lock_get(dlg_ka_list_lock);
00175                 if(*dlg_ka_list_head==NULL) {
00176                         lock_release(dlg_ka_list_lock);
00177                         return 0;
00178                 }
00179                 dka = *dlg_ka_list_head;
00180 #if 0
00181                 LM_DBG("dlg ka timer at %lu for"
00182                                 " dlg[%u,%u] on %lu\n", (unsigned long)ti,
00183                                 dka->iuid.h_entry, dka->iuid.h_id,
00184                                 (unsigned long)dka->katime);
00185 #endif
00186                 if(dka->katime>ti) {
00187                         lock_release(dlg_ka_list_lock);
00188                         return 0;
00189                 }
00190                 if(*dlg_ka_list_head == *dlg_ka_list_tail) {
00191                         *dlg_ka_list_head = NULL;
00192                         *dlg_ka_list_head = NULL;
00193                 }
00194                 *dlg_ka_list_head = dka->next;
00195                 lock_release(dlg_ka_list_lock);
00196 
00197                 /* send keep-alive for dka */
00198                 dlg = dlg_get_by_iuid(&dka->iuid);
00199                 if(dlg==NULL) {
00200                         shm_free(dka);
00201                         dka = NULL;
00202                 } else {
00203                         if(dka->iflags & DLG_IFLAG_KA_SRC)
00204                                 dlg_send_ka(dlg, DLG_CALLER_LEG, 0);
00205                         if(dka->iflags & DLG_IFLAG_KA_DST)
00206                                 dlg_send_ka(dlg, DLG_CALLEE_LEG, 0);
00207                         dlg_release(dlg);
00208                 }
00209                 /* append to tail */
00210                 if(dka!=NULL)
00211                 {
00212                         lock_get(dlg_ka_list_lock);
00213                         if(*dlg_ka_list_tail!=NULL)
00214                                 (*dlg_ka_list_tail)->next = dka;
00215                         if(*dlg_ka_list_head==NULL)
00216                                 *dlg_ka_list_tail = dka;
00217                         *dlg_ka_list_tail = dka;
00218                         lock_release(dlg_ka_list_lock);
00219                 }
00220         }
00221 
00222         return 0;
00223 }
00224 
00230 int init_dlg_table(unsigned int size)
00231 {
00232         unsigned int n;
00233         unsigned int i;
00234 
00235         dlg_ka_list_head = (dlg_ka_t **)shm_malloc(sizeof(dlg_ka_t *));
00236         if(dlg_ka_list_head==NULL) {
00237                 LM_ERR("no more shm mem (h)\n");
00238                 goto error0;
00239         }
00240         dlg_ka_list_tail = (dlg_ka_t **)shm_malloc(sizeof(dlg_ka_t *));
00241         if(dlg_ka_list_tail==NULL) {
00242                 LM_ERR("no more shm mem (t)\n");
00243                 goto error0;
00244         }
00245         *dlg_ka_list_head = NULL;
00246         *dlg_ka_list_tail = NULL;
00247         dlg_ka_list_lock = (gen_lock_t*)shm_malloc(sizeof(gen_lock_t));
00248         if(dlg_ka_list_lock==NULL) {
00249                 LM_ERR("no more shm mem (l)\n");
00250                 goto error0;
00251         }
00252         lock_init(dlg_ka_list_lock);
00253 
00254         d_table = (struct dlg_table*)shm_malloc
00255                 ( sizeof(struct dlg_table) + size*sizeof(struct dlg_entry));
00256         if (d_table==0) {
00257                 LM_ERR("no more shm mem (1)\n");
00258                 goto error0;
00259         }
00260 
00261         memset( d_table, 0, sizeof(struct dlg_table) );
00262         d_table->size = size;
00263         d_table->entries = (struct dlg_entry*)(d_table+1);
00264 
00265         n = (size<MAX_LDG_LOCKS)?size:MAX_LDG_LOCKS;
00266         for(  ; n>=MIN_LDG_LOCKS ; n-- ) {
00267                 d_table->locks = lock_set_alloc(n);
00268                 if (d_table->locks==0)
00269                         continue;
00270                 if (lock_set_init(d_table->locks)==0) {
00271                         lock_set_dealloc(d_table->locks);
00272                         d_table->locks = 0;
00273                         continue;
00274                 }
00275                 d_table->locks_no = n;
00276                 break;
00277         }
00278 
00279         if (d_table->locks==0) {
00280                 LM_ERR("unable to allocted at least %d locks for the hash table\n",
00281                         MIN_LDG_LOCKS);
00282                 goto error1;
00283         }
00284 
00285         for( i=0 ; i<size; i++ ) {
00286                 memset( &(d_table->entries[i]), 0, sizeof(struct dlg_entry) );
00287                 d_table->entries[i].next_id = rand() % (3*size);
00288                 d_table->entries[i].lock_idx = i % d_table->locks_no;
00289         }
00290 
00291         return 0;
00292 error1:
00293         shm_free( d_table );
00294         d_table = NULL;
00295 error0:
00296         if(dlg_ka_list_head!=NULL)
00297                 shm_free(dlg_ka_list_head);
00298         if(dlg_ka_list_tail!=NULL)
00299                 shm_free(dlg_ka_list_tail);
00300         dlg_ka_list_head = NULL;
00301         dlg_ka_list_tail = NULL;
00302         return -1;
00303 }
00304 
00305 
00310 inline void destroy_dlg(struct dlg_cell *dlg)
00311 {
00312         int ret = 0;
00313         struct dlg_var *var;
00314 
00315         LM_DBG("destroying dialog %p (ref %d)\n", dlg, dlg->ref);
00316 
00317         ret = remove_dialog_timer(&dlg->tl);
00318         if (ret < 0) {
00319                 LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
00320                         "with clid '%.*s' and tags '%.*s' '%.*s'\n",
00321                         dlg, dlg->h_entry, dlg->h_id,
00322                         dlg->callid.len, dlg->callid.s,
00323                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00324                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00325         } else if (ret > 0) {
00326                 LM_DBG("removed timer for dlg %p [%u:%u] "
00327                         "with clid '%.*s' and tags '%.*s' '%.*s'\n",
00328                         dlg, dlg->h_entry, dlg->h_id,
00329                         dlg->callid.len, dlg->callid.s,
00330                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00331                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00332         }
00333 
00334         run_dlg_callbacks( DLGCB_DESTROY , dlg, NULL, NULL, DLG_DIR_NONE, 0);
00335 
00336 
00337         /* delete the dialog from DB*/
00338         if (dlg_db_mode)
00339                 remove_dialog_from_db(dlg);
00340 
00341         if (dlg->cbs.first)
00342                 destroy_dlg_callbacks_list(dlg->cbs.first);
00343 
00344         if (dlg->profile_links)
00345                 destroy_linkers(dlg->profile_links);
00346 
00347         if (dlg->tag[DLG_CALLER_LEG].s)
00348                 shm_free(dlg->tag[DLG_CALLER_LEG].s);
00349 
00350         if (dlg->tag[DLG_CALLEE_LEG].s)
00351                 shm_free(dlg->tag[DLG_CALLEE_LEG].s);
00352 
00353         if (dlg->cseq[DLG_CALLER_LEG].s)
00354                 shm_free(dlg->cseq[DLG_CALLER_LEG].s);
00355 
00356         if (dlg->cseq[DLG_CALLEE_LEG].s)
00357                 shm_free(dlg->cseq[DLG_CALLEE_LEG].s);
00358 
00359         if (dlg->toroute_name.s)
00360                 shm_free(dlg->toroute_name.s);
00361 
00362         
00363         while (dlg->vars) {
00364                 var = dlg->vars;
00365                 dlg->vars = dlg->vars->next;
00366                 shm_free(var->key.s);
00367                 shm_free(var->value.s);
00368                 shm_free(var);
00369         }
00370 
00371 
00372         shm_free(dlg);
00373         dlg = 0;
00374 }
00375 
00376 
00380 void destroy_dlg_table(void)
00381 {
00382         struct dlg_cell *dlg, *l_dlg;
00383         unsigned int i;
00384 
00385         if (d_table==0)
00386                 return;
00387 
00388         if (d_table->locks) {
00389                 lock_set_destroy(d_table->locks);
00390                 lock_set_dealloc(d_table->locks);
00391         }
00392 
00393         for( i=0 ; i<d_table->size; i++ ) {
00394                 dlg = d_table->entries[i].first;
00395                 while (dlg) {
00396                         l_dlg = dlg;
00397                         dlg = dlg->next;
00398                         destroy_dlg(l_dlg);
00399                 }
00400 
00401         }
00402 
00403         shm_free(d_table);
00404         d_table = 0;
00405 
00406         return;
00407 }
00408 
00409 
00419 struct dlg_cell* build_new_dlg( str *callid, str *from_uri, str *to_uri,
00420                 str *from_tag, str *req_uri)
00421 {
00422         struct dlg_cell *dlg;
00423         int len;
00424         char *p;
00425 
00426         len = sizeof(struct dlg_cell) + callid->len + from_uri->len +
00427                 to_uri->len + req_uri->len;
00428         dlg = (struct dlg_cell*)shm_malloc( len );
00429         if (dlg==0) {
00430                 LM_ERR("no more shm mem (%d)\n",len);
00431                 return 0;
00432         }
00433 
00434         memset( dlg, 0, len);
00435         dlg->state = DLG_STATE_UNCONFIRMED;
00436 
00437         dlg->h_entry = core_hash( callid, 0, d_table->size);
00438         LM_DBG("new dialog on hash %u\n",dlg->h_entry);
00439 
00440         p = (char*)(dlg+1);
00441 
00442         dlg->callid.s = p;
00443         dlg->callid.len = callid->len;
00444         memcpy( p, callid->s, callid->len);
00445         p += callid->len;
00446 
00447         dlg->from_uri.s = p;
00448         dlg->from_uri.len = from_uri->len;
00449         memcpy( p, from_uri->s, from_uri->len);
00450         p += from_uri->len;
00451 
00452         dlg->to_uri.s = p;
00453         dlg->to_uri.len = to_uri->len;
00454         memcpy( p, to_uri->s, to_uri->len);
00455         p += to_uri->len; 
00456 
00457         dlg->req_uri.s = p;
00458         dlg->req_uri.len = req_uri->len;
00459         memcpy( p, req_uri->s, req_uri->len);
00460         p += req_uri->len;
00461 
00462         if ( p!=(((char*)dlg)+len) ) {
00463                 LM_CRIT("buffer overflow\n");
00464                 shm_free(dlg);
00465                 return 0;
00466         }
00467 
00468         return dlg;
00469 }
00470 
00471 
00482 int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
00483                                         str *cseq, unsigned int leg)
00484 {
00485         char *p;
00486 
00487         dlg->tag[leg].s = (char*)shm_malloc( tag->len + rr->len + contact->len );
00488         dlg->cseq[leg].s = (char*)shm_malloc( cseq->len );
00489         if ( dlg->tag[leg].s==NULL || dlg->cseq[leg].s==NULL) {
00490                 LM_ERR("no more shm mem\n");
00491                 if (dlg->tag[leg].s)
00492                 {
00493                         shm_free(dlg->tag[leg].s);
00494                         dlg->tag[leg].s = NULL;
00495                 }
00496                 if (dlg->cseq[leg].s)
00497                 {
00498                         shm_free(dlg->cseq[leg].s);
00499                         dlg->cseq[leg].s = NULL;
00500                 }
00501                 return -1;
00502         }
00503         p = dlg->tag[leg].s;
00504 
00505         /* tag */
00506         dlg->tag[leg].len = tag->len;
00507         memcpy( p, tag->s, tag->len);
00508         p += tag->len;
00509         /* contact */
00510         dlg->contact[leg].s = p;
00511         dlg->contact[leg].len = contact->len;
00512         memcpy( p, contact->s, contact->len);
00513         p += contact->len;
00514         /* rr */
00515         if (rr->len) {
00516                 dlg->route_set[leg].s = p;
00517                 dlg->route_set[leg].len = rr->len;
00518                 memcpy( p, rr->s, rr->len);
00519         }
00520 
00521         /* cseq */
00522         dlg->cseq[leg].len = cseq->len;
00523         memcpy( dlg->cseq[leg].s, cseq->s, cseq->len);
00524 
00525         return 0;
00526 }
00527 
00528 
00536 int dlg_update_cseq(struct dlg_cell * dlg, unsigned int leg, str *cseq)
00537 {
00538         if ( dlg->cseq[leg].s ) {
00539                 if (dlg->cseq[leg].len < cseq->len) {
00540                         shm_free(dlg->cseq[leg].s);
00541                         dlg->cseq[leg].s = (char*)shm_malloc(cseq->len);
00542                         if (dlg->cseq[leg].s==NULL)
00543                                 goto error;
00544                 }
00545         } else {
00546                 dlg->cseq[leg].s = (char*)shm_malloc(cseq->len);
00547                 if (dlg->cseq[leg].s==NULL)
00548                         goto error;
00549         }
00550 
00551         memcpy( dlg->cseq[leg].s, cseq->s, cseq->len );
00552         dlg->cseq[leg].len = cseq->len;
00553 
00554         LM_DBG("cseq is %.*s\n", dlg->cseq[leg].len, dlg->cseq[leg].s);
00555         return 0;
00556 error:
00557         LM_ERR("not more shm mem\n");
00558         return -1;
00559 }
00560 
00561 
00571 dlg_cell_t *dlg_lookup( unsigned int h_entry, unsigned int h_id)
00572 {
00573         dlg_cell_t *dlg;
00574         dlg_entry_t *d_entry;
00575 
00576         if(d_table==NULL)
00577                 return 0;
00578 
00579         if (h_entry>=d_table->size)
00580                 goto not_found;
00581 
00582         d_entry = &(d_table->entries[h_entry]);
00583 
00584         dlg_lock( d_table, d_entry);
00585 
00586         for( dlg=d_entry->first ; dlg ; dlg=dlg->next ) {
00587                 if (dlg->h_id == h_id) {
00588                         ref_dlg_unsafe(dlg, 1);
00589                         dlg_unlock( d_table, d_entry);
00590                         LM_DBG("dialog id=%u found on entry %u\n", h_id, h_entry);
00591                         return dlg;
00592                 }
00593         }
00594 
00595         dlg_unlock( d_table, d_entry);
00596 not_found:
00597         LM_DBG("no dialog id=%u found on entry %u\n", h_id, h_entry);
00598         return 0;
00599 }
00600 
00601 
00610 dlg_cell_t* dlg_get_by_iuid(dlg_iuid_t *diuid)
00611 {
00612         if(diuid==NULL)
00613                 return NULL;
00614         if(diuid->h_id==0)
00615                 return NULL;
00616         /* dlg ref counter is increased by next line */
00617         return dlg_lookup(diuid->h_entry, diuid->h_id);
00618 }
00619 
00630 static inline struct dlg_cell* internal_get_dlg(unsigned int h_entry,
00631                                                 str *callid, str *ftag, str *ttag, unsigned int *dir)
00632 {
00633         struct dlg_cell *dlg;
00634         struct dlg_entry *d_entry;
00635 
00636         d_entry = &(d_table->entries[h_entry]);
00637 
00638         dlg_lock( d_table, d_entry);
00639 
00640         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
00641                 /* Check callid / fromtag / totag */
00642                 if (match_dialog( dlg, callid, ftag, ttag, dir)==1) {
00643                         ref_dlg_unsafe(dlg, 1);
00644                         dlg_unlock( d_table, d_entry);
00645                         LM_DBG("dialog callid='%.*s' found\n on entry %u, dir=%d\n",
00646                                 callid->len, callid->s,h_entry,*dir);
00647                         return dlg;
00648                 }
00649         }
00650 
00651         dlg_unlock( d_table, d_entry);
00652         LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
00653         return 0;
00654 }
00655 
00656 
00657 
00674 struct dlg_cell* get_dlg( str *callid, str *ftag, str *ttag, unsigned int *dir)
00675 {
00676         struct dlg_cell *dlg;
00677         unsigned int he;
00678 
00679         he = core_hash(callid, 0, d_table->size);
00680         dlg = internal_get_dlg(he, callid, ftag, ttag, dir);
00681 
00682         if (dlg == 0) {
00683                 LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
00684                 return 0;
00685         }
00686         return dlg;
00687 }
00688 
00689 
00695 void link_dlg(struct dlg_cell *dlg, int n)
00696 {
00697         struct dlg_entry *d_entry;
00698 
00699         d_entry = &(d_table->entries[dlg->h_entry]);
00700 
00701         dlg_lock( d_table, d_entry);
00702 
00703         /* keep id 0 for special cases */
00704         dlg->h_id = 1 + d_entry->next_id++;
00705         if(dlg->h_id == 0) dlg->h_id = 1;
00706         LM_DBG("linking dialog [%u:%u]\n", dlg->h_entry, dlg->h_id);
00707         if (d_entry->first==0) {
00708                 d_entry->first = d_entry->last = dlg;
00709         } else {
00710                 d_entry->last->next = dlg;
00711                 dlg->prev = d_entry->last;
00712                 d_entry->last = dlg;
00713         }
00714 
00715         ref_dlg_unsafe(dlg, 1+n);
00716 
00717         dlg_unlock( d_table, d_entry);
00718         return;
00719 }
00720 
00721 
00728 void dlg_ref(dlg_cell_t *dlg, unsigned int cnt)
00729 {
00730         dlg_entry_t *d_entry;
00731 
00732         d_entry = &(d_table->entries[dlg->h_entry]);
00733 
00734         dlg_lock( d_table, d_entry);
00735         ref_dlg_unsafe( dlg, cnt);
00736         dlg_unlock( d_table, d_entry);
00737 }
00738 
00739 
00746 void dlg_unref(dlg_cell_t *dlg, unsigned int cnt)
00747 {
00748         dlg_entry_t *d_entry;
00749 
00750         d_entry = &(d_table->entries[dlg->h_entry]);
00751 
00752         dlg_lock( d_table, d_entry);
00753         unref_dlg_unsafe( dlg, cnt, d_entry);
00754         dlg_unlock( d_table, d_entry);
00755 }
00756 
00757 
00763 void dlg_release(dlg_cell_t *dlg)
00764 {
00765         if(dlg==NULL)
00766                 return;
00767         dlg_unref(dlg, 1);
00768 }
00769 
00770 
00777 static inline void log_next_state_dlg(const int event, const struct dlg_cell *dlg) {
00778         LM_CRIT("bogus event %d in state %d for dlg %p [%u:%u] with clid '%.*s' and tags "
00779                 "'%.*s' '%.*s'\n", event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
00780                 dlg->callid.len, dlg->callid.s,
00781                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00782                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00783 }
00784 
00785 
00799 void next_state_dlg(dlg_cell_t *dlg, int event,
00800                 int *old_state, int *new_state, int *unref)
00801 {
00802         dlg_entry_t *d_entry;
00803 
00804         d_entry = &(d_table->entries[dlg->h_entry]);
00805 
00806         *unref = 0;
00807 
00808         dlg_lock( d_table, d_entry);
00809 
00810         *old_state = dlg->state;
00811 
00812         switch (event) {
00813                 case DLG_EVENT_TDEL:
00814                         switch (dlg->state) {
00815                                 case DLG_STATE_UNCONFIRMED:
00816                                 case DLG_STATE_EARLY:
00817                                         dlg->state = DLG_STATE_DELETED;
00818                                         unref_dlg_unsafe(dlg,1,d_entry);
00819                                         *unref = 1;
00820                                         break;
00821                                 case DLG_STATE_CONFIRMED_NA:
00822                                 case DLG_STATE_CONFIRMED:
00823                                         unref_dlg_unsafe(dlg,1,d_entry);
00824                                         break;
00825                                 case DLG_STATE_DELETED:
00826                                         *unref = 1;
00827                                         break;
00828                                 default:
00829                                         log_next_state_dlg(event, dlg);
00830                         }
00831                         break;
00832                 case DLG_EVENT_RPL1xx:
00833                         switch (dlg->state) {
00834                                 case DLG_STATE_UNCONFIRMED:
00835                                 case DLG_STATE_EARLY:
00836                                         dlg->state = DLG_STATE_EARLY;
00837                                         break;
00838                                 default:
00839                                         log_next_state_dlg(event, dlg);
00840                         }
00841                         break;
00842                 case DLG_EVENT_RPL3xx:
00843                         switch (dlg->state) {
00844                                 case DLG_STATE_UNCONFIRMED:
00845                                 case DLG_STATE_EARLY:
00846                                         dlg->state = DLG_STATE_DELETED;
00847                                         *unref = 1;
00848                                         break;
00849                                 default:
00850                                         log_next_state_dlg(event, dlg);
00851                         }
00852                         break;
00853                 case DLG_EVENT_RPL2xx:
00854                         switch (dlg->state) {
00855                                 case DLG_STATE_DELETED:
00856                                         if (dlg->dflags&DLG_FLAG_HASBYE) {
00857                                                 LM_CRIT("bogus event %d in state %d (with BYE) "
00858                                                         "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n",
00859                                                         event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
00860                                                         dlg->callid.len, dlg->callid.s,
00861                                                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00862                                                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00863                                                 break;
00864                                         }
00865                                         ref_dlg_unsafe(dlg,1);
00866                                 case DLG_STATE_UNCONFIRMED:
00867                                 case DLG_STATE_EARLY:
00868                                         dlg->state = DLG_STATE_CONFIRMED_NA;
00869                                         break;
00870                                 case DLG_STATE_CONFIRMED_NA:
00871                                 case DLG_STATE_CONFIRMED:
00872                                         break;
00873                                 default:
00874                                         log_next_state_dlg(event, dlg);
00875                         }
00876                         break;
00877                 case DLG_EVENT_REQACK:
00878                         switch (dlg->state) {
00879                                 case DLG_STATE_CONFIRMED_NA:
00880                                         dlg->state = DLG_STATE_CONFIRMED;
00881                                         break;
00882                                 case DLG_STATE_CONFIRMED:
00883                                         break;
00884                                 case DLG_STATE_DELETED:
00885                                         break;
00886                                 default:
00887                                         log_next_state_dlg(event, dlg);
00888                         }
00889                         break;
00890                 case DLG_EVENT_REQBYE:
00891                         switch (dlg->state) {
00892                                 case DLG_STATE_CONFIRMED_NA:
00893                                 case DLG_STATE_CONFIRMED:
00894                                         dlg->dflags |= DLG_FLAG_HASBYE;
00895                                         dlg->state = DLG_STATE_DELETED;
00896                                         *unref = 1;
00897                                         break;
00898                                 case DLG_STATE_EARLY:
00899                                 case DLG_STATE_DELETED:
00900                                         break;
00901                                 default:
00902                                         log_next_state_dlg(event, dlg);
00903                         }
00904                         break;
00905                 case DLG_EVENT_REQPRACK:
00906                         switch (dlg->state) {
00907                                 case DLG_STATE_EARLY:
00908                                 case DLG_STATE_CONFIRMED_NA:
00909                                 case DLG_STATE_DELETED:
00910                                         break;
00911                                 default:
00912                                         log_next_state_dlg(event, dlg);
00913                         }
00914                         break;
00915                 case DLG_EVENT_REQ:
00916                         switch (dlg->state) {
00917                                 case DLG_STATE_EARLY:
00918                                 case DLG_STATE_CONFIRMED_NA:
00919                                 case DLG_STATE_CONFIRMED:
00920                                 case DLG_STATE_DELETED:
00921                                         break;
00922                                 default:
00923                                         log_next_state_dlg(event, dlg);
00924                         }
00925                         break;
00926                 default:
00927                         LM_CRIT("unknown event %d in state %d "
00928                                 "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n",
00929                                 event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
00930                                 dlg->callid.len, dlg->callid.s,
00931                                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
00932                                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
00933         }
00934         *new_state = dlg->state;
00935 
00936         dlg_unlock( d_table, d_entry);
00937 
00938         LM_DBG("dialog %p changed from state %d to "
00939                 "state %d, due event %d (ref %d)\n", dlg, *old_state, *new_state, event,
00940                 dlg->ref);
00941 }
00942 
00946 int dlg_set_toroute(struct dlg_cell *dlg, str *route)
00947 {
00948         if(dlg==NULL || route==NULL || route->len<=0)
00949                 return 0;
00950         if(dlg->toroute_name.s!=NULL) {
00951                 shm_free(dlg->toroute_name.s);
00952                 dlg->toroute_name.s = NULL;
00953                 dlg->toroute_name.len = 0;
00954         }
00955         dlg->toroute_name.s = (char*)shm_malloc((route->len+1)*sizeof(char));
00956         if(dlg->toroute_name.s==NULL) {
00957                 LM_ERR("no more shared memory\n");
00958                 return -1;
00959         }
00960         memcpy(dlg->toroute_name.s, route->s, route->len);
00961         dlg->toroute_name.len = route->len;
00962         dlg->toroute_name.s[dlg->toroute_name.len] = '\0';
00963         dlg->toroute = route_lookup(&main_rt, dlg->toroute_name.s);
00964         return 0;
00965 }
00966 
00967 /**************************** MI functions ******************************/
00976 static inline int internal_mi_print_dlg(struct mi_node *rpl,
00977                                                                         struct dlg_cell *dlg, int with_context)
00978 {
00979         struct mi_node* node= NULL;
00980         struct mi_node* node1 = NULL;
00981         struct mi_attr* attr= NULL;
00982         int len;
00983         char* p;
00984 
00985         node = add_mi_node_child(rpl, 0, "dialog",6 , 0, 0 );
00986         if (node==0)
00987                 goto error;
00988 
00989         attr = addf_mi_attr( node, 0, "hash", 4, "%u:%u",
00990                         dlg->h_entry, dlg->h_id );
00991         if (attr==0)
00992                 goto error;
00993 
00994         p= int2str((unsigned long)dlg->state, &len);
00995         node1 = add_mi_node_child( node, MI_DUP_VALUE, "state", 5, p, len);
00996         if (node1==0)
00997                 goto error;
00998 
00999         p= int2str((unsigned long)dlg->ref, &len);
01000         node1 = add_mi_node_child( node, MI_DUP_VALUE, "ref_count", 9, p, len);
01001         if (node1==0)
01002                 goto error;
01003 
01004         p= int2str((unsigned long)dlg->start_ts, &len);
01005         node1 = add_mi_node_child(node,MI_DUP_VALUE,"timestart",9, p, len);
01006         if (node1==0)
01007                 goto error;
01008 
01009         p= int2str((unsigned long)dlg->tl.timeout, &len);
01010         node1 = add_mi_node_child(node,MI_DUP_VALUE, "timeout", 7, p, len);
01011         if (node1==0)
01012                 goto error;
01013 
01014         node1 = add_mi_node_child(node, MI_DUP_VALUE, "callid", 6,
01015                         dlg->callid.s, dlg->callid.len);
01016         if(node1 == 0)
01017                 goto error;
01018 
01019         node1 = add_mi_node_child(node, MI_DUP_VALUE, "from_uri", 8,
01020                         dlg->from_uri.s, dlg->from_uri.len);
01021         if(node1 == 0)
01022                 goto error;
01023 
01024         node1 = add_mi_node_child(node, MI_DUP_VALUE, "from_tag", 8,
01025                         dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLER_LEG].len);
01026         if(node1 == 0)
01027                 goto error;
01028 
01029         node1 = add_mi_node_child(node, MI_DUP_VALUE, "caller_contact", 14,
01030                         dlg->contact[DLG_CALLER_LEG].s,
01031                         dlg->contact[DLG_CALLER_LEG].len);
01032         if(node1 == 0)
01033                 goto error;
01034 
01035         node1 = add_mi_node_child(node, MI_DUP_VALUE, "caller_cseq", 11,
01036                         dlg->cseq[DLG_CALLER_LEG].s,
01037                         dlg->cseq[DLG_CALLER_LEG].len);
01038         if(node1 == 0)
01039                 goto error;
01040 
01041         node1 = add_mi_node_child(node, MI_DUP_VALUE,"caller_route_set",16,
01042                         dlg->route_set[DLG_CALLER_LEG].s,
01043                         dlg->route_set[DLG_CALLER_LEG].len);
01044         if(node1 == 0)
01045                 goto error;
01046 
01047         if (dlg->bind_addr[DLG_CALLER_LEG]) {
01048                 node1 = add_mi_node_child(node, 0,
01049                         "caller_bind_addr",16,
01050                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s,
01051                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len);
01052         } else {
01053                 node1 = add_mi_node_child(node, 0,
01054                         "caller_bind_addr",16,0,0);
01055         }
01056 
01057         if (dlg->bind_addr[DLG_CALLEE_LEG]) {
01058                 node1 = add_mi_node_child(node, 0,
01059                         "callee_bind_addr",16,
01060                         dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s,
01061                         dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len);
01062         } else {
01063                 node1 = add_mi_node_child(node, 0,
01064                         "callee_bind_addr",16,0,0);
01065         }
01066 
01067         node1 = add_mi_node_child(node, MI_DUP_VALUE, "to_uri", 6,
01068                         dlg->to_uri.s, dlg->to_uri.len);
01069         if(node1 == 0)
01070                 goto error;
01071 
01072         node1 = add_mi_node_child(node, MI_DUP_VALUE, "to_tag", 6,
01073                         dlg->tag[DLG_CALLEE_LEG].s, dlg->tag[DLG_CALLEE_LEG].len);
01074         if(node1 == 0)
01075                 goto error;
01076 
01077         node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_contact", 14,
01078                         dlg->contact[DLG_CALLEE_LEG].s,
01079                         dlg->contact[DLG_CALLEE_LEG].len);
01080         if(node1 == 0)
01081                 goto error;
01082 
01083         node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_cseq", 11,
01084                         dlg->cseq[DLG_CALLEE_LEG].s,
01085                         dlg->cseq[DLG_CALLEE_LEG].len);
01086         if(node1 == 0)
01087                 goto error;
01088 
01089         node1 = add_mi_node_child(node, MI_DUP_VALUE,"callee_route_set",16,
01090                         dlg->route_set[DLG_CALLEE_LEG].s,
01091                         dlg->route_set[DLG_CALLEE_LEG].len);
01092         if(node1 == 0)
01093                 goto error;
01094 
01095         if (with_context) {
01096                 node1 = add_mi_node_child(node, 0, "context", 7, 0, 0);
01097                 if(node1 == 0)
01098                         goto error;
01099                 run_dlg_callbacks( DLGCB_MI_CONTEXT,
01100                                    dlg,
01101                                    NULL,
01102                                    NULL,
01103                                    DLG_DIR_NONE,
01104                                    (void *)node1);
01105         }
01106         return 0;
01107 
01108 error:
01109         LM_ERR("failed to add node\n");
01110         return -1;
01111 }
01112 
01113 
01121 int mi_print_dlg(struct mi_node *rpl, struct dlg_cell *dlg, int with_context)
01122 {
01123         return internal_mi_print_dlg( rpl, dlg, with_context);
01124 }
01125 
01133 static int internal_mi_print_dlgs(struct mi_node *rpl, int with_context)
01134 {
01135         struct dlg_cell *dlg;
01136         unsigned int i;
01137 
01138         LM_DBG("printing %i dialogs\n", d_table->size);
01139 
01140         for( i=0 ; i<d_table->size ; i++ ) {
01141                 dlg_lock( d_table, &(d_table->entries[i]) );
01142 
01143                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
01144                         if (internal_mi_print_dlg(rpl, dlg, with_context)!=0)
01145                                 goto error;
01146                 }
01147                 dlg_unlock( d_table, &(d_table->entries[i]) );
01148         }
01149         return 0;
01150 
01151 error:
01152         dlg_unlock( d_table, &(d_table->entries[i]) );
01153         LM_ERR("failed to print dialog\n");
01154         return -1;
01155 }
01156 
01157 
01158 static inline struct mi_root* process_mi_params(struct mi_root *cmd_tree,
01159                                                                                                         struct dlg_cell **dlg_p)
01160 {
01161         struct mi_node* node;
01162         struct dlg_entry *d_entry;
01163         struct dlg_cell *dlg;
01164         str *callid;
01165         str *from_tag;
01166         unsigned int h_entry;
01167 
01168         node = cmd_tree->node.kids;
01169         if (node == NULL) {
01170                 /* no parameters at all */
01171                 *dlg_p = NULL;
01172                 return NULL;
01173         }
01174 
01175         /* we have params -> get callid and fromtag */
01176         callid = &node->value;
01177         LM_DBG("callid='%.*s'\n", callid->len, callid->s);
01178 
01179         node = node->next;
01180         if ( !node || !node->value.s || !node->value.len) {
01181                 from_tag = NULL;
01182         } else {
01183                 from_tag = &node->value;
01184                 LM_DBG("from_tag='%.*s'\n", from_tag->len, from_tag->s);
01185                 if ( node->next!=NULL )
01186                         return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
01187         }
01188 
01189         h_entry = core_hash( callid, 0, d_table->size);
01190 
01191         d_entry = &(d_table->entries[h_entry]);
01192         dlg_lock( d_table, d_entry);
01193 
01194         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
01195                 if (match_downstream_dialog( dlg, callid, from_tag)==1) {
01196                         if (dlg->state==DLG_STATE_DELETED) {
01197                                 *dlg_p = NULL;
01198                                 break;
01199                         } else {
01200                                 *dlg_p = dlg;
01201                                 dlg_unlock( d_table, d_entry);
01202                                 return 0;
01203                         }
01204                 }
01205         }
01206         dlg_unlock( d_table, d_entry);
01207 
01208         return init_mi_tree( 404, MI_SSTR("Nu such dialog"));
01209 }
01210 
01211 
01218 struct mi_root * mi_print_dlgs(struct mi_root *cmd_tree, void *param )
01219 {
01220         struct mi_root* rpl_tree= NULL;
01221         struct mi_node* rpl = NULL;
01222         struct dlg_cell* dlg = NULL;
01223 
01224         rpl_tree = process_mi_params( cmd_tree, &dlg);
01225         if (rpl_tree)
01226                 /* param error */
01227                 return rpl_tree;
01228 
01229         rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
01230         if (rpl_tree==0)
01231                 return 0;
01232         rpl = &rpl_tree->node;
01233 
01234         if (dlg==NULL) {
01235                 if ( internal_mi_print_dlgs(rpl,0)!=0 )
01236                         goto error;
01237         } else {
01238                 if ( internal_mi_print_dlg(rpl,dlg,0)!=0 )
01239                         goto error;
01240         }
01241 
01242         return rpl_tree;
01243 error:
01244         free_mi_tree(rpl_tree);
01245         return NULL;
01246 }
01247 
01248 
01255 struct mi_root * mi_print_dlgs_ctx(struct mi_root *cmd_tree, void *param )
01256 {
01257         struct mi_root* rpl_tree= NULL;
01258         struct mi_node* rpl = NULL;
01259         struct dlg_cell* dlg = NULL;
01260 
01261         rpl_tree = process_mi_params( cmd_tree, &dlg);
01262         if (rpl_tree)
01263                 /* param error */
01264                 return rpl_tree;
01265 
01266         rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
01267         if (rpl_tree==0)
01268                 return 0;
01269         rpl = &rpl_tree->node;
01270 
01271         if (dlg==NULL) {
01272                 if ( internal_mi_print_dlgs(rpl,1)!=0 )
01273                         goto error;
01274         } else {
01275                 if ( internal_mi_print_dlg(rpl,dlg,1)!=0 )
01276                         goto error;
01277         }
01278 
01279         return rpl_tree;
01280 error:
01281         free_mi_tree(rpl_tree);
01282         return NULL;
01283 }
01284 
01291 struct mi_root * mi_terminate_dlgs(struct mi_root *cmd_tree, void *param )
01292 {
01293         struct mi_root* rpl_tree= NULL;
01294         struct dlg_cell* dlg = NULL;
01295         str headers = {0, 0};
01296 
01297         rpl_tree = process_mi_params( cmd_tree, &dlg);
01298         if (rpl_tree)
01299                 /* param error */
01300                 return rpl_tree;
01301         if (dlg==NULL)
01302                 return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
01303 
01304         rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
01305         if (rpl_tree==0)
01306                 return 0;
01307         if (dlg_bye_all(dlg, &headers)!=0)
01308                 goto error;
01309         return rpl_tree;
01310 error:
01311         free_mi_tree(rpl_tree);
01312         return NULL;
01313 }
01314 
01315