dialog: avoid realloc of memory for cseq when setting leg info
[sip-router] / modules / dialog / dlg_hash.c
1 /*
2  * Copyright (C) 2006 Voice System SRL
3  * Copyright (C) 2011 Carsten Bock, carsten@ng-voice.com
4  *
5  * This file is part of Kamailio, a free SIP server.
6  *
7  * Kamailio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version
11  *
12  * Kamailio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License 
18  * along with this program; if not, write to the Free Software 
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * History:
22  * --------
23  * 2006-04-14  initial version (bogdan)
24  * 2007-03-06  syncronized state machine added for dialog state. New tranzition
25  *             design based on events; removed num_1xx and num_2xx (bogdan)
26  * 2007-04-30  added dialog matching without DID (dialog ID), but based only
27  *             on RFC3261 elements - based on an original patch submitted 
28  *             by Michel Bensoussan <michel@extricom.com> (bogdan)
29  * 2007-07-06  additional information stored in order to save it in the db:
30  *             cseq, route_set, contact and sock_info for both caller and 
31  *             callee (ancuta)
32  * 2007-07-10  Optimized dlg_match_mode 2 (DID_NONE), it now employs a proper
33  *             hash table lookup and isn't dependant on the is_direction 
34  *             function (which requires an RR param like dlg_match_mode 0 
35  *             anyways.. ;) ; based on a patch from 
36  *             Tavis Paquette <tavis@galaxytelecom.net> 
37  *             and Peter Baer <pbaer@galaxytelecom.net>  (bogdan)
38  * 2008-04-17  added new type of callback to be triggered right before the
39  *              dialog is destroyed (deleted from memory) (bogdan)
40  * 2008-04-17  added new dialog flag to avoid state tranzitions from DELETED to
41  *             CONFIRMED_NA due delayed "200 OK" (bogdan)
42  */
43
44
45 /*!
46  * \file
47  * \brief Functions related to dialog creation and searching
48  * \ingroup dialog
49  * Module: \ref dialog
50  */
51
52 #include <stdlib.h>
53 #include <string.h>
54
55 #include "../../dprint.h"
56 #include "../../ut.h"
57 #include "../../hashes.h"
58 #include "../../lib/kmi/mi.h"
59 #include "dlg_timer.h"
60 #include "dlg_var.h"
61 #include "dlg_hash.h"
62 #include "dlg_profile.h"
63 #include "dlg_req_within.h"
64 #include "dlg_db_handler.h"
65
66 #define MAX_LDG_LOCKS  2048
67 #define MIN_LDG_LOCKS  2
68
69 extern int dlg_ka_interval;
70
71 /*! global dialog table */
72 struct dlg_table *d_table = 0;
73
74 dlg_ka_t **dlg_ka_list_head = NULL;
75 dlg_ka_t **dlg_ka_list_tail = NULL;
76 gen_lock_t *dlg_ka_list_lock = NULL;
77
78 /*!
79  * \brief Reference a dialog without locking
80  * \param _dlg dialog
81  * \param _cnt increment for the reference counter
82  */
83 #define ref_dlg_unsafe(_dlg,_cnt)     \
84         do { \
85                 (_dlg)->ref += (_cnt); \
86                 LM_DBG("ref dlg %p with %d -> %d\n", \
87                         (_dlg),(_cnt),(_dlg)->ref); \
88         }while(0)
89
90
91 /*!
92  * \brief Unreference a dialog without locking
93  * \param _dlg dialog
94  * \param _cnt decrement for the reference counter
95  * \param _d_entry dialog entry
96  */
97 #define unref_dlg_unsafe(_dlg,_cnt,_d_entry)   \
98         do { \
99                 if((_dlg)->ref <= 0 ) { \
100                         LM_WARN("invalid unref'ing dlg %p with ref %d by %d\n",\
101                                         (_dlg),(_dlg)->ref,(_cnt));\
102                         break; \
103                 } \
104                 (_dlg)->ref -= (_cnt); \
105                 LM_DBG("unref dlg %p with %d -> %d\n",\
106                         (_dlg),(_cnt),(_dlg)->ref);\
107                 if ((_dlg)->ref<0) {\
108                         LM_CRIT("bogus ref %d with cnt %d for dlg %p [%u:%u] "\
109                                 "with clid '%.*s' and tags '%.*s' '%.*s'\n",\
110                                 (_dlg)->ref, _cnt, _dlg,\
111                                 (_dlg)->h_entry, (_dlg)->h_id,\
112                                 (_dlg)->callid.len, (_dlg)->callid.s,\
113                                 (_dlg)->tag[DLG_CALLER_LEG].len,\
114                                 (_dlg)->tag[DLG_CALLER_LEG].s,\
115                                 (_dlg)->tag[DLG_CALLEE_LEG].len,\
116                                 (_dlg)->tag[DLG_CALLEE_LEG].s); \
117                 }\
118                 if ((_dlg)->ref<=0) { \
119                         unlink_unsafe_dlg( _d_entry, _dlg);\
120                         LM_DBG("ref <=0 for dialog %p\n",_dlg);\
121                         destroy_dlg(_dlg);\
122                 }\
123         }while(0)
124
125 /**
126  * add item to keep-alive list
127  *
128  */
129 int dlg_ka_add(dlg_cell_t *dlg)
130 {
131         dlg_ka_t *dka;
132
133         if(dlg_ka_interval<=0)
134                 return 0;
135         if(!(dlg->iflags & (DLG_IFLAG_KA_SRC | DLG_IFLAG_KA_SRC)))
136                 return 0;
137
138         dka = (dlg_ka_t*)shm_malloc(sizeof(dlg_ka_t));
139         if(dka==NULL) {
140                 LM_ERR("no more shm mem\n");
141                 return -1;
142         }
143         memset(dka, 0, sizeof(dlg_ka_t));
144         dka->katime = get_ticks() + dlg_ka_interval;
145         dka->iuid.h_entry = dlg->h_entry;
146         dka->iuid.h_id = dlg->h_id;
147         dka->iflags = dlg->iflags;
148
149         lock_get(dlg_ka_list_lock);
150         if(*dlg_ka_list_tail!=NULL)
151                 (*dlg_ka_list_tail)->next = dka;
152         if(*dlg_ka_list_head==NULL)
153                 *dlg_ka_list_head = dka;
154         *dlg_ka_list_tail = dka;
155         lock_release(dlg_ka_list_lock);
156         LM_DBG("added dlg[%d,%d] to KA list\n", dlg->h_entry, dlg->h_id);
157         return 0;
158 }
159
160 /**
161  * run keep-alive list
162  *
163  */
164 int dlg_ka_run(ticks_t ti)
165 {
166         dlg_ka_t *dka;
167         dlg_cell_t *dlg;
168
169         if(dlg_ka_interval<=0)
170                 return 0;
171
172         while(1) {
173                 /* get head item */
174                 lock_get(dlg_ka_list_lock);
175                 if(*dlg_ka_list_head==NULL) {
176                         lock_release(dlg_ka_list_lock);
177                         return 0;
178                 }
179                 dka = *dlg_ka_list_head;
180 #if 0
181                 LM_DBG("dlg ka timer at %lu for"
182                                 " dlg[%u,%u] on %lu\n", (unsigned long)ti,
183                                 dka->iuid.h_entry, dka->iuid.h_id,
184                                 (unsigned long)dka->katime);
185 #endif
186                 if(dka->katime>ti) {
187                         lock_release(dlg_ka_list_lock);
188                         return 0;
189                 }
190                 if(*dlg_ka_list_head == *dlg_ka_list_tail) {
191                         *dlg_ka_list_head = NULL;
192                         *dlg_ka_list_tail = NULL;
193                 }
194                 *dlg_ka_list_head = dka->next;
195                 lock_release(dlg_ka_list_lock);
196
197                 /* send keep-alive for dka */
198                 dlg = dlg_get_by_iuid(&dka->iuid);
199                 if(dlg==NULL) {
200                         shm_free(dka);
201                         dka = NULL;
202                 } else {
203                         if(dka->iflags & DLG_IFLAG_KA_SRC)
204                                 dlg_send_ka(dlg, DLG_CALLER_LEG, 0);
205                         if(dka->iflags & DLG_IFLAG_KA_DST)
206                                 dlg_send_ka(dlg, DLG_CALLEE_LEG, 0);
207                         dlg_release(dlg);
208                 }
209                 /* append to tail */
210                 if(dka!=NULL)
211                 {
212                         dka->katime = ti + dlg_ka_interval;
213                         lock_get(dlg_ka_list_lock);
214                         if(*dlg_ka_list_tail!=NULL)
215                                 (*dlg_ka_list_tail)->next = dka;
216                         if(*dlg_ka_list_head==NULL)
217                                 *dlg_ka_list_head = dka;
218                         *dlg_ka_list_tail = dka;
219                         lock_release(dlg_ka_list_lock);
220                 }
221         }
222
223         return 0;
224 }
225
226 /*!
227  * \brief Initialize the global dialog table
228  * \param size size of the table
229  * \return 0 on success, -1 on failure
230  */
231 int init_dlg_table(unsigned int size)
232 {
233         unsigned int n;
234         unsigned int i;
235
236         dlg_ka_list_head = (dlg_ka_t **)shm_malloc(sizeof(dlg_ka_t *));
237         if(dlg_ka_list_head==NULL) {
238                 LM_ERR("no more shm mem (h)\n");
239                 goto error0;
240         }
241         dlg_ka_list_tail = (dlg_ka_t **)shm_malloc(sizeof(dlg_ka_t *));
242         if(dlg_ka_list_tail==NULL) {
243                 LM_ERR("no more shm mem (t)\n");
244                 goto error0;
245         }
246         *dlg_ka_list_head = NULL;
247         *dlg_ka_list_tail = NULL;
248         dlg_ka_list_lock = (gen_lock_t*)shm_malloc(sizeof(gen_lock_t));
249         if(dlg_ka_list_lock==NULL) {
250                 LM_ERR("no more shm mem (l)\n");
251                 goto error0;
252         }
253         lock_init(dlg_ka_list_lock);
254
255         d_table = (struct dlg_table*)shm_malloc
256                 ( sizeof(struct dlg_table) + size*sizeof(struct dlg_entry));
257         if (d_table==0) {
258                 LM_ERR("no more shm mem (1)\n");
259                 goto error0;
260         }
261
262         memset( d_table, 0, sizeof(struct dlg_table) );
263         d_table->size = size;
264         d_table->entries = (struct dlg_entry*)(d_table+1);
265
266         n = (size<MAX_LDG_LOCKS)?size:MAX_LDG_LOCKS;
267         for(  ; n>=MIN_LDG_LOCKS ; n-- ) {
268                 d_table->locks = lock_set_alloc(n);
269                 if (d_table->locks==0)
270                         continue;
271                 if (lock_set_init(d_table->locks)==0) {
272                         lock_set_dealloc(d_table->locks);
273                         d_table->locks = 0;
274                         continue;
275                 }
276                 d_table->locks_no = n;
277                 break;
278         }
279
280         if (d_table->locks==0) {
281                 LM_ERR("unable to allocted at least %d locks for the hash table\n",
282                         MIN_LDG_LOCKS);
283                 goto error1;
284         }
285
286         for( i=0 ; i<size; i++ ) {
287                 memset( &(d_table->entries[i]), 0, sizeof(struct dlg_entry) );
288                 d_table->entries[i].next_id = rand() % (3*size);
289                 d_table->entries[i].lock_idx = i % d_table->locks_no;
290         }
291
292         return 0;
293 error1:
294         shm_free( d_table );
295         d_table = NULL;
296 error0:
297         if(dlg_ka_list_head!=NULL)
298                 shm_free(dlg_ka_list_head);
299         if(dlg_ka_list_tail!=NULL)
300                 shm_free(dlg_ka_list_tail);
301         dlg_ka_list_head = NULL;
302         dlg_ka_list_tail = NULL;
303         return -1;
304 }
305
306
307 /*!
308  * \brief Destroy a dialog, run callbacks and free memory
309  * \param dlg destroyed dialog
310  */
311 inline void destroy_dlg(struct dlg_cell *dlg)
312 {
313         int ret = 0;
314         struct dlg_var *var;
315
316         LM_DBG("destroying dialog %p (ref %d)\n", dlg, dlg->ref);
317
318         ret = remove_dialog_timer(&dlg->tl);
319         if (ret < 0) {
320                 LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
321                         "with clid '%.*s' and tags '%.*s' '%.*s'\n",
322                         dlg, dlg->h_entry, dlg->h_id,
323                         dlg->callid.len, dlg->callid.s,
324                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
325                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
326         } else if (ret > 0) {
327                 LM_DBG("removed timer for dlg %p [%u:%u] "
328                         "with clid '%.*s' and tags '%.*s' '%.*s'\n",
329                         dlg, dlg->h_entry, dlg->h_id,
330                         dlg->callid.len, dlg->callid.s,
331                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
332                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
333         }
334
335         run_dlg_callbacks( DLGCB_DESTROY , dlg, NULL, NULL, DLG_DIR_NONE, 0);
336
337
338         /* delete the dialog from DB*/
339         if (dlg_db_mode)
340                 remove_dialog_from_db(dlg);
341
342         if (dlg->cbs.first)
343                 destroy_dlg_callbacks_list(dlg->cbs.first);
344
345         if (dlg->profile_links)
346                 destroy_linkers(dlg->profile_links);
347
348         if (dlg->tag[DLG_CALLER_LEG].s)
349                 shm_free(dlg->tag[DLG_CALLER_LEG].s);
350
351         if (dlg->tag[DLG_CALLEE_LEG].s)
352                 shm_free(dlg->tag[DLG_CALLEE_LEG].s);
353
354         if (dlg->cseq[DLG_CALLER_LEG].s)
355                 shm_free(dlg->cseq[DLG_CALLER_LEG].s);
356
357         if (dlg->cseq[DLG_CALLEE_LEG].s)
358                 shm_free(dlg->cseq[DLG_CALLEE_LEG].s);
359
360         if (dlg->toroute_name.s)
361                 shm_free(dlg->toroute_name.s);
362
363         
364         while (dlg->vars) {
365                 var = dlg->vars;
366                 dlg->vars = dlg->vars->next;
367                 shm_free(var->key.s);
368                 shm_free(var->value.s);
369                 shm_free(var);
370         }
371
372
373         shm_free(dlg);
374         dlg = 0;
375 }
376
377
378 /*!
379  * \brief Destroy the global dialog table
380  */
381 void destroy_dlg_table(void)
382 {
383         struct dlg_cell *dlg, *l_dlg;
384         unsigned int i;
385
386         if (d_table==0)
387                 return;
388
389         if (d_table->locks) {
390                 lock_set_destroy(d_table->locks);
391                 lock_set_dealloc(d_table->locks);
392         }
393
394         for( i=0 ; i<d_table->size; i++ ) {
395                 dlg = d_table->entries[i].first;
396                 while (dlg) {
397                         l_dlg = dlg;
398                         dlg = dlg->next;
399                         destroy_dlg(l_dlg);
400                 }
401
402         }
403
404         shm_free(d_table);
405         d_table = 0;
406
407         return;
408 }
409
410
411 /*!
412  * \brief Create a new dialog structure for a SIP dialog
413  * \param callid dialog callid
414  * \param from_uri dialog from uri
415  * \param to_uri dialog to uri
416  * \param from_tag dialog from tag
417  * \param req_uri dialog r-uri
418  * \return created dialog structure on success, NULL otherwise
419  */
420 struct dlg_cell* build_new_dlg( str *callid, str *from_uri, str *to_uri,
421                 str *from_tag, str *req_uri)
422 {
423         struct dlg_cell *dlg;
424         int len;
425         char *p;
426
427         len = sizeof(struct dlg_cell) + callid->len + from_uri->len +
428                 to_uri->len + req_uri->len;
429         dlg = (struct dlg_cell*)shm_malloc( len );
430         if (dlg==0) {
431                 LM_ERR("no more shm mem (%d)\n",len);
432                 return 0;
433         }
434
435         memset( dlg, 0, len);
436         dlg->state = DLG_STATE_UNCONFIRMED;
437
438         dlg->h_entry = core_hash( callid, 0, d_table->size);
439         LM_DBG("new dialog on hash %u\n",dlg->h_entry);
440
441         p = (char*)(dlg+1);
442
443         dlg->callid.s = p;
444         dlg->callid.len = callid->len;
445         memcpy( p, callid->s, callid->len);
446         p += callid->len;
447
448         dlg->from_uri.s = p;
449         dlg->from_uri.len = from_uri->len;
450         memcpy( p, from_uri->s, from_uri->len);
451         p += from_uri->len;
452
453         dlg->to_uri.s = p;
454         dlg->to_uri.len = to_uri->len;
455         memcpy( p, to_uri->s, to_uri->len);
456         p += to_uri->len; 
457
458         dlg->req_uri.s = p;
459         dlg->req_uri.len = req_uri->len;
460         memcpy( p, req_uri->s, req_uri->len);
461         p += req_uri->len;
462
463         if ( p!=(((char*)dlg)+len) ) {
464                 LM_CRIT("buffer overflow\n");
465                 shm_free(dlg);
466                 return 0;
467         }
468
469         return dlg;
470 }
471
472
473 /*!
474  * \brief Set the leg information for an existing dialog
475  * \param dlg dialog
476  * \param tag from tag or to tag
477  * \param rr record-routing information
478  * \param contact caller or callee contact
479  * \param cseq CSEQ of caller or callee
480  * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
481  * \return 0 on success, -1 on failure
482  */
483 int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
484                                         str *cseq, unsigned int leg)
485 {
486         char *p;
487
488         if(dlg->tag[leg].s)
489                 shm_free(dlg->tag[leg].s);
490         dlg->tag[leg].s = (char*)shm_malloc( tag->len + rr->len + contact->len );
491
492         if(dlg->cseq[leg].s) {
493                 if (dlg->cseq[leg].len < cseq->len) {
494                         shm_free(dlg->cseq[leg].s);
495                         dlg->cseq[leg].s = (char*)shm_malloc(cseq->len);
496                 }
497         } else {
498                 dlg->cseq[leg].s = (char*)shm_malloc( cseq->len );
499         }
500
501         if ( dlg->tag[leg].s==NULL || dlg->cseq[leg].s==NULL) {
502                 LM_ERR("no more shm mem\n");
503                 if (dlg->tag[leg].s)
504                 {
505                         shm_free(dlg->tag[leg].s);
506                         dlg->tag[leg].s = NULL;
507                 }
508                 if (dlg->cseq[leg].s)
509                 {
510                         shm_free(dlg->cseq[leg].s);
511                         dlg->cseq[leg].s = NULL;
512                 }
513                 return -1;
514         }
515         p = dlg->tag[leg].s;
516
517         /* tag */
518         dlg->tag[leg].len = tag->len;
519         memcpy( p, tag->s, tag->len);
520         p += tag->len;
521         /* contact */
522         dlg->contact[leg].s = p;
523         dlg->contact[leg].len = contact->len;
524         memcpy( p, contact->s, contact->len);
525         p += contact->len;
526         /* rr */
527         if (rr->len) {
528                 dlg->route_set[leg].s = p;
529                 dlg->route_set[leg].len = rr->len;
530                 memcpy( p, rr->s, rr->len);
531         }
532
533         /* cseq */
534         dlg->cseq[leg].len = cseq->len;
535         memcpy( dlg->cseq[leg].s, cseq->s, cseq->len);
536
537         return 0;
538 }
539
540
541 /*!
542  * \brief Update or set the CSEQ for an existing dialog
543  * \param dlg dialog
544  * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
545  * \param cseq CSEQ of caller or callee
546  * \return 0 on success, -1 on failure
547  */
548 int dlg_update_cseq(struct dlg_cell * dlg, unsigned int leg, str *cseq)
549 {
550         if ( dlg->cseq[leg].s ) {
551                 if (dlg->cseq[leg].len < cseq->len) {
552                         shm_free(dlg->cseq[leg].s);
553                         dlg->cseq[leg].s = (char*)shm_malloc(cseq->len);
554                         if (dlg->cseq[leg].s==NULL)
555                                 goto error;
556                 }
557         } else {
558                 dlg->cseq[leg].s = (char*)shm_malloc(cseq->len);
559                 if (dlg->cseq[leg].s==NULL)
560                         goto error;
561         }
562
563         memcpy( dlg->cseq[leg].s, cseq->s, cseq->len );
564         dlg->cseq[leg].len = cseq->len;
565
566         LM_DBG("cseq is %.*s\n", dlg->cseq[leg].len, dlg->cseq[leg].s);
567         return 0;
568 error:
569         LM_ERR("not more shm mem\n");
570         return -1;
571 }
572
573
574 /*!
575  * \brief Lookup a dialog in the global list
576  *
577  * Note that the caller is responsible for decrementing (or reusing)
578  * the reference counter by one again iff a dialog has been found.
579  * \param h_entry number of the hash table entry
580  * \param h_id id of the hash table entry
581  * \return dialog structure on success, NULL on failure
582  */
583 dlg_cell_t *dlg_lookup( unsigned int h_entry, unsigned int h_id)
584 {
585         dlg_cell_t *dlg;
586         dlg_entry_t *d_entry;
587
588         if(d_table==NULL)
589                 return 0;
590
591         if (h_entry>=d_table->size)
592                 goto not_found;
593
594         d_entry = &(d_table->entries[h_entry]);
595
596         dlg_lock( d_table, d_entry);
597
598         for( dlg=d_entry->first ; dlg ; dlg=dlg->next ) {
599                 if (dlg->h_id == h_id) {
600                         ref_dlg_unsafe(dlg, 1);
601                         dlg_unlock( d_table, d_entry);
602                         LM_DBG("dialog id=%u found on entry %u\n", h_id, h_entry);
603                         return dlg;
604                 }
605         }
606
607         dlg_unlock( d_table, d_entry);
608 not_found:
609         LM_DBG("no dialog id=%u found on entry %u\n", h_id, h_entry);
610         return 0;
611 }
612
613
614 /*!
615  * \brief Search a dialog in the global list by iuid
616  *
617  * Note that the caller is responsible for decrementing (or reusing)
618  * the reference counter by one again if a dialog has been found.
619  * \param diuid internal unique id per dialog
620  * \return dialog structure on success, NULL on failure
621  */
622 dlg_cell_t* dlg_get_by_iuid(dlg_iuid_t *diuid)
623 {
624         if(diuid==NULL)
625                 return NULL;
626         if(diuid->h_id==0)
627                 return NULL;
628         /* dlg ref counter is increased by next line */
629         return dlg_lookup(diuid->h_entry, diuid->h_id);
630 }
631
632 /*!
633  * \brief Helper function to get a dialog corresponding to a SIP message
634  * \see get_dlg
635  * \param h_entry hash index in the directory list
636  * \param callid callid
637  * \param ftag from tag
638  * \param ttag to tag
639  * \param dir direction
640  * \return dialog structure on success, NULL on failure
641  */
642 static inline struct dlg_cell* internal_get_dlg(unsigned int h_entry,
643                                                 str *callid, str *ftag, str *ttag, unsigned int *dir)
644 {
645         struct dlg_cell *dlg;
646         struct dlg_entry *d_entry;
647
648         d_entry = &(d_table->entries[h_entry]);
649
650         dlg_lock( d_table, d_entry);
651
652         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
653                 /* Check callid / fromtag / totag */
654                 if (match_dialog( dlg, callid, ftag, ttag, dir)==1) {
655                         ref_dlg_unsafe(dlg, 1);
656                         dlg_unlock( d_table, d_entry);
657                         LM_DBG("dialog callid='%.*s' found\n on entry %u, dir=%d\n",
658                                 callid->len, callid->s,h_entry,*dir);
659                         return dlg;
660                 }
661         }
662
663         dlg_unlock( d_table, d_entry);
664         LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
665         return 0;
666 }
667
668
669
670 /*!
671  * \brief Get dialog that correspond to CallId, From Tag and To Tag
672  *
673  * Get dialog that correspond to CallId, From Tag and To Tag.
674  * See RFC 3261, paragraph 4. Overview of Operation:                 
675  * "The combination of the To tag, From tag, and Call-ID completely  
676  * defines a peer-to-peer SIP relationship between [two UAs] and is 
677  * referred to as a dialog."
678  * Note that the caller is responsible for decrementing (or reusing)
679  * the reference counter by one again iff a dialog has been found.
680  * \param callid callid
681  * \param ftag from tag
682  * \param ttag to tag
683  * \param dir direction
684  * \return dialog structure on success, NULL on failure
685  */
686 struct dlg_cell* get_dlg( str *callid, str *ftag, str *ttag, unsigned int *dir)
687 {
688         struct dlg_cell *dlg;
689         unsigned int he;
690
691         he = core_hash(callid, 0, d_table->size);
692         dlg = internal_get_dlg(he, callid, ftag, ttag, dir);
693
694         if (dlg == 0) {
695                 LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
696                 return 0;
697         }
698         return dlg;
699 }
700
701
702 /*!
703  * \brief Link a dialog structure
704  * \param dlg dialog
705  * \param n extra increments for the reference counter
706  */
707 void link_dlg(struct dlg_cell *dlg, int n)
708 {
709         struct dlg_entry *d_entry;
710
711         d_entry = &(d_table->entries[dlg->h_entry]);
712
713         dlg_lock( d_table, d_entry);
714
715         /* keep id 0 for special cases */
716         dlg->h_id = 1 + d_entry->next_id++;
717         if(dlg->h_id == 0) dlg->h_id = 1;
718         LM_DBG("linking dialog [%u:%u]\n", dlg->h_entry, dlg->h_id);
719         if (d_entry->first==0) {
720                 d_entry->first = d_entry->last = dlg;
721         } else {
722                 d_entry->last->next = dlg;
723                 dlg->prev = d_entry->last;
724                 d_entry->last = dlg;
725         }
726
727         ref_dlg_unsafe(dlg, 1+n);
728
729         dlg_unlock( d_table, d_entry);
730         return;
731 }
732
733
734 /*!
735  * \brief Refefence a dialog with locking
736  * \see ref_dlg_unsafe
737  * \param dlg dialog
738  * \param cnt increment for the reference counter
739  */
740 void dlg_ref(dlg_cell_t *dlg, unsigned int cnt)
741 {
742         dlg_entry_t *d_entry;
743
744         d_entry = &(d_table->entries[dlg->h_entry]);
745
746         dlg_lock( d_table, d_entry);
747         ref_dlg_unsafe( dlg, cnt);
748         dlg_unlock( d_table, d_entry);
749 }
750
751
752 /*!
753  * \brief Unreference a dialog with locking
754  * \see unref_dlg_unsafe
755  * \param dlg dialog
756  * \param cnt decrement for the reference counter
757  */
758 void dlg_unref(dlg_cell_t *dlg, unsigned int cnt)
759 {
760         dlg_entry_t *d_entry;
761
762         d_entry = &(d_table->entries[dlg->h_entry]);
763
764         dlg_lock( d_table, d_entry);
765         unref_dlg_unsafe( dlg, cnt, d_entry);
766         dlg_unlock( d_table, d_entry);
767 }
768
769
770 /*!
771  * \brief Release a dialog from ref counter by 1
772  * \see dlg_unref
773  * \param dlg dialog
774  */
775 void dlg_release(dlg_cell_t *dlg)
776 {
777         if(dlg==NULL)
778                 return;
779         dlg_unref(dlg, 1);
780 }
781
782
783 /*!
784  * \brief Small logging helper functions for next_state_dlg.
785  * \param event logged event
786  * \param dlg dialog data
787  * \see next_state_dlg
788  */
789 static inline void log_next_state_dlg(const int event, const struct dlg_cell *dlg) {
790         LM_CRIT("bogus event %d in state %d for dlg %p [%u:%u] with clid '%.*s' and tags "
791                 "'%.*s' '%.*s'\n", event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
792                 dlg->callid.len, dlg->callid.s,
793                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
794                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
795 }
796
797
798 /*!
799  * \brief Update a dialog state according a event and the old state
800  *
801  * This functions implement the main state machine that update a dialog
802  * state according a processed event and the current state. If necessary
803  * it will delete the processed dialog. The old and new state are also
804  * saved for reference.
805  * \param dlg updated dialog
806  * \param event current event
807  * \param old_state old dialog state
808  * \param new_state new dialog state
809  * \param unref set to 1 when the dialog was deleted, 0 otherwise
810  */
811 void next_state_dlg(dlg_cell_t *dlg, int event,
812                 int *old_state, int *new_state, int *unref)
813 {
814         dlg_entry_t *d_entry;
815
816         d_entry = &(d_table->entries[dlg->h_entry]);
817
818         *unref = 0;
819
820         dlg_lock( d_table, d_entry);
821
822         *old_state = dlg->state;
823
824         switch (event) {
825                 case DLG_EVENT_TDEL:
826                         switch (dlg->state) {
827                                 case DLG_STATE_UNCONFIRMED:
828                                 case DLG_STATE_EARLY:
829                                         dlg->state = DLG_STATE_DELETED;
830                                         unref_dlg_unsafe(dlg,1,d_entry);
831                                         *unref = 1;
832                                         break;
833                                 case DLG_STATE_CONFIRMED_NA:
834                                 case DLG_STATE_CONFIRMED:
835                                         unref_dlg_unsafe(dlg,1,d_entry);
836                                         break;
837                                 case DLG_STATE_DELETED:
838                                         *unref = 1;
839                                         break;
840                                 default:
841                                         log_next_state_dlg(event, dlg);
842                         }
843                         break;
844                 case DLG_EVENT_RPL1xx:
845                         switch (dlg->state) {
846                                 case DLG_STATE_UNCONFIRMED:
847                                 case DLG_STATE_EARLY:
848                                         dlg->state = DLG_STATE_EARLY;
849                                         break;
850                                 default:
851                                         log_next_state_dlg(event, dlg);
852                         }
853                         break;
854                 case DLG_EVENT_RPL3xx:
855                         switch (dlg->state) {
856                                 case DLG_STATE_UNCONFIRMED:
857                                 case DLG_STATE_EARLY:
858                                         dlg->state = DLG_STATE_DELETED;
859                                         *unref = 1;
860                                         break;
861                                 default:
862                                         log_next_state_dlg(event, dlg);
863                         }
864                         break;
865                 case DLG_EVENT_RPL2xx:
866                         switch (dlg->state) {
867                                 case DLG_STATE_DELETED:
868                                         if (dlg->dflags&DLG_FLAG_HASBYE) {
869                                                 LM_CRIT("bogus event %d in state %d (with BYE) "
870                                                         "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n",
871                                                         event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
872                                                         dlg->callid.len, dlg->callid.s,
873                                                         dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
874                                                         dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
875                                                 break;
876                                         }
877                                         ref_dlg_unsafe(dlg,1);
878                                 case DLG_STATE_UNCONFIRMED:
879                                 case DLG_STATE_EARLY:
880                                         dlg->state = DLG_STATE_CONFIRMED_NA;
881                                         break;
882                                 case DLG_STATE_CONFIRMED_NA:
883                                 case DLG_STATE_CONFIRMED:
884                                         break;
885                                 default:
886                                         log_next_state_dlg(event, dlg);
887                         }
888                         break;
889                 case DLG_EVENT_REQACK:
890                         switch (dlg->state) {
891                                 case DLG_STATE_CONFIRMED_NA:
892                                         dlg->state = DLG_STATE_CONFIRMED;
893                                         break;
894                                 case DLG_STATE_CONFIRMED:
895                                         break;
896                                 case DLG_STATE_DELETED:
897                                         break;
898                                 default:
899                                         log_next_state_dlg(event, dlg);
900                         }
901                         break;
902                 case DLG_EVENT_REQBYE:
903                         switch (dlg->state) {
904                                 case DLG_STATE_CONFIRMED_NA:
905                                 case DLG_STATE_CONFIRMED:
906                                         dlg->dflags |= DLG_FLAG_HASBYE;
907                                         dlg->state = DLG_STATE_DELETED;
908                                         *unref = 1;
909                                         break;
910                                 case DLG_STATE_EARLY:
911                                 case DLG_STATE_DELETED:
912                                         break;
913                                 default:
914                                         log_next_state_dlg(event, dlg);
915                         }
916                         break;
917                 case DLG_EVENT_REQPRACK:
918                         switch (dlg->state) {
919                                 case DLG_STATE_EARLY:
920                                 case DLG_STATE_CONFIRMED_NA:
921                                 case DLG_STATE_DELETED:
922                                         break;
923                                 default:
924                                         log_next_state_dlg(event, dlg);
925                         }
926                         break;
927                 case DLG_EVENT_REQ:
928                         switch (dlg->state) {
929                                 case DLG_STATE_EARLY:
930                                 case DLG_STATE_CONFIRMED_NA:
931                                 case DLG_STATE_CONFIRMED:
932                                 case DLG_STATE_DELETED:
933                                         break;
934                                 default:
935                                         log_next_state_dlg(event, dlg);
936                         }
937                         break;
938                 default:
939                         LM_CRIT("unknown event %d in state %d "
940                                 "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' '%.*s'\n",
941                                 event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
942                                 dlg->callid.len, dlg->callid.s,
943                                 dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
944                                 dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
945         }
946         *new_state = dlg->state;
947
948         dlg_unlock( d_table, d_entry);
949
950         LM_DBG("dialog %p changed from state %d to "
951                 "state %d, due event %d (ref %d)\n", dlg, *old_state, *new_state, event,
952                 dlg->ref);
953 }
954
955 /**
956  *
957  */
958 int dlg_set_toroute(struct dlg_cell *dlg, str *route)
959 {
960         if(dlg==NULL || route==NULL || route->len<=0)
961                 return 0;
962         if(dlg->toroute_name.s!=NULL) {
963                 shm_free(dlg->toroute_name.s);
964                 dlg->toroute_name.s = NULL;
965                 dlg->toroute_name.len = 0;
966         }
967         dlg->toroute_name.s = (char*)shm_malloc((route->len+1)*sizeof(char));
968         if(dlg->toroute_name.s==NULL) {
969                 LM_ERR("no more shared memory\n");
970                 return -1;
971         }
972         memcpy(dlg->toroute_name.s, route->s, route->len);
973         dlg->toroute_name.len = route->len;
974         dlg->toroute_name.s[dlg->toroute_name.len] = '\0';
975         dlg->toroute = route_lookup(&main_rt, dlg->toroute_name.s);
976         return 0;
977 }
978
979 /*
980  * Internal function to adjust the lifetime of a dialog, used by
981  * various userland functions that touch the dialog timeout.
982  */
983
984 int     update_dlg_timeout(dlg_cell_t *dlg, int timeout)
985 {
986         if(update_dlg_timer(&dlg->tl, timeout) < 0) {
987                 LM_ERR("failed to update dialog lifetime\n");
988                 dlg_release(dlg);
989                 return -1;
990         } 
991
992         dlg->lifetime = timeout;
993         dlg->dflags |= DLG_FLAG_CHANGED;
994
995         dlg_release(dlg);
996
997         return 0;
998 }
999
1000 /**************************** MI functions ******************************/
1001 /*!
1002  * \brief Helper method that output a dialog via the MI interface
1003  * \see mi_print_dlg
1004  * \param rpl MI node that should be filled
1005  * \param dlg printed dialog
1006  * \param with_context if 1 then the dialog context will be also printed
1007  * \return 0 on success, -1 on failure
1008  */
1009 static inline int internal_mi_print_dlg(struct mi_node *rpl,
1010                                                                         struct dlg_cell *dlg, int with_context)
1011 {
1012         struct mi_node* node= NULL;
1013         struct mi_node* node1 = NULL;
1014         struct mi_attr* attr= NULL;
1015         int len;
1016         char* p;
1017
1018         node = add_mi_node_child(rpl, 0, "dialog",6 , 0, 0 );
1019         if (node==0)
1020                 goto error;
1021
1022         attr = addf_mi_attr( node, 0, "hash", 4, "%u:%u",
1023                         dlg->h_entry, dlg->h_id );
1024         if (attr==0)
1025                 goto error;
1026
1027         p= int2str((unsigned long)dlg->state, &len);
1028         node1 = add_mi_node_child( node, MI_DUP_VALUE, "state", 5, p, len);
1029         if (node1==0)
1030                 goto error;
1031
1032         p= int2str((unsigned long)dlg->ref, &len);
1033         node1 = add_mi_node_child( node, MI_DUP_VALUE, "ref_count", 9, p, len);
1034         if (node1==0)
1035                 goto error;
1036
1037         p= int2str((unsigned long)dlg->start_ts, &len);
1038         node1 = add_mi_node_child(node,MI_DUP_VALUE,"timestart",9, p, len);
1039         if (node1==0)
1040                 goto error;
1041
1042         p= int2str((unsigned long)dlg->tl.timeout, &len);
1043         node1 = add_mi_node_child(node,MI_DUP_VALUE, "timeout", 7, p, len);
1044         if (node1==0)
1045                 goto error;
1046
1047         node1 = add_mi_node_child(node, MI_DUP_VALUE, "callid", 6,
1048                         dlg->callid.s, dlg->callid.len);
1049         if(node1 == 0)
1050                 goto error;
1051
1052         node1 = add_mi_node_child(node, MI_DUP_VALUE, "from_uri", 8,
1053                         dlg->from_uri.s, dlg->from_uri.len);
1054         if(node1 == 0)
1055                 goto error;
1056
1057         node1 = add_mi_node_child(node, MI_DUP_VALUE, "from_tag", 8,
1058                         dlg->tag[DLG_CALLER_LEG].s, dlg->tag[DLG_CALLER_LEG].len);
1059         if(node1 == 0)
1060                 goto error;
1061
1062         node1 = add_mi_node_child(node, MI_DUP_VALUE, "caller_contact", 14,
1063                         dlg->contact[DLG_CALLER_LEG].s,
1064                         dlg->contact[DLG_CALLER_LEG].len);
1065         if(node1 == 0)
1066                 goto error;
1067
1068         node1 = add_mi_node_child(node, MI_DUP_VALUE, "caller_cseq", 11,
1069                         dlg->cseq[DLG_CALLER_LEG].s,
1070                         dlg->cseq[DLG_CALLER_LEG].len);
1071         if(node1 == 0)
1072                 goto error;
1073
1074         node1 = add_mi_node_child(node, MI_DUP_VALUE,"caller_route_set",16,
1075                         dlg->route_set[DLG_CALLER_LEG].s,
1076                         dlg->route_set[DLG_CALLER_LEG].len);
1077         if(node1 == 0)
1078                 goto error;
1079
1080         if (dlg->bind_addr[DLG_CALLER_LEG]) {
1081                 node1 = add_mi_node_child(node, 0,
1082                         "caller_bind_addr",16,
1083                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.s,
1084                         dlg->bind_addr[DLG_CALLER_LEG]->sock_str.len);
1085         } else {
1086                 node1 = add_mi_node_child(node, 0,
1087                         "caller_bind_addr",16,0,0);
1088         }
1089
1090         if (dlg->bind_addr[DLG_CALLEE_LEG]) {
1091                 node1 = add_mi_node_child(node, 0,
1092                         "callee_bind_addr",16,
1093                         dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.s,
1094                         dlg->bind_addr[DLG_CALLEE_LEG]->sock_str.len);
1095         } else {
1096                 node1 = add_mi_node_child(node, 0,
1097                         "callee_bind_addr",16,0,0);
1098         }
1099
1100         node1 = add_mi_node_child(node, MI_DUP_VALUE, "to_uri", 6,
1101                         dlg->to_uri.s, dlg->to_uri.len);
1102         if(node1 == 0)
1103                 goto error;
1104
1105         node1 = add_mi_node_child(node, MI_DUP_VALUE, "to_tag", 6,
1106                         dlg->tag[DLG_CALLEE_LEG].s, dlg->tag[DLG_CALLEE_LEG].len);
1107         if(node1 == 0)
1108                 goto error;
1109
1110         node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_contact", 14,
1111                         dlg->contact[DLG_CALLEE_LEG].s,
1112                         dlg->contact[DLG_CALLEE_LEG].len);
1113         if(node1 == 0)
1114                 goto error;
1115
1116         node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_cseq", 11,
1117                         dlg->cseq[DLG_CALLEE_LEG].s,
1118                         dlg->cseq[DLG_CALLEE_LEG].len);
1119         if(node1 == 0)
1120                 goto error;
1121
1122         node1 = add_mi_node_child(node, MI_DUP_VALUE,"callee_route_set",16,
1123                         dlg->route_set[DLG_CALLEE_LEG].s,
1124                         dlg->route_set[DLG_CALLEE_LEG].len);
1125         if(node1 == 0)
1126                 goto error;
1127
1128         if (with_context) {
1129                 node1 = add_mi_node_child(node, 0, "context", 7, 0, 0);
1130                 if(node1 == 0)
1131                         goto error;
1132                 run_dlg_callbacks( DLGCB_MI_CONTEXT,
1133                                    dlg,
1134                                    NULL,
1135                                    NULL,
1136                                    DLG_DIR_NONE,
1137                                    (void *)node1);
1138         }
1139         return 0;
1140
1141 error:
1142         LM_ERR("failed to add node\n");
1143         return -1;
1144 }
1145
1146
1147 /*!
1148  * \brief Output a dialog via the MI interface
1149  * \param rpl MI node that should be filled
1150  * \param dlg printed dialog
1151  * \param with_context if 1 then the dialog context will be also printed
1152  * \return 0 on success, -1 on failure
1153  */
1154 int mi_print_dlg(struct mi_node *rpl, struct dlg_cell *dlg, int with_context)
1155 {
1156         return internal_mi_print_dlg( rpl, dlg, with_context);
1157 }
1158
1159 /*!
1160  * \brief Helper function that output all dialogs via the MI interface
1161  * \see mi_print_dlgs
1162  * \param rpl MI node that should be filled
1163  * \param with_context if 1 then the dialog context will be also printed
1164  * \return 0 on success, -1 on failure
1165  */
1166 static int internal_mi_print_dlgs(struct mi_node *rpl, int with_context)
1167 {
1168         struct dlg_cell *dlg;
1169         unsigned int i;
1170
1171         LM_DBG("printing %i dialogs\n", d_table->size);
1172
1173         for( i=0 ; i<d_table->size ; i++ ) {
1174                 dlg_lock( d_table, &(d_table->entries[i]) );
1175
1176                 for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
1177                         if (internal_mi_print_dlg(rpl, dlg, with_context)!=0)
1178                                 goto error;
1179                 }
1180                 dlg_unlock( d_table, &(d_table->entries[i]) );
1181         }
1182         return 0;
1183
1184 error:
1185         dlg_unlock( d_table, &(d_table->entries[i]) );
1186         LM_ERR("failed to print dialog\n");
1187         return -1;
1188 }
1189
1190
1191 static inline struct mi_root* process_mi_params(struct mi_root *cmd_tree,
1192                                                                                                         struct dlg_cell **dlg_p)
1193 {
1194         struct mi_node* node;
1195         struct dlg_entry *d_entry;
1196         struct dlg_cell *dlg;
1197         str *callid;
1198         str *from_tag;
1199         unsigned int h_entry;
1200
1201         node = cmd_tree->node.kids;
1202         if (node == NULL) {
1203                 /* no parameters at all */
1204                 *dlg_p = NULL;
1205                 return NULL;
1206         }
1207
1208         /* we have params -> get callid and fromtag */
1209         callid = &node->value;
1210         if(callid->s==NULL || callid->len<=0)
1211                 return init_mi_tree(400, MI_SSTR(MI_MISSING_PARM));
1212         LM_DBG("callid='%.*s'\n", callid->len, callid->s);
1213
1214         node = node->next;
1215         if ( !node || !node->value.s || !node->value.len) {
1216                 from_tag = NULL;
1217         } else {
1218                 from_tag = &node->value;
1219                 LM_DBG("from_tag='%.*s'\n", from_tag->len, from_tag->s);
1220                 if ( node->next!=NULL )
1221                         return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
1222         }
1223
1224         h_entry = core_hash( callid, 0, d_table->size);
1225
1226         d_entry = &(d_table->entries[h_entry]);
1227         dlg_lock( d_table, d_entry);
1228
1229         for( dlg = d_entry->first ; dlg ; dlg = dlg->next ) {
1230                 if (match_downstream_dialog( dlg, callid, from_tag)==1) {
1231                         if (dlg->state==DLG_STATE_DELETED) {
1232                                 *dlg_p = NULL;
1233                                 break;
1234                         } else {
1235                                 *dlg_p = dlg;
1236                                 dlg_unlock( d_table, d_entry);
1237                                 return 0;
1238                         }
1239                 }
1240         }
1241         dlg_unlock( d_table, d_entry);
1242
1243         return init_mi_tree( 404, MI_SSTR("Nu such dialog"));
1244 }
1245
1246
1247 /*!
1248  * \brief Output all dialogs via the MI interface
1249  * \param cmd_tree MI command tree
1250  * \param param unused
1251  * \return mi node with the dialog information, or NULL on failure
1252  */
1253 struct mi_root * mi_print_dlgs(struct mi_root *cmd_tree, void *param )
1254 {
1255         struct mi_root* rpl_tree= NULL;
1256         struct mi_node* rpl = NULL;
1257         struct dlg_cell* dlg = NULL;
1258
1259         rpl_tree = process_mi_params( cmd_tree, &dlg);
1260         if (rpl_tree)
1261                 /* param error */
1262                 return rpl_tree;
1263
1264         rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
1265         if (rpl_tree==0)
1266                 return 0;
1267         rpl = &rpl_tree->node;
1268
1269         if (dlg==NULL) {
1270                 if ( internal_mi_print_dlgs(rpl,0)!=0 )
1271                         goto error;
1272         } else {
1273                 if ( internal_mi_print_dlg(rpl,dlg,0)!=0 )
1274                         goto error;
1275         }
1276
1277         return rpl_tree;
1278 error:
1279         free_mi_tree(rpl_tree);
1280         return NULL;
1281 }
1282
1283
1284 /*!
1285  * \brief Print a dialog context via the MI interface
1286  * \param cmd_tree MI command tree
1287  * \param param unused
1288  * \return mi node with the dialog information, or NULL on failure
1289  */
1290 struct mi_root * mi_print_dlgs_ctx(struct mi_root *cmd_tree, void *param )
1291 {
1292         struct mi_root* rpl_tree= NULL;
1293         struct mi_node* rpl = NULL;
1294         struct dlg_cell* dlg = NULL;
1295
1296         rpl_tree = process_mi_params( cmd_tree, &dlg);
1297         if (rpl_tree)
1298                 /* param error */
1299                 return rpl_tree;
1300
1301         rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
1302         if (rpl_tree==0)
1303                 return 0;
1304         rpl = &rpl_tree->node;
1305
1306         if (dlg==NULL) {
1307                 if ( internal_mi_print_dlgs(rpl,1)!=0 )
1308                         goto error;
1309         } else {
1310                 if ( internal_mi_print_dlg(rpl,dlg,1)!=0 )
1311                         goto error;
1312         }
1313
1314         return rpl_tree;
1315 error:
1316         free_mi_tree(rpl_tree);
1317         return NULL;
1318 }
1319
1320 /*!
1321  * \brief Terminate all or selected dialogs via the MI interface
1322  * \param cmd_tree MI command tree
1323  * \param param unused
1324  * \return mi node with the dialog information, or NULL on failure
1325  */
1326 struct mi_root * mi_terminate_dlgs(struct mi_root *cmd_tree, void *param )
1327 {
1328         struct mi_root* rpl_tree= NULL;
1329         struct dlg_cell* dlg = NULL;
1330         str headers = {0, 0};
1331
1332         rpl_tree = process_mi_params( cmd_tree, &dlg);
1333         if (rpl_tree)
1334                 /* param error */
1335                 return rpl_tree;
1336         if (dlg==NULL)
1337                 return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
1338
1339         rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
1340         if (rpl_tree==0)
1341                 return 0;
1342         if (dlg_bye_all(dlg, &headers)!=0)
1343                 goto error;
1344         return rpl_tree;
1345 error:
1346         free_mi_tree(rpl_tree);
1347         return NULL;
1348 }
1349
1350