1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759 |
- /*!
- * \file
- * \brief Functions related to dialog creation and searching
- * \ingroup dialog
- * Module: \ref dialog
- */
- #include <stdlib.h>
- #include <string.h>
- #include "../../dprint.h"
- #include "../../ut.h"
- #include "../../lib/kmi/mi.h"
- #include "dlg_timer.h"
- #include "dlg_var.h"
- #include "dlg_hash.h"
- #include "dlg_profile.h"
- #include "dlg_handlers.h"
- #include "dlg_db_handler.h"
- #define MAX_LDG_LOCKS 2048
- #define MIN_LDG_LOCKS 2
- extern int dlg_db_mode;
- /*! global dialog table */
- struct dlg_table *d_table = 0;
- /*! global dialog out table */
- static int dlg_hash_size_out = 4096;
- /*!
- * \brief Reference a dialog without locking
- * \param _dlg dialog
- * \param _cnt increment for the reference counter
- */
- #define ref_dlg_unsafe(_dlg,_cnt) \
- do { \
- (_dlg)->ref += (_cnt); \
- LM_DBG("ref dlg %p with %d -> %d\n", \
- (_dlg),(_cnt),(_dlg)->ref); \
- }while(0)
- /*!
- * \brief Unreference a dialog without locking
- * \param _dlg dialog
- * \param _cnt decrement for the reference counter
- * \param _d_entry dialog entry
- */
- #define unref_dlg_unsafe(_dlg,_cnt,_d_entry) \
- do { \
- (_dlg)->ref -= (_cnt); \
- LM_DBG("unref dlg %p with %d -> %d\n",\
- (_dlg),(_cnt),(_dlg)->ref);\
- if ((_dlg)->ref<0) {\
- LM_CRIT("bogus ref %d with cnt %d for dlg %p [%u:%u] "\
- "with clid '%.*s' and tags '%.*s'\n",\
- (_dlg)->ref, _cnt, _dlg,\
- (_dlg)->h_entry, (_dlg)->h_id,\
- (_dlg)->callid.len, (_dlg)->callid.s,\
- (_dlg)->from_tag.len,\
- (_dlg)->from_tag.s);\
- }\
- if ((_dlg)->ref<=0) { \
- unlink_unsafe_dlg( _d_entry, _dlg);\
- LM_DBG("ref <=0 for dialog %p\n",_dlg);\
- destroy_dlg(_dlg);\
- }\
- }while(0)
- /*!
- * \brief Initialize the global dialog table
- * \param size size of the table
- * \return 0 on success, -1 on failure
- */
- int init_dlg_table(unsigned int size) {
- unsigned int n;
- unsigned int i;
- d_table = (struct dlg_table*) shm_malloc
- (sizeof (struct dlg_table) +size * sizeof (struct dlg_entry));
- if (d_table == 0) {
- LM_ERR("no more shm mem (1)\n");
- goto error0;
- }
- memset(d_table, 0, sizeof (struct dlg_table));
- d_table->size = size;
- d_table->entries = (struct dlg_entry*) (d_table + 1);
- n = (size < MAX_LDG_LOCKS) ? size : MAX_LDG_LOCKS;
- for (; n >= MIN_LDG_LOCKS; n--) {
- d_table->locks = lock_set_alloc(n);
- if (d_table->locks == 0)
- continue;
- if (lock_set_init(d_table->locks) == 0) {
- lock_set_dealloc(d_table->locks);
- d_table->locks = 0;
- continue;
- }
- d_table->locks_no = n;
- break;
- }
- if (d_table->locks == 0) {
- LM_ERR("unable to allocted at least %d locks for the hash table\n",
- MIN_LDG_LOCKS);
- goto error1;
- }
- for (i = 0; i < size; i++) {
- memset(&(d_table->entries[i]), 0, sizeof (struct dlg_entry));
- d_table->entries[i].next_id = rand() % (3*size);
- d_table->entries[i].lock_idx = i % d_table->locks_no;
- }
- return 0;
- error1:
- shm_free(d_table);
- error0:
- return -1;
- }
- /*!
- * \brief free all the memory in the entry_out structure
- * \param d_entry_out structure
- * \return void
- */
- static void destroy_entry_out(struct dlg_entry_out *d_entry_out) {
- struct dlg_cell_out *dlg_out;
- struct dlg_cell_out *dlg_out_tmp;
- dlg_out = d_entry_out->first;
- LM_DBG("Destroy dialog entry out\n");
- while (dlg_out) {
- //clear all dlg_out memory space
- if (dlg_out->caller_cseq.s) {
- LM_DBG("content before freeing caller cseq is [%.*s]\n", dlg_out->caller_cseq.len, dlg_out->caller_cseq.s);
- shm_free(dlg_out->caller_cseq.s);
- }
- if (dlg_out->callee_cseq.s) {
- LM_DBG("content before freeing callee cseq is [%.*s]\n", dlg_out->callee_cseq.len, dlg_out->callee_cseq.s);
- shm_free(dlg_out->callee_cseq.s);
- }
- if (dlg_out->callee_contact.s) {
- LM_DBG("content before freeing callee contact is [%.*s]\n", dlg_out->callee_contact.len, dlg_out->callee_contact.s);
- shm_free(dlg_out->callee_contact.s);
- }
- if (dlg_out->callee_route_set.s) {
- shm_free(dlg_out->callee_route_set.s);
- }
- if (dlg_out->did.s) {
- shm_free(dlg_out->did.s);
- }
- dlg_out_tmp = dlg_out->next;
- shm_free(dlg_out);
- dlg_out = dlg_out_tmp;
- }
- }
- /*!
- * \brief Destroy a dialog, run callbacks and free memory
- * \param dlg destroyed dialog
- */
- inline void destroy_dlg(struct dlg_cell *dlg) {
- int ret = 0;
- struct dlg_var *var;
- LM_DBG("destroying dialog %p\n", dlg);
- ret = remove_dialog_timer(&dlg->tl);
- if (ret < 0) {
- LM_CRIT("unable to unlink the timer on dlg %p [%u:%u] "
- "with clid '%.*s' and tags '%.*s'\n",
- dlg, dlg->h_entry, dlg->h_id,
- dlg->callid.len, dlg->callid.s,
- dlg->from_tag.len, dlg->from_tag.s);
- } else if (ret > 0) {
- LM_DBG("removed timer for dlg %p [%u:%u] "
- "with clid '%.*s' and tags '%.*s' \n",
- dlg, dlg->h_entry, dlg->h_id,
- dlg->callid.len, dlg->callid.s,
- dlg->from_tag.len, dlg->from_tag.s);
- }
- if (dlg_db_mode)
- remove_dialog_in_from_db(dlg);
- LM_DBG("About to run dlg callback for destroy\n");
- run_dlg_callbacks(DLGCB_DESTROY, dlg, NULL, NULL, DLG_DIR_NONE, 0);
- LM_DBG("DONE: About to run dlg callback for destroy\n");
- if (dlg == get_current_dlg_pointer())
- reset_current_dlg_pointer();
- if (dlg->cbs.first)
- destroy_dlg_callbacks_list(dlg->cbs.first);
- if (dlg->profile_links)
- destroy_linkers(dlg->profile_links);
- if (dlg->from_tag.s)
- shm_free(dlg->from_tag.s);
- if (dlg->first_req_cseq.s)
- shm_free(dlg->first_req_cseq.s);
- if (dlg->toroute_name.s)
- shm_free(dlg->toroute_name.s);
- if (dlg->did.s)
- shm_free(dlg->did.s);
- if (dlg->caller_route_set.s)
- shm_free(dlg->caller_route_set.s);
- if (dlg->caller_contact.s)
- shm_free(dlg->caller_contact.s);
- while (dlg->vars) {
- var = dlg->vars;
- dlg->vars = dlg->vars->next;
- shm_free(var->key.s);
- shm_free(var->value.s);
- shm_free(var);
- }
- if (&(dlg->dlg_entry_out)) {
- lock_get(dlg->dlg_out_entries_lock);
- destroy_entry_out(&(dlg->dlg_entry_out));
- lock_release(dlg->dlg_out_entries_lock);
- }
- lock_destroy(dlg->dlg_out_entries_lock);
- lock_dealloc(dlg->dlg_out_entries_lock);
- shm_free(dlg);
- dlg = 0;
- }
- /*!
- * \brief Destroy the global dialog table
- */
- void destroy_dlg_table(void) {
- struct dlg_cell *dlg, *l_dlg;
- unsigned int i;
- if (d_table == 0)
- return;
- if (d_table->locks) {
- lock_set_destroy(d_table->locks);
- lock_set_dealloc(d_table->locks);
- }
- for (i = 0; i < d_table->size; i++) {
- dlg = d_table->entries[i].first;
- while (dlg) {
- l_dlg = dlg;
- dlg = dlg->next;
- destroy_dlg(l_dlg);
- }
- }
- shm_free(d_table);
- d_table = 0;
- return;
- }
- /*!
- * \brief Create a new dialog structure for a SIP dialog
- * \param callid dialog callid
- * \param from_uri dialog from uri
- * \param to_uri dialog to uri
- * \param from_tag dialog from tag
- * \param req_uri dialog r-uri
- * \return created dialog structure on success, NULL otherwise
- */
- struct dlg_cell* build_new_dlg(str *callid, str *from_uri, str *from_tag, str *req_uri) {
- struct dlg_cell *dlg;
- int len;
- char *p;
- len = sizeof (struct dlg_cell) +callid->len + from_uri->len + req_uri->len;
- dlg = (struct dlg_cell*) shm_malloc(len);
- if (dlg == 0) {
- LM_ERR("no more shm mem (%d)\n", len);
- return 0;
- }
- memset(dlg, 0, len);
- dlg->dlg_out_entries_lock = lock_alloc();
- if (dlg->dlg_out_entries_lock == NULL) {
- LM_ERR("Cannot allocate lock for dlg out entries. Aborting...\n");
- shm_free(dlg);
- return 0;
- } else {
- if (lock_init(dlg->dlg_out_entries_lock) == NULL) {
- LM_ERR("Cannot init the lock for dlg out entries. Aborting...\n");
- lock_destroy(dlg->dlg_out_entries_lock);
- lock_dealloc(dlg->dlg_out_entries_lock);
- shm_free(dlg);
- return 0;
- }
- }
- dlg->state = DLG_STATE_UNCONFIRMED;
- dlg->h_entry = core_hash(callid, 0, d_table->size);
- LM_DBG("new dialog on hash %u\n", dlg->h_entry);
- p = (char*) (dlg + 1);
- dlg->callid.s = p;
- dlg->callid.len = callid->len;
- memcpy(p, callid->s, callid->len);
- p += callid->len;
- dlg->from_uri.s = p;
- dlg->from_uri.len = from_uri->len;
- memcpy(p, from_uri->s, from_uri->len);
- p += from_uri->len;
- dlg->req_uri.s = p;
- dlg->req_uri.len = req_uri->len;
- memcpy(p, req_uri->s, req_uri->len);
- p += req_uri->len;
- if (p != (((char*) dlg) + len)) {
- LM_CRIT("buffer overflow\n");
- shm_free(dlg);
- return 0;
- }
- return dlg;
- }
- /*!
- * \brief Set the leg information for an existing dialog
- * \param dlg dialog
- * \param tag from tag or to tag
- * \param rr record-routing information
- * \param contact caller or callee contact
- * \param cseq CSEQ of caller or callee
- * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
- * \return 0 on success, -1 on failure
- */
- int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
- str *cseq, struct socket_info *bind_addr, unsigned int leg) {
- if (!dlg) {
- return -1;
- }
- //create new dlg_out entry
- struct dlg_entry_out *d_entry_out = &(dlg->dlg_entry_out);
- struct dlg_cell_out *dlg_out;
- if (leg == DLG_CALLER_LEG) {
- if (tag->len > 0) {
- dlg->from_tag.s = (char*) shm_malloc(tag->len);
- if (!dlg->from_tag.s) {
- LM_ERR("no more shm_mem\n");
- return -1;
- }
- memcpy(dlg->from_tag.s, tag->s, tag->len);
- dlg->from_tag.len = tag->len;
- }
- if (contact->len > 0) {
- dlg->caller_contact.s = (char*) shm_malloc(contact->len);
- if (!dlg->caller_contact.s) {
- LM_ERR("no more shm_mem\n");
- return -1;
- }
- memcpy(dlg->caller_contact.s, contact->s, contact->len);
- dlg->caller_contact.len = contact->len;
- }
- if (rr->len > 0) {
- dlg->caller_route_set.s = (char*) shm_malloc(rr->len);
- if (!dlg->caller_route_set.s) {
- LM_ERR("no more shm_mem\n");
- return -1;
- }
- memcpy(dlg->caller_route_set.s, rr->s, rr->len);
- dlg->caller_route_set.len = rr->len;
- }
- if (cseq->len > 0) {
- dlg->first_req_cseq.s = (char*) shm_malloc(cseq->len);
- if (!dlg->first_req_cseq.s) {
- LM_ERR("no more shm_mem\n");
- return -1;
- }
- memcpy(dlg->first_req_cseq.s, cseq->s, cseq->len);
- dlg->first_req_cseq.len = cseq->len;
- }
- } else {
- /* this is the callee side so we need to find the dialog_out entry with the correct to_tag
- and assign caller and callee cseq, callee contact, callee route_set
- */
- if (d_entry_out) {
- lock_get(dlg->dlg_out_entries_lock);
- dlg_out = d_entry_out->first;
- while (dlg_out) {
- LM_DBG("Searching out dialog with to_tag '%.*s' (looking for %.*s\n", dlg_out->to_tag.len, dlg_out->to_tag.s, tag->len, tag->s);
- if (dlg_out->to_tag.len == tag->len && memcmp(dlg_out->to_tag.s, tag->s, dlg_out->to_tag.len) == 0) {
- LM_DBG("Found dialog_out entry with correct to_tag - updating leg info\n");
- if (contact->len > 0) {
- dlg_out->callee_contact.s = (char*) shm_malloc(contact->len);
- if (!dlg_out->callee_contact.s) {
- LM_ERR("no more shm mem\n");
- return -1; //if we're out of mem we dont really care about cleaning up - prob going to crash anyway
- }
- dlg_out->callee_contact.len = contact->len;
- memcpy(dlg_out->callee_contact.s, contact->s, contact->len);
- }
- if (rr->len > 0) {
- dlg_out->callee_route_set.s = (char*) shm_malloc(rr->len);
- if (!dlg_out->callee_route_set.s) {
- LM_ERR("no more shm mem\n");
- return -1; //if we're out of mem we dont really care about cleaning up - prob going to crash anyway
- }
- dlg_out->callee_route_set.len = rr->len;
- memcpy(dlg_out->callee_route_set.s, rr->s, rr->len);
- }
- if (cseq->len > 0) {
- dlg_out->callee_cseq.s = (char*) shm_malloc(cseq->len);
- dlg_out->caller_cseq.s = (char*) shm_malloc(cseq->len);
- if (!dlg_out->callee_cseq.s || !dlg_out->caller_cseq.s) {
- LM_ERR("no more shm mem\n");
- return -1; //if we're out of mem we dont really care about cleaning up - prob going to crash anyway
- }
- dlg_out->caller_cseq.len = cseq->len;
- memcpy(dlg_out->caller_cseq.s, cseq->s, cseq->len);
- dlg_out->callee_cseq.len = cseq->len;
- memcpy(dlg_out->callee_cseq.s, cseq->s, cseq->len);
- }
- dlg_out->callee_bind_addr = bind_addr;
- }
- dlg_out = dlg_out->next;
- }
- lock_release(dlg->dlg_out_entries_lock);
- } else {
- LM_ERR("This dialog has no dialog out entries\n");
- return -1;
- }
- }
- return 0;
- }
- /*!
- * \brief Create a new dialog out structure for a SIP dialog
- * \param to_tag - dialog to_tag
- * \return created dlg_out structure on success, NULL otherwise
- */
- struct dlg_cell_out* build_new_dlg_out(struct dlg_cell *dlg, str* to_uri, str* to_tag) {
- struct dlg_cell_out *dlg_out;
- int len;
- char *p;
- //len = sizeof (struct dlg_cell_out) +dlg->did.len + to_tag->len + to_uri->len;
- len = sizeof (struct dlg_cell_out) +to_tag->len + to_uri->len;
- dlg_out = (struct dlg_cell_out*) shm_malloc(len);
- if (dlg_out == 0) {
- LM_ERR("no more shm mem (%d)\n", len);
- return 0;
- }
- memset(dlg_out, 0, len);
- dlg_out->h_entry = core_hash(to_tag, 0, dlg_hash_size_out);
- LM_DBG("new dialog_out on hash %u\n", dlg_out->h_entry);
- p = (char*) (dlg_out + 1);
- //dlg_out->did.s = p;
- //dlg_out->did.len = dlg->did.len;
- //memcpy(p, dlg->did.s, dlg->did.len);
- //p += dlg->did.len;
- dlg_out->to_uri.s = p;
- dlg_out->to_uri.len = to_uri->len;
- memcpy(p, to_uri->s, to_uri->len);
- p += to_uri->len;
- dlg_out->to_tag.s = p;
- dlg_out->to_tag.len = to_tag->len;
- memcpy(p, to_tag->s, to_tag->len);
- p += to_tag->len;
- if (p != (((char*) dlg_out) + len)) {
- LM_CRIT("buffer overflow\n");
- shm_free(dlg_out);
- return 0;
- }
- //did might be updated (check update_did_dlg_out) if there is a concurrent call -therefore this should not be done as single block of memory
- //so Richard editted this to not have did in the single block of memory
- if (dlg->did.len > 0) {
- dlg_out->did.s = (char*) shm_malloc(dlg->did.len);
- if (!dlg_out->did.s) {
- LM_ERR("no more shm_mem\n");
- return 0;
- }
- memcpy(dlg_out->did.s, dlg->did.s, dlg->did.len);
- dlg_out->did.len = dlg->did.len;
- }
- return dlg_out;
- }
- /*!
- * \brief Free the memory for a dlg_out cell
- * \param dlg_out structure
- * \return void
- */
- void free_dlg_out_cell(struct dlg_cell_out *dlg_out) {
- if (dlg_out->callee_contact.s)
- shm_free(dlg_out->callee_contact.s);
- if (dlg_out->callee_cseq.s)
- shm_free(dlg_out->callee_cseq.s);
- if (dlg_out->callee_route_set.s)
- shm_free(dlg_out->callee_route_set.s);
- if (dlg_out->caller_cseq.s)
- shm_free(dlg_out->caller_cseq.s);
- //Richard removed this - it is free-ed two lines above!!??!
- //if (dlg_out->callee_route_set.s)
- // shm_free(dlg_out->callee_route_set.s);
- //Richard added this as the did is now malloc-ed separately and not as a single concurrent block (as the totag etc. are)
- if (dlg_out->did.s)
- shm_free(dlg_out->did.s);
- shm_free(dlg_out);
- }
- /*!
- * \brief Remove dlg_out entry identified by to_tag from dlg structure
- * \param dlg structure
- * \param dlg_out to_tag
- * \return void
- */
- void dlg_remove_dlg_out_tag(struct dlg_cell *dlg, str *to_tag) {
- lock_get(dlg->dlg_out_entries_lock);
- struct dlg_entry_out *d_entry_out = &(dlg->dlg_entry_out);
- struct dlg_cell_out *pdlg_out = d_entry_out->first;
- struct dlg_cell_out *tmpdlg = 0;
- int only = 0;
- while (pdlg_out) {
- if (pdlg_out->deleted) {
- LM_DBG("Found dlg_out to remove\n");
- if (pdlg_out->prev) {
- pdlg_out->prev->next = pdlg_out->next;
- } else {
- //assume that we are first
- if (pdlg_out->next) {
- d_entry_out->first = pdlg_out->next;
- pdlg_out->next->prev = 0;
- } else {
- LM_ERR("dlg out entry has prev set to null and next set to null too\n");
- only = 1;
- }
- }
- if (pdlg_out->next) {
- pdlg_out->next->prev = pdlg_out->prev;
- } else {
- //we are likely the last
- if (pdlg_out->prev) {
- d_entry_out->last = pdlg_out->prev;
- } else {
- LM_ERR("dlg out next is NULL and so is prev");
- only = 1;
- }
- }
- tmpdlg = pdlg_out->next;
- free_dlg_out_cell(pdlg_out);
- pdlg_out = tmpdlg;
- if (only) {
- d_entry_out->last = 0;
- d_entry_out->first = 0;
- }
- } else {
- LM_DBG("Not deleting dlg_out as it is not set to deleted\n");
- pdlg_out = pdlg_out->next;
- }
- }
- lock_release(dlg->dlg_out_entries_lock);
- }
- /*!
- * \brief Remove all dlg_out entries from dlg structure expect that identified as dlg_do_not_remove
- * \param dlg_out cell - structure to not remove
- * \param mark_only - 1 then only mark for deletion, if 0 then delete
- * \return void
- */
- void dlg_remove_dlg_out(struct dlg_cell_out *dlg_out_do_not_remove, struct dlg_cell *dlg, int only_mark) {
- lock_get(dlg->dlg_out_entries_lock);
- //get dlg_out_entry list from dlg
- struct dlg_entry_out *d_entry_out = &(dlg->dlg_entry_out);
- struct dlg_cell_out *dlg_out;
- //check if list is empty
- if ((d_entry_out->first == d_entry_out->last) && (d_entry_out->first == 0)) {
- LM_DBG("There are no dlg_out entries\n");
- lock_release(dlg->dlg_out_entries_lock);
- return;
- }
- dlg_out = d_entry_out->first;
- LM_DBG("Scanning dlg_entry_out list for dlg_out entry with did: [%s]", dlg->did.s);
- //run through the list and for each dlg_out_entry:
- while (dlg_out) {
- //check if it is the dlg_out that we don't want to remove (compare the to-tags)
- if (dlg_out->to_tag.len == dlg_out_do_not_remove->to_tag.len &&
- memcmp(dlg_out->to_tag.s, dlg_out_do_not_remove->to_tag.s, dlg_out->to_tag.len) == 0) {
- LM_DBG("This is the dlg_out not to be removed!\n");
- } else {
- //check if this the last entry in the entry_table
- if ((d_entry_out->first == d_entry_out->last)) {
- //we shouldnt ever get here
- LM_DBG("This is the last dlg_out_entry in the dlg_entries_out\n");
- //this is the last then set entry_out-> first and entry_out->last to zero
- dlg->dlg_entry_out.first = dlg->dlg_entry_out.last = 0;
- } else {
- if (!only_mark) {
- LM_DBG("Deleteing dlg out structure\n");
- if (dlg_out->prev) {
- dlg_out->prev->next = dlg_out->next;
- }
- //make the next->previous dlg_out point to the previous of this dlg_out
- //do not do this if this is the last entry in the list as the next struct is null
- if (dlg_out->next) {
- dlg_out->next->prev = dlg_out->prev;
- }
- free_dlg_out_cell(dlg_out);
- } else {
- LM_DBG("Marking dlg_out structure for deletion - it should be deleted by tm callback instead to_tag: %.*s\n", dlg_out->to_tag.len, dlg_out->to_tag.s);
- dlg_out->deleted = 1;
- }
- }
- }
- dlg_out = dlg_out->next;
- }
- lock_release(dlg->dlg_out_entries_lock);
- }
- /*!
- * \brief Update or set the CSEQ for an existing dialog
- * \param dlg dialog
- * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
- * \param cseq CSEQ of caller or callee
- * \return 0 on success, -1 on failure
- */
- int dlg_update_cseq(struct dlg_cell * dlg, unsigned int leg, str *cseq, str *to_tag) {
- LM_DBG("trying to update cseq with seq [%.*s]\n", cseq->len, cseq->s);
- //Runs through the dlg_oput entries finds the one that matches the to_tag and updates the callee or caller cseq accordingly
- struct dlg_entry_out *d_entry_out = &(dlg->dlg_entry_out);
- struct dlg_cell_out *dlg_out;
- dlg_out = d_entry_out->first;
- if (to_tag) {
- //compare the to_tag passed parameter to all the dlg_out to_tag entry of the dlg parameter (There could be multiple)
- while (dlg_out) {
- if (dlg_out->to_tag.len == to_tag->len && memcmp(dlg_out->to_tag.s, to_tag->s, dlg_out->to_tag.len) == 0) {
- //this parameter matches we have found the dlg_out to update the cseq
- if (leg == DLG_CALLER_LEG) {
- //update caller cseq
- if (dlg_out->caller_cseq.s) {
- if (dlg_out->caller_cseq.len < cseq->len) {
- shm_free(dlg_out->caller_cseq.s);
- dlg_out->caller_cseq.s = (char*) shm_malloc(cseq->len);
- if (dlg_out->caller_cseq.s == NULL)
- goto error;
- dlg_out->caller_cseq.len = cseq->len;
- memcpy(dlg_out->caller_cseq.s, cseq->s, cseq->len);
- }
- } else {
- dlg_out->caller_cseq.s = (char*) shm_malloc(cseq->len);
- if (dlg_out->caller_cseq.s == NULL)
- goto error;
- dlg_out->caller_cseq.len = cseq->len;
- memcpy(dlg_out->caller_cseq.s, cseq->s, cseq->len);
- }
- } else if (leg == DLG_CALLEE_LEG) {
- //update callee cseq
- if (dlg_out->callee_cseq.s) {
- if (dlg_out->callee_cseq.len < cseq->len) {
- shm_free(dlg_out->callee_cseq.s);
- dlg_out->callee_cseq.s = (char*) shm_malloc(cseq->len);
- if (dlg_out->callee_cseq.s == NULL)
- goto error;
- dlg_out->callee_cseq.len = cseq->len;
- memcpy(dlg_out->callee_cseq.s, cseq->s, cseq->len);
- }
- } else {
- dlg_out->callee_cseq.s = (char*) shm_malloc(cseq->len);
- if (dlg_out->callee_cseq.s == NULL)
- goto error;
- dlg_out->callee_cseq.len = cseq->len;
- memcpy(dlg_out->callee_cseq.s, cseq->s, cseq->len);
- }
- }
- }
- dlg_out = dlg_out->next;
- }
- }
- return 0;
- error:
- LM_ERR("not more shm mem\n");
- return -1;
- }
- /*!
- * \brief Update or set the CSEQ for an existing dialog
- * \param dlg dialog
- * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
- * \param cseq CSEQ of caller or callee
- * \return 0 on success, -1 on failure
- */
- int dlg_update_contact(struct dlg_cell * dlg, unsigned int leg, str *contact, str *to_tag) {
- LM_DBG("trying to update contact with contact [%.*s]\n", contact->len, contact->s);
- //Runs through the dlg_oput entries finds the one that matches the to_tag and updates the callee or caller contact accordingly
- struct dlg_entry_out *d_entry_out = &(dlg->dlg_entry_out);
- struct dlg_cell_out *dlg_out;
- dlg_out = d_entry_out->first;
- if (leg == DLG_CALLER_LEG) {
- //update caller contact
- if (dlg->caller_contact.s) {
- if (dlg->caller_contact.len < contact->len) {
- shm_free(dlg->caller_contact.s);
- dlg->caller_contact.s = (char*) shm_malloc(contact->len);
- if (dlg->caller_contact.s == NULL)
- goto error;
- dlg->caller_contact.len = contact->len;
- memcpy(dlg->caller_contact.s, contact->s, contact->len);
- }
- } else {
- dlg->caller_contact.s = (char*) shm_malloc(contact->len);
- if (dlg->caller_contact.s == NULL)
- goto error;
- dlg->caller_contact.len = contact->len;
- memcpy(dlg->caller_contact.s, contact->s, contact->len);
- }
- }
- if (leg == DLG_CALLEE_LEG) {
- //update callee contact
- if (!to_tag) {
- LM_ERR("No to tag to identify dlg_out\n");
- return -1;
- }
- //compare the to_tag passed parameter to all the dlg_out to_tag entry of the dlg parameter (There could be multiple)
- while (dlg_out) {
- if (dlg_out->to_tag.len == to_tag->len && memcmp(dlg_out->to_tag.s, to_tag->s, dlg_out->to_tag.len) == 0) {
- //this parameter matches we have found the dlg_out to update the callee contact
- //update callee contact
- if (dlg_out->callee_contact.s) {
- if (dlg_out->callee_contact.len < contact->len) {
- shm_free(dlg_out->callee_contact.s);
- dlg_out->callee_contact.s = (char*) shm_malloc(contact->len);
- if (dlg_out->callee_contact.s == NULL)
- goto error;
- dlg_out->callee_contact.len = contact->len;
- memcpy(dlg_out->callee_contact.s, contact->s, contact->len);
- }
- } else {
- dlg_out->callee_contact.s = (char*) shm_malloc(contact->len);
- if (dlg_out->callee_contact.s == NULL)
- goto error;
- dlg_out->callee_contact.len = contact->len;
- memcpy(dlg_out->callee_contact.s, contact->s, contact->len);
- }
- }
- dlg_out = dlg_out->next;
- }
- }
- return 0;
- error:
- LM_ERR("not more shm mem\n");
- return -1;
- }
- /*!
- * \brief Lookup a dialog in the global list
- *
- * Note that the caller is responsible for decrementing (or reusing)
- * the reference counter by one again iff a dialog has been found.
- * \param h_entry number of the hash table entry
- * \param h_id id of the hash table entry
- * \return dialog structure on success, NULL on failure
- */
- struct dlg_cell * lookup_dlg(unsigned int h_entry, unsigned int h_id) {
- struct dlg_cell *dlg;
- struct dlg_entry *d_entry;
- if (h_entry >= d_table->size)
- goto not_found;
- d_entry = &(d_table->entries[h_entry]);
- dlg_lock(d_table, d_entry);
- for (dlg = d_entry->first; dlg; dlg = dlg->next) {
- if (dlg->h_id == h_id) {
- ref_dlg_unsafe(dlg, 1);
- dlg_unlock(d_table, d_entry);
- LM_DBG("dialog id=%u found on entry %u\n", h_id, h_entry);
- return dlg;
- }
- }
- dlg_unlock(d_table, d_entry);
- not_found:
- LM_DBG("no dialog id=%u found on entry %u\n", h_id, h_entry);
- return 0;
- }
- /*!
- * \brief Helper function to get a dialog corresponding to a SIP message
- * \see get_dlg
- * \param callid callid
- * \param ftag from tag
- * \param ttag to tag
- * \param dir direction
- * \return dialog structure on success, NULL on failure
- */
- static inline struct dlg_cell * internal_get_dlg(unsigned int h_entry,
- str *callid, str *ftag, str *ttag, unsigned int *dir) {
- struct dlg_cell *dlg;
- struct dlg_entry *d_entry;
- d_entry = &(d_table->entries[h_entry]);
- dlg_lock(d_table, d_entry);
- for (dlg = d_entry->first; dlg; dlg = dlg->next) {
- /* Check callid / fromtag / totag */
- if (match_dialog(dlg, callid, ftag, ttag, dir) == 1) {
- ref_dlg_unsafe(dlg, 1);
- dlg_unlock(d_table, d_entry);
- return dlg;
- }
- }
- dlg_unlock(d_table, d_entry);
- return 0;
- }
- /*!
- * \brief Get dialog that correspond to CallId, From Tag and To Tag
- *
- * Get dialog that correspond to CallId, From Tag and To Tag.
- * See RFC 3261, paragraph 4. Overview of Operation:
- * "The combination of the To tag, From tag, and Call-ID completely
- * defines a peer-to-peer SIP relationship between [two UAs] and is
- * referred to as a dialog."
- * Note that the caller is responsible for decrementing (or reusing)
- * the reference counter by one again iff a dialog has been found.
- * \param callid callid
- * \param ftag from tag
- * \param ttag to tag
- * \param dir direction
- * \return dialog structure on success, NULL on failure
- */
- struct dlg_cell * get_dlg(str *callid, str *ftag, str *ttag, unsigned int *dir) {
- struct dlg_cell *dlg;
- if ((dlg = internal_get_dlg(core_hash(callid, 0,
- d_table->size), callid, ftag, ttag, dir)) == 0 &&
- (dlg = internal_get_dlg(core_hash(callid, ttag->len
- ? ttag : 0, d_table->size), callid, ftag, ttag, dir)) == 0) {
- LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
- return 0;
- }
- return dlg;
- }
- /*!
- * \brief Link a dialog structure
- * \param dlg dialog
- * \param n extra increments for the reference counter
- */
- void link_dlg_out(struct dlg_cell *dlg, struct dlg_cell_out *dlg_out, int n) {
- LM_DBG("Start: link_dlg_out\n");
- lock_get(dlg->dlg_out_entries_lock);
- struct dlg_entry_out *d_entry_out = &(dlg->dlg_entry_out);
- if ((d_entry_out->first == d_entry_out->last) && (d_entry_out->first == 0)) {
- //adding first out dialog
- LM_DBG("Adding first dlg_out structure\n");
- d_entry_out->first = dlg_out;
- d_entry_out->last = dlg_out;
- } else {
- LM_DBG("Adding new dlg_out structure\n");
- dlg_out->prev = d_entry_out->last;
- dlg_out->next = 0;
- d_entry_out->last->next = dlg_out;
- d_entry_out->last = dlg_out;
- }
- lock_release(dlg->dlg_out_entries_lock);
- LM_DBG("Done: link_dlg_out\n");
- return;
- }
- /*!
- * \brief Link a dialog structure
- * \param dlg dialog
- * \param n extra increments for the reference counter
- */
- void link_dlg(struct dlg_cell *dlg, int n) {
- struct dlg_entry *d_entry;
- LM_DBG("Linking new dialog with h_entry: %u", dlg->h_entry);
- d_entry = &(d_table->entries[dlg->h_entry]);
- dlg_lock(d_table, d_entry);
- dlg->h_id = d_entry->next_id++;
- if (d_entry->first == 0) {
- d_entry->first = d_entry->last = dlg;
- } else {
- d_entry->last->next = dlg;
- dlg->prev = d_entry->last;
- d_entry->last = dlg;
- }
- ref_dlg_unsafe(dlg, 1 + n);
- dlg_unlock(d_table, d_entry);
- return;
- }
- /*!
- * \brief Refefence a dialog with locking
- * \see ref_dlg_unsafe
- * \param dlg dialog
- * \param cnt increment for the reference counter
- */
- void ref_dlg(struct dlg_cell *dlg, unsigned int cnt) {
- struct dlg_entry *d_entry;
- d_entry = &(d_table->entries[dlg->h_entry]);
- dlg_lock(d_table, d_entry);
- ref_dlg_unsafe(dlg, cnt);
- dlg_unlock(d_table, d_entry);
- }
- /*!
- * \brief Unreference a dialog with locking
- * \see unref_dlg_unsafe
- * \param dlg dialog
- * \param cnt decrement for the reference counter
- */
- void unref_dlg(struct dlg_cell *dlg, unsigned int cnt) {
- struct dlg_entry *d_entry;
- d_entry = &(d_table->entries[dlg->h_entry]);
- dlg_lock(d_table, d_entry);
- unref_dlg_unsafe(dlg, cnt, d_entry);
- dlg_unlock(d_table, d_entry);
- }
- /*!
- * Small logging helper functions for next_state_dlg.
- * \param event logged event
- * \param dlg dialog data
- * \see next_state_dlg
- */
- static inline void log_next_state_dlg(const int event, const struct dlg_cell * dlg) {
- LM_CRIT("bogus event %d in state %d for dlg %p [%u:%u] with clid '%.*s' and tags "
- "'%.*s'\n", event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
- dlg->callid.len, dlg->callid.s,
- dlg->from_tag.len, dlg->from_tag.s);
- }
- /*!
- * \brief Update a dialog state according a event and the old state
- *
- * This functions implement the main state machine that update a dialog
- * state according a processed event and the current state. If necessary
- * it will delete the processed dialog. The old and new state are also
- * saved for reference.
- * \param dlg updated dialog
- * \param event current event
- * \param old_state old dialog state
- * \param new_state new dialog state
- * \param unref set to 1 when the dialog was deleted, 0 otherwise
- */
- void next_state_dlg(struct dlg_cell *dlg, int event,
- int *old_state, int *new_state, int *unref, str * to_tag) {
- struct dlg_entry *d_entry;
- d_entry = &(d_table->entries[dlg->h_entry]);
- *unref = 0;
- dlg_lock(d_table, d_entry);
- *old_state = dlg->state;
- struct dlg_entry_out *d_entry_out = &(dlg->dlg_entry_out);
- struct dlg_cell_out *dlg_out;
- dlg_out = d_entry_out->first;
- int found = -1;
- switch (event) {
- case DLG_EVENT_TDEL:
- switch (dlg->state) {
- case DLG_STATE_UNCONFIRMED:
- case DLG_STATE_EARLY:
- dlg->state = DLG_STATE_DELETED;
- unref_dlg_unsafe(dlg, 1, d_entry);
- *unref = 1;
- break;
- case DLG_STATE_CONFIRMED:
- unref_dlg_unsafe(dlg, 1, d_entry);
- break;
- case DLG_STATE_DELETED:
- *unref = 1;
- break;
- default:
- log_next_state_dlg(event, dlg);
- }
- break;
- case DLG_EVENT_RPL1xx:
- switch (dlg->state) {
- case DLG_STATE_UNCONFIRMED:
- case DLG_STATE_EARLY:
- dlg->state = DLG_STATE_EARLY;
- break;
- default:
- log_next_state_dlg(event, dlg);
- }
- break;
- case DLG_EVENT_RPL3xx:
- switch (dlg->state) {
- case DLG_STATE_UNCONFIRMED:
- case DLG_STATE_EARLY:
- dlg->state = DLG_STATE_DELETED;
- *unref = 1;
- break;
- default:
- log_next_state_dlg(event, dlg);
- }
- break;
- case DLG_EVENT_RPL2xx:
- switch (dlg->state) {
- case DLG_STATE_DELETED:
- if (dlg->dflags & DLG_FLAG_HASBYE) {
- LM_CRIT("bogus event %d in state %d (with BYE) "
- "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s' \n",
- event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
- dlg->callid.len, dlg->callid.s,
- dlg->from_tag.len, dlg->from_tag.s);
- break;
- }
- ref_dlg_unsafe(dlg, 1);
- case DLG_STATE_UNCONFIRMED:
- case DLG_STATE_EARLY:
- dlg->state = DLG_STATE_CONFIRMED;
- //TODO: check that the callbacks for confirmed are run
- break;
- case DLG_STATE_CONFIRMED:
- //check the to_tag passed parameter exists
- if (to_tag) {
- //compare the to_tag passed parameter to the dlg_out to_tag entry of the dlg parameter (There should be only 1 dlg_out entry)
- if (dlg_out->to_tag.len == to_tag->len && memcmp(dlg_out->to_tag.s, to_tag->s, dlg_out->to_tag.len) == 0) {
- //this parameter matches the existing dlg_out and is therefore a retransmission, so break
- break;
- } else {
- LM_ERR("It looks like this is a concurrently confirmed call!!\n");
- LM_ERR("Error checking now so not putting into DLG_STATE_CONCURRENTLY_CONFIRMED\n");
- LM_ERR("This is event DLG_EVENT_RPL2XX and the current dlg state is DLG_STATE_CONFIRMED\n");
- LM_ERR("There should only be one dlg out here as the state is CONFIRMED but we are checking anyway!\n");
- LM_ERR("To tag passed in the 2XX: [%.*s]", to_tag->len, to_tag->s);
- LM_ERR("Now printing dlgouts totags - there should be only one!\n");
- while (dlg_out) {
- LM_ERR("dlg_out to_tag: [%.*s]\n", dlg_out->to_tag.len, dlg_out->to_tag.s);
- dlg_out = dlg_out->next;
- }
- //The parameter does not match so this is a concurrently confirmed call
- //dlg->state = DLG_STATE_CONCURRENTLY_CONFIRMED;
- }
- } else {
- //to_tag parameter does not exist so break
- break;
- }
- case DLG_STATE_CONCURRENTLY_CONFIRMED:
- //check the to_tag passed parameter exists
- if (to_tag) {
- //compare the to_tag passed parameter to all the dlg_out to_tag entry of the dlg parameter (There could be multiple)
- while (dlg_out) {
- if (dlg_out->to_tag.len == to_tag->len && memcmp(dlg_out->to_tag.s, to_tag->s, dlg_out->to_tag.len) == 0) {
- //this parameter matches the existing dlg_out and is therefore a retransmission
- found = 1;
- }
- dlg_out = dlg_out->next;
- }
- if (found == -1) {
- //The parameter does not match so this is another concurrently confirmed call (we would have breaked by now if it matched)
- dlg->state = DLG_STATE_CONCURRENTLY_CONFIRMED;
- }
- } else {
- //to_tag parameter does not exist so break
- break;
- }
- break;
- default:
- log_next_state_dlg(event, dlg);
- }
- break;
- case DLG_EVENT_REQACK:
- switch (dlg->state) {
- case DLG_STATE_CONFIRMED:
- break;
- case DLG_STATE_DELETED:
- break;
- default:
- log_next_state_dlg(event, dlg);
- }
- break;
- case DLG_EVENT_REQBYE:
- switch (dlg->state) {
- case DLG_STATE_CONFIRMED:
- dlg->dflags |= DLG_FLAG_HASBYE;
- dlg->state = DLG_STATE_DELETED;
- *unref = 1;
- break;
- case DLG_STATE_EARLY:
- case DLG_STATE_DELETED:
- break;
- default:
- log_next_state_dlg(event, dlg);
- }
- break;
- case DLG_EVENT_REQPRACK:
- switch (dlg->state) {
- case DLG_STATE_EARLY:
- //Richard added this - think it is necessary as can received PRACK in early state!
- break;
- default:
- log_next_state_dlg(event, dlg);
- }
- break;
- case DLG_EVENT_REQ:
- switch (dlg->state) {
- case DLG_STATE_EARLY:
- case DLG_STATE_CONFIRMED:
- break;
- default:
- log_next_state_dlg(event, dlg);
- }
- break;
- default:
- LM_CRIT("unknown event %d in state %d "
- "for dlg %p [%u:%u] with clid '%.*s' and tags '%.*s'\n",
- event, dlg->state, dlg, dlg->h_entry, dlg->h_id,
- dlg->callid.len, dlg->callid.s,
- dlg->from_tag.len, dlg->from_tag.s);
- }
- *new_state = dlg->state;
- dlg_unlock(d_table, d_entry);
- LM_DBG("dialog %p changed from state %d to "
- "state %d, due event %d\n", dlg, *old_state, *new_state, event);
- }
- /**
- *
- */
- int dlg_set_toroute(struct dlg_cell *dlg, str * route) {
- if (dlg == NULL || route == NULL || route->len <= 0)
- return 0;
- if (dlg->toroute_name.s != NULL) {
- shm_free(dlg->toroute_name.s);
- dlg->toroute_name.s = NULL;
- dlg->toroute_name.len = 0;
- }
- dlg->toroute_name.s = (char*) shm_malloc((route->len + 1) * sizeof (char));
- if (dlg->toroute_name.s == NULL) {
- LM_ERR("no more shared memory\n");
- return -1;
- }
- memcpy(dlg->toroute_name.s, route->s, route->len);
- dlg->toroute_name.len = route->len;
- dlg->toroute_name.s[dlg->toroute_name.len] = '\0';
- dlg->toroute = route_lookup(&main_rt, dlg->toroute_name.s);
- return 0;
- }
- /*!
- * \brief Takes the did of the dialog and appends an "x" to it to make a different did for concurrent calls
- * \param dlg_cell - dlg_cell whose did we use
- * \param new_did - empty container for new_did
- * \return void
- */
- void create_concurrent_did(struct dlg_cell *dlg, str * new_did) {
- int len = dlg->did.len + 1 + 1;
- new_did->s = shm_malloc(len);
- if (new_did->s == 0) {
- LM_ERR("no more shm mem (%d)\n", len);
- return;
- }
- memset(new_did->s, 0, len);
- memcpy(new_did->s, dlg->did.s, dlg->did.len);
- new_did->s[dlg->did.len] = 'x';
- new_did->len = dlg->did.len + 1;
- }
- /*!
- * \brief Update the did of the dlg_out structure
- * \param dlg_cell_out - structure to update
- * \param new_did - new did to use
- * \return 1 success, 0 failure
- */
- int update_dlg_out_did(struct dlg_cell_out *dlg_out, str * new_did) {
- //update the did of the dlg_out
- if (dlg_out->did.s) {
- if (dlg_out->did.len < new_did->len) {
- shm_free(dlg_out->did.s);
- dlg_out->did.s = (char*) shm_malloc(new_did->len);
- if (dlg_out->did.s == NULL)
- goto error;
- }
- } else {
- dlg_out->did.s = (char*) shm_malloc(new_did->len);
- if (dlg_out->did.s == NULL)
- goto error;
- }
- memcpy(dlg_out->did.s, new_did->s, new_did->len);
- dlg_out->did.len = new_did->len;
- return 0;
- error:
- LM_ERR("not more shm mem\n");
- return -1;
- }
- /*!
- * \brief Update the did of the dlg structure
- * \param dlg_cell - structure to update
- * \param new_did - new did to use
- * \return 1 success, 0 failure
- */
- int update_dlg_did(struct dlg_cell *dlg, str * new_did) {
- //update the did of the dlg_out
- if (dlg->did.s) {
- if (dlg->did.len < new_did->len) {
- shm_free(dlg->did.s);
- dlg->did.s = (char*) shm_malloc(new_did->len);
- if (dlg->did.s == NULL)
- goto error;
- }
- } else {
- dlg->did.s = (char*) shm_malloc(new_did->len);
- if (dlg->did.s == NULL)
- goto error;
- }
- memcpy(dlg->did.s, new_did->s, new_did->len);
- dlg->did.len = new_did->len;
- return 0;
- error:
- LM_ERR("not more shm mem\n");
- return -1;
- }
- /**************************** MI functions ******************************/
- /*!
- * \brief Helper method that output a dialog via the MI interface
- * \see mi_print_dlg
- * \param rpl MI node that should be filled
- * \param dlg printed dialog
- * \param with_context if 1 then the dialog context will be also printed
- * \return 0 on success, -1 on failure
- */
- static inline int internal_mi_print_dlg_out(struct mi_node *rpl,
- struct dlg_cell_out * dlg_out) {
- struct mi_node* node = NULL;
- struct mi_node* node1 = NULL;
- struct mi_attr* attr = NULL;
- node = add_mi_node_child(rpl, 0, "dialog_out", 10, 0, 0);
- if (node == 0)
- goto error;
- attr = addf_mi_attr(node, 0, "hash", 4, "%u:%u",
- dlg_out->h_entry, dlg_out->h_id);
- if (attr == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "to_tag", 6,
- dlg_out->to_tag.s, dlg_out->to_tag.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "did", 3,
- dlg_out->did.s, dlg_out->did.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_contact", 14,
- dlg_out->callee_contact.s,
- dlg_out->callee_contact.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "caller_cseq", 11,
- dlg_out->caller_cseq.s,
- dlg_out->caller_cseq.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_cseq", 11,
- dlg_out->callee_cseq.s,
- dlg_out->callee_cseq.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "callee_route_set", 16,
- dlg_out->callee_route_set.s,
- dlg_out->callee_route_set.len);
- if (node1 == 0)
- goto error;
- if (dlg_out->callee_bind_addr) {
- node1 = add_mi_node_child(node, 0,
- "callee_bind_addr", 16,
- dlg_out->callee_bind_addr->sock_str.s,
- dlg_out->callee_bind_addr->sock_str.len);
- } else {
- node1 = add_mi_node_child(node, 0,
- "callee_bind_addr", 16, 0, 0);
- }
- return 0;
- error:
- LM_ERR("failed to add node\n");
- return -1;
- }
- /*!
- * \brief Helper method that output a dialog via the MI interface
- * \see mi_print_dlg
- * \param rpl MI node that should be filled
- * \param dlg printed dialog
- * \param with_context if 1 then the dialog context will be also printed
- * \return 0 on success, -1 on failure
- */
- static inline int internal_mi_print_dlg(struct mi_node *rpl,
- struct dlg_cell *dlg, int with_context) {
- struct mi_node* node = NULL;
- struct mi_node* node1 = NULL;
- struct mi_attr* attr = NULL;
- int len;
- char* p;
- node = add_mi_node_child(rpl, 0, "dialog", 6, 0, 0);
- if (node == 0)
- goto error;
- attr = addf_mi_attr(node, 0, "hash", 4, "%u:%u",
- dlg->h_entry, dlg->h_id);
- if (attr == 0)
- goto error;
- p = int2str((unsigned long) dlg->state, &len);
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "state", 5, p, len);
- if (node1 == 0)
- goto error;
- p = int2str((unsigned long) dlg->ref, &len);
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "ref_count", 9, p, len);
- if (node1 == 0)
- goto error;
- p = int2str((unsigned long) dlg->start_ts, &len);
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "timestart", 9, p, len);
- if (node1 == 0)
- goto error;
- p = int2str((unsigned long) dlg->tl.timeout, &len);
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "timeout", 7, p, len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "callid", 6,
- dlg->callid.s, dlg->callid.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "from_uri", 8,
- dlg->from_uri.s, dlg->from_uri.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "from_tag", 8,
- dlg->from_tag.s, dlg->from_tag.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "did", 3,
- dlg->did.s, dlg->did.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "caller_contact", 14,
- dlg->caller_contact.s,
- dlg->caller_contact.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "first_req_cseq", 14,
- dlg->first_req_cseq.s,
- dlg->first_req_cseq.len);
- if (node1 == 0)
- goto error;
- node1 = add_mi_node_child(node, MI_DUP_VALUE, "caller_route_set", 16,
- dlg->caller_route_set.s,
- dlg->caller_route_set.len);
- if (node1 == 0)
- goto error;
- if (dlg->caller_bind_addr) {
- node1 = add_mi_node_child(node, 0,
- "caller_bind_addr", 16,
- dlg->caller_bind_addr->sock_str.s,
- dlg->caller_bind_addr->sock_str.len);
- } else {
- node1 = add_mi_node_child(node, 0,
- "caller_bind_addr", 16, 0, 0);
- }
- if (with_context) {
- node1 = add_mi_node_child(node, 0, "context", 7, 0, 0);
- if (node1 == 0)
- goto error;
- run_dlg_callbacks(DLGCB_MI_CONTEXT,
- dlg,
- NULL,
- NULL,
- DLG_DIR_NONE,
- (void *) node1);
- }
- struct dlg_cell_out *dlg_out;
- struct dlg_entry_out *d_entry_out = &(dlg->dlg_entry_out);
- dlg_out = d_entry_out->first;
- while (dlg_out) {
- if (internal_mi_print_dlg_out(rpl, dlg_out) != 0)
- goto error;
- dlg_out = dlg_out->next;
- }
- return 0;
- error:
- LM_ERR("failed to add node\n");
- return -1;
- }
- /*!
- * \brief Output a dialog via the MI interface
- * \param rpl MI node that should be filled
- * \param dlg printed dialog
- * \param with_context if 1 then the dialog context will be also printed
- * \return 0 on success, -1 on failure
- */
- int mi_print_dlg(struct mi_node *rpl, struct dlg_cell *dlg, int with_context) {
- return internal_mi_print_dlg(rpl, dlg, with_context);
- }
- /*!
- * \brief Helper function that output all dialogs via the MI interface
- * \see mi_print_dlgs
- * \param rpl MI node that should be filled
- * \param with_context if 1 then the dialog context will be also printed
- * \return 0 on success, -1 on failure
- */
- static int internal_mi_print_dlgs(struct mi_node *rpl, int with_context) {
- struct dlg_cell *dlg;
- unsigned int i;
- LM_DBG("printing %i dialogs\n", d_table->size);
- for (i = 0; i < d_table->size; i++) {
- dlg_lock(d_table, &(d_table->entries[i]));
- for (dlg = d_table->entries[i].first; dlg; dlg = dlg->next) {
- if (internal_mi_print_dlg(rpl, dlg, with_context) != 0)
- goto error;
- }
- dlg_unlock(d_table, &(d_table->entries[i]));
- }
- return 0;
- error:
- dlg_unlock(d_table, &(d_table->entries[i]));
- LM_ERR("failed to print dialog\n");
- return -1;
- }
- static inline struct mi_root * process_mi_params(struct mi_root *cmd_tree, struct dlg_cell **dlg_p) {
- struct mi_node* node;
- struct dlg_entry *d_entry;
- struct dlg_cell *dlg;
- str *callid;
- str *from_tag;
- unsigned int h_entry;
- node = cmd_tree->node.kids;
- if (node == NULL) {
- /* no parameters at all */
- *dlg_p = NULL;
- return NULL;
- }
- /* we have params -> get callid and fromtag */
- callid = &node->value;
- LM_DBG("callid='%.*s'\n", callid->len, callid->s);
- node = node->next;
- if (!node || !node->value.s || !node->value.len) {
- from_tag = NULL;
- } else {
- from_tag = &node->value;
- LM_DBG("from_tag='%.*s'\n", from_tag->len, from_tag->s);
- if (node->next != NULL)
- return init_mi_tree(400, MI_SSTR(MI_MISSING_PARM));
- }
- h_entry = core_hash(callid, 0, d_table->size);
- d_entry = &(d_table->entries[h_entry]);
- dlg_lock(d_table, d_entry);
- for (dlg = d_entry->first; dlg; dlg = dlg->next) {
- if (match_downstream_dialog(dlg, callid, from_tag) == 1) {
- if (dlg->state == DLG_STATE_DELETED) {
- *dlg_p = NULL;
- break;
- } else {
- *dlg_p = dlg;
- dlg_unlock(d_table, d_entry);
- return 0;
- }
- }
- }
- dlg_unlock(d_table, d_entry);
- return init_mi_tree(404, MI_SSTR("Nu such dialog"));
- }
- /*!
- * \brief Output all dialogs via the MI interface
- * \param cmd_tree MI command tree
- * \param param unused
- * \return mi node with the dialog information, or NULL on failure
- */
- struct mi_root * mi_print_dlgs(struct mi_root *cmd_tree, void *param) {
- struct mi_root* rpl_tree = NULL;
- struct mi_node* rpl = NULL;
- struct dlg_cell* dlg = NULL;
- rpl_tree = process_mi_params(cmd_tree, &dlg);
- if (rpl_tree)
- //param error
- return rpl_tree;
- rpl_tree = init_mi_tree(200, MI_SSTR(MI_OK));
- if (rpl_tree == 0)
- return 0;
- rpl = &rpl_tree->node;
- if (dlg == NULL) {
- if (internal_mi_print_dlgs(rpl, 0) != 0)
- goto error;
- } else {
- if (internal_mi_print_dlg(rpl, dlg, 0) != 0)
- goto error;
- }
- return rpl_tree;
- error:
- free_mi_tree(rpl_tree);
- return NULL;
- }
- /*!
- * \brief Print a dialog context via the MI interface
- * \param cmd_tree MI command tree
- * \param param unused
- * \return mi node with the dialog information, or NULL on failure
- */
- struct mi_root * mi_print_dlgs_ctx(struct mi_root *cmd_tree, void *param) {
- struct mi_root* rpl_tree = NULL;
- struct mi_node* rpl = NULL;
- struct dlg_cell* dlg = NULL;
- rpl_tree = process_mi_params(cmd_tree, &dlg);
- if (rpl_tree)
- /* param error */
- return rpl_tree;
- rpl_tree = init_mi_tree(200, MI_SSTR(MI_OK));
- if (rpl_tree == 0)
- return 0;
- rpl = &rpl_tree->node;
- if (dlg == NULL) {
- if (internal_mi_print_dlgs(rpl, 1) != 0)
- goto error;
- } else {
- if (internal_mi_print_dlg(rpl, dlg, 1) != 0)
- goto error;
- }
- return rpl_tree;
- error:
- free_mi_tree(rpl_tree);
- return NULL;
- }
- time_t api_get_dlg_expires(str *callid, str *ftag, str *ttag) {
- struct dlg_cell *dlg;
- time_t expires = 0;
- time_t start;
- if (!callid || !ftag || !ttag) {
- LM_ERR("Missing callid, from tag or to tag\n");
- return 0;
- }
- unsigned int direction = DLG_DIR_NONE;
- dlg = get_dlg(callid, ftag, ttag, &direction);
- if (!dlg) return 0;
- if (dlg->state != DLG_STATE_CONFIRMED || !dlg->start_ts) {
- /* Dialog not started yet so lets assume start time is now.*/
- start = time(0);
- } else {
- start = dlg->start_ts;
- }
- expires = start + dlg->lifetime;
- unref_dlg(dlg, 1);
- return expires;
- }
- char* state_to_char(unsigned int state) {
- switch (state) {
- case DLG_STATE_UNCONFIRMED:
- return "Unconfirmed";
- case DLG_STATE_EARLY:
- return "Early";
- case DLG_STATE_CONFIRMED:
- return "Confirmed";
- case DLG_STATE_DELETED:
- return "Deleted";
- default:
- return "Unknown";
- }
- }
|