1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477 |
- /*!
- * \file
- * \brief Functions related to dialog handling
- * \ingroup dialog
- * Module: \ref dialog
- */
- #include <string.h>
- #include <time.h>
- #include "../../trim.h"
- #include "../../pvar.h"
- #include "../../timer.h"
- #include "../../lib/kcore/statistics.h"
- #include "../../action.h"
- #include "../../script_cb.h"
- #include "../../lib/kcore/faked_msg.h"
- #include "../../parser/parse_from.h"
- #include "../../parser/parse_cseq.h"
- #include "../../parser/contact/parse_contact.h"
- #include "../../parser/parse_from.h"
- #include "../../parser/parse_rr.h"
- #include "../../modules/tm/tm_load.h"
- #include "../../modules/rr/api.h"
- #include "dlg_hash.h"
- #include "dlg_timer.h"
- #include "dlg_cb.h"
- #include "dlg_handlers.h"
- #include "dlg_req_within.h"
- #include "dlg_profile.h"
- #include "dlg_var.h"
- #include "dlg_db_handler.h"
- static str rr_param; /*!< record-route parameter for matching */
- static int dlg_flag; /*!< flag for dialog tracking */
- static pv_spec_t *timeout_avp; /*!< AVP for timeout setting */
- static int default_timeout; /*!< default dialog timeout */
- static int seq_match_mode; /*!< dlg_match mode */
- static int shutdown_done = 0; /*!< 1 when destroy_dlg_handlers was called */
- extern int detect_spirals;
- extern int initial_cbs_inscript;
- int spiral_detected = -1;
- extern struct rr_binds d_rrb; /*!< binding to record-routing module */
- extern struct tm_binds d_tmb;
- /* statistic variables */
- extern stat_var *early_dlgs; /*!< number of early dialogs */
- extern stat_var *processed_dlgs; /*!< number of processed dialogs */
- extern stat_var *expired_dlgs; /*!< number of expired dialogs */
- extern stat_var *failed_dlgs; /*!< number of failed dialogs */
- extern pv_elem_t *ruri_param_model; /*!< pv-string to get r-uri */
- static unsigned int CURR_DLG_LIFETIME = 0; /*!< current dialog lifetime */
- static unsigned int CURR_DLG_STATUS = 0; /*!< current dialog state */
- static unsigned int CURR_DLG_ID = 0xffffffff; /*!< current dialog id */
- /*! size of the dialog record-route parameter */
- #define RR_DLG_PARAM_SIZE (2*2*sizeof(int)+3+MAX_DLG_RR_PARAM_NAME)
- /*! separator inside the record-route paramter */
- #define DLG_SEPARATOR '.'
- /*!
- * \brief Initialize the dialog handlers
- * \param rr_param_p added record-route parameter
- * \param dlg_flag_p dialog flag
- * \param timeout_avp_p AVP for timeout setting
- * \param default_timeout_p default timeout
- * \param seq_match_mode_p matching mode
- */
- void init_dlg_handlers(char *rr_param_p, int dlg_flag_p, pv_spec_t *timeout_avp_p, int default_timeout_p, int seq_match_mode_p) {
- rr_param.s = rr_param_p;
- rr_param.len = strlen(rr_param.s);
- dlg_flag = 1 << dlg_flag_p;
- timeout_avp = timeout_avp_p;
- default_timeout = default_timeout_p;
- seq_match_mode = seq_match_mode_p;
- }
- /*!
- * \brief Shutdown operation of the module
- */
- void destroy_dlg_handlers(void) {
- shutdown_done = 1;
- }
- /*!
- * \brief Add record-route parameter for dialog tracking
- * \param req SIP request
- * \param entry dialog hash entry
- * \param id dialog hash id
- * \return 0 on success, -1 on failure
- */
- static inline int add_dlg_rr_param(struct dlg_cell *dlg, struct sip_msg *req, unsigned int entry, unsigned int id) {
- static char buf[RR_DLG_PARAM_SIZE];
- str s;
- int n;
- char *p;
- s.s = p = buf;
- *(p++) = ';';
- memcpy(p, rr_param.s, rr_param.len);
- p += rr_param.len;
- *(p++) = '=';
- char *did = p;
- n = RR_DLG_PARAM_SIZE - (p - buf);
- if (int2reverse_hex(&p, &n, entry) == -1)
- return -1;
- *(p++) = DLG_SEPARATOR;
- n = RR_DLG_PARAM_SIZE - (p - buf);
- if (int2reverse_hex(&p, &n, id) == -1)
- return -1;
- s.len = p - buf;
- if (d_rrb.add_rr_param(req, &s) < 0) {
- LM_ERR("failed to add rr param\n");
- return -1;
- }
- //add the did into the dlg structure
- int did_len = p - did;
- if (dlg->did.s) {
- if (dlg->did.len < did_len) {
- shm_free(dlg->did.s);
- dlg->did.s = (char*) shm_malloc(did_len);
- if (dlg->did.s == NULL) {
- LM_ERR("failed to add did to dlg_cell struct\n");
- return -1;
- }
- }
- } else {
- dlg->did.s = (char*) shm_malloc(did_len);
- if (dlg->did.s == NULL) {
- LM_ERR("failed to add did to dlg_cell struct\n");
- return -1;
- }
- }
- memcpy(dlg->did.s, did, did_len);
- dlg->did.len = did_len;
- return 0;
- }
- /*!
- * \brief Parse SIP message and populate leg informations
- *
- * Parse SIP message and populate leg informations.
- * \param dlg the dialog to add cseq, contact & record_route
- * \param msg sip message
- * \param t transaction
- * \param leg type of the call leg
- * \param tag SIP To tag
- * \return 0 on success, -1 on failure
- * \note for a request: get record route in normal order, for a reply get
- * in reverse order, skipping the ones from the request and the proxies' own
- */
- int populate_leg_info(struct dlg_cell *dlg, struct sip_msg *msg,
- struct cell* t, unsigned int leg, str *tag) {
- unsigned int skip_recs;
- str cseq;
- str contact;
- str rr_set;
- struct socket_info* callee_bind_address = NULL;
- if (leg == DLG_CALLER_LEG)
- dlg->caller_bind_addr = msg->rcv.bind_address;
- else
- callee_bind_address = msg->rcv.bind_address;
- /* extract the cseq number as string from the request or response*/
- //TO DO - can pair the cseqs here to make sure that the response and request are in sync
- if ((!msg->cseq && (parse_headers(msg, HDR_CSEQ_F, 0) < 0 || !msg->cseq))
- || !msg->cseq->parsed) {
- LM_ERR("bad sip message or missing CSeq hdr :-/\n");
- goto error0;
- }
- cseq = (get_cseq(msg))->number;
- /* extract the contact address */
- if (!msg->contact && (parse_headers(msg, HDR_CONTACT_F, 0) < 0 || !msg->contact)) {
- LM_ERR("bad sip message or missing Contact hdr\n");
- goto error0;
- }
- if (parse_contact(msg->contact) < 0 ||
- ((contact_body_t *) msg->contact->parsed)->contacts == NULL ||
- ((contact_body_t *) msg->contact->parsed)->contacts->next != NULL) {
- LM_ERR("bad Contact HDR\n");
- goto error0;
- }
- contact = ((contact_body_t *) msg->contact->parsed)->contacts->uri;
- /* extract the RR parts */
- if (!msg->record_route && (parse_headers(msg, HDR_EOH_F, 0) < 0)) {
- LM_ERR("failed to parse record route header\n");
- goto error0;
- }
- if (leg == DLG_CALLER_LEG) {
- skip_recs = 0;
- } else {
- skip_recs = 0;
- /* was the 200 OK received or local generated */
- /*skip_recs = dlg->from_rr_nb +
- ((t->relayed_reply_branch >= 0) ?
- ((t->uac[t->relayed_reply_branch].flags & TM_UAC_FLAG_R2) ? 2 :
- ((t->uac[t->relayed_reply_branch].flags & TM_UAC_FLAG_RR) ? 1 : 0))
- : 0);
- * */
- }
- if (msg->record_route) {
- if (print_rr_body(msg->record_route, &rr_set, leg,
- &skip_recs) != 0) {
- LM_ERR("failed to print route records \n");
- goto error0;
- }
- } else {
- rr_set.s = 0;
- rr_set.len = 0;
- }
- if (leg == DLG_CALLER_LEG)
- dlg->from_rr_nb = skip_recs;
- LM_DBG("route_set %.*s, contact %.*s, cseq %.*s and bind_addr %.*s\n",
- rr_set.len, rr_set.s, contact.len, contact.s,
- cseq.len, cseq.s,
- msg->rcv.bind_address->sock_str.len,
- msg->rcv.bind_address->sock_str.s);
- if (dlg_set_leg_info(dlg, tag, &rr_set, &contact, &cseq, callee_bind_address, leg) != 0) {
- LM_ERR("dlg_set_leg_info failed\n");
- if (rr_set.s) pkg_free(rr_set.s);
- goto error0;
- }
- if (rr_set.s) pkg_free(rr_set.s);
- return 0;
- error0:
- return -1;
- }
- /*!
- * \brief Function that executes BYE reply callbacks
- * \param t transaction, unused
- * \param type type of the callback, should be TMCB_RESPONSE_FWDED
- * \param param saved dialog structure inside the callback
- */
- static void dlg_terminated_confirmed(struct cell* t,
- int type,
- struct tmcb_params* params) {
- if (!params || !params->req || !params->param) {
- LM_ERR("invalid parameters!\n");
- return;
- }
- struct dlg_cell* dlg = (struct dlg_cell*) *params->param;
- if (!dlg) {
- LM_ERR("failed to get dialog from params!\n");
- return;
- }
- /* dialog termination confirmed (BYE reply) */
- run_dlg_callbacks(DLGCB_TERMINATED_CONFIRMED,
- dlg,
- params->req,
- params->rpl,
- DLG_DIR_UPSTREAM,
- 0);
- }
- /*!
- * \brief Execute callback for the BYE request and register callback for the BYE reply
- * \param req request message
- * \param dlg corresponding dialog
- * \param dir message direction
- */
- static void dlg_terminated(struct sip_msg* req,
- struct dlg_cell* dlg,
- unsigned int dir) {
- if (!req) {
- LM_ERR("request is empty!");
- return;
- }
- if (!dlg) {
- LM_ERR("dialog is empty!");
- return;
- }
- /* dialog terminated (BYE) */
- run_dlg_callbacks(DLGCB_TERMINATED, dlg, req, NULL, dir, 0);
- /* register callback for the coresponding reply */
- LM_DBG("Registering tmcb1\n");
- if (d_tmb.register_tmcb(req,
- 0,
- TMCB_RESPONSE_OUT,
- dlg_terminated_confirmed,
- (void*) dlg,
- 0) <= 0) {
- LM_ERR("cannot register response callback for BYE request\n");
- return;
- }
- }
- static void unlink_dlgouts_from_cb(struct cell* t, int type, struct tmcb_params *param) {
- struct dlg_cell *dlg = (struct dlg_cell *) (*param->param);
- if (!dlg)
- return;
- if (t && t->fwded_totags && t->fwded_totags->tag.len > 0) {
- LM_DBG("unlink_dlgouts_from_cb: transaction [%.*s] can now be removed IFF it has been marked for deletion\n", t->fwded_totags->tag.len, t->fwded_totags->tag.s);
- dlg_remove_dlg_out_tag(dlg, &t->fwded_totags->tag);
- }
- }
- /*!
- * \brief Function that is registered as TM callback and called on replies
- *
- * Function that is registered as TM callback and called on replies. It
- * parses the reply and set the appropriate event. This is then used to
- * update the dialog state, run eventual dialog callbacks and save or
- * update the necessary informations about the dialog.
- * \see next_state_dlg
- * \param t transaction, unused
- * \param type type of the entered callback
- * \param param saved dialog structure in the callback
- */
- static void dlg_onreply(struct cell* t, int type, struct tmcb_params *param) {
- struct dlg_cell *dlg;
- struct dlg_cell_out *dlg_out = 0;
- int new_state, old_state, unref, event;
- str to_tag, to_uri;
- struct sip_msg *req = param->req;
- struct sip_msg *rpl = param->rpl;
- struct dlg_entry_out* dlg_entry_out = 0;
- if (t && t->fwded_totags)
- LM_DBG("ONREPLY CALL_BACK from TM received and type is [%i] and TO is [%.*s]\n", type, t->fwded_totags->tag.len, t->fwded_totags->tag.s);
- else
- LM_DBG("ONREPLY CALL_BACK from TM received and type is [%i]\n", type);
- dlg = (struct dlg_cell *) (*param->param);
- if (shutdown_done || dlg == 0)
- return;
- if (t) {
- dlg->transaction = t;
- }
- LM_DBG("DLG dialogid is entry:id [%i:%i]\n", dlg->h_entry, dlg->h_id);
- if (type == TMCB_RESPONSE_FWDED) {
- // The state does not change, but the msg is mutable in this callback
- LM_DBG("TMCB_RESPONSE_FWDED from TM received");
- run_dlg_callbacks(DLGCB_RESPONSE_FWDED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
- return;
- }
- if (type == TMCB_RESPONSE_OUT) {
- LM_DBG("TMCB_RESPONSE_OUT\n");
- return;
- }
- if (type == TMCB_RESPONSE_READY) {
- if (rpl == FAKED_REPLY) {
- LM_DBG("Faked reply\n");
- return;
- }
- // get to tag
- LM_DBG("Extracting to-tag from reply");
- if (!rpl->to && ((parse_headers(rpl, HDR_TO_F, 0) < 0) || !rpl->to)) {
- LM_ERR("bad reply or missing TO hdr :-/\n");
- to_tag.s = 0;
- to_tag.len = 0;
- } else {
- //populate to uri for this branch.
- to_uri = get_to(rpl)->uri;
- to_tag = get_to(rpl)->tag_value;
- if (to_tag.s == 0 || to_tag.len == 0) {
- LM_ERR("missing TAG param in TO hdr :-/\n");
- to_tag.s = 0;
- to_tag.len = 0;
- //Here we assume that the transaction module timer will remove any early dialogs
- return;
- }
- }
- LM_DBG("Got to-tag from response: %.*s \n", to_tag.len, to_tag.s);
- }
- if (type == TMCB_DESTROY)
- event = DLG_EVENT_TDEL;
- else if (param->code < 200)
- event = DLG_EVENT_RPL1xx;
- else if (param->code < 300)
- event = DLG_EVENT_RPL2xx;
- else
- event = DLG_EVENT_RPL3xx;
- LM_DBG("Calling next_state_dlg and event is %i\n", event);
- next_state_dlg(dlg, event, &old_state, &new_state, &unref, &to_tag);
- if (type == TMCB_RESPONSE_READY) {
- LM_DBG("Checking if there is an existing dialog_out entry with same to-tag");
- dlg_entry_out = &dlg->dlg_entry_out;
- lock_get(dlg->dlg_out_entries_lock);
- dlg_out = dlg_entry_out->first;
- LM_DBG("Scanning dlg_entry_out list for dlg_out");
- while (dlg_out) {
- //Check if there is an already dialog_out entry with same To-tag
- if (dlg_out->to_tag.len == to_tag.len &&
- memcmp(dlg_out->to_tag.s, to_tag.s, dlg_out->to_tag.len) == 0) {
- //Found a dialog_out entry with same to_tag!
- LM_DBG("Found dlg_out for to-tag: %.*s\n", dlg_out->to_tag.len, dlg_out->to_tag.s);
- break;
- }
- dlg_out = dlg_out->next;
- }
- lock_release(dlg->dlg_out_entries_lock);
- if (!dlg_out) {
- LM_DBG("No dlg_out entry found - creating a new dialog_out entry on dialog [%p]\n", dlg);
- dlg_out = build_new_dlg_out(dlg, &to_uri, &to_tag);
- link_dlg_out(dlg, dlg_out, 0);
- /* save callee's cseq, caller cseq, callee contact and callee record route*/
- if (populate_leg_info(dlg, rpl, t, DLG_CALLEE_LEG, &to_tag) != 0) {
- LM_ERR("could not add further info to the dlg out\n");
- }
- if (!dlg_out) {
- LM_ERR("failed to create new dialog out structure\n");
- //TODO do something on this error!
- }
- } else {
- //This dlg_out already exists, update cseq and contact if present
- LM_DBG("dlg_out entry found - updating cseq's for dialog out [%p] for to-tag [%.*s] \n", dlg_out, dlg_out->to_tag.len, dlg_out->to_tag.s);
- if ((!rpl->cseq && parse_headers(rpl, HDR_CSEQ_F, 0) < 0) || !rpl->cseq ||
- !rpl->cseq->parsed) {
- LM_ERR("bad sip message or missing CSeq hdr :-/\n");
- }
- dlg_update_cseq(dlg, DLG_CALLEE_LEG, &((get_cseq(rpl))->number), &(dlg_out->to_tag));
- /* extract the contact address to update if present*/
- if (!rpl->contact && (parse_headers(rpl, HDR_CONTACT_F, 0) < 0 || !rpl->contact)) {
- LM_ERR("Can not update callee contact: bad sip message or missing Contact hdr\n");
- }
- else if (parse_contact(rpl->contact) < 0 ||
- ((contact_body_t *) rpl->contact->parsed)->contacts == NULL ||
- ((contact_body_t *) rpl->contact->parsed)->contacts->next != NULL) {
- LM_ERR("Can not update callee contact: bad Contact HDR\n");
- }
- else
- {
- str contact;
- contact = ((contact_body_t *) rpl->contact->parsed)->contacts->uri;
- dlg_update_contact(dlg, DLG_CALLEE_LEG, &contact, &(dlg_out->to_tag));
- }
- }
- }
- if (new_state == DLG_STATE_EARLY) {
- if ((dlg->dflags & DLG_FLAG_INSERTED) == 0) {
- dlg->dflags |= DLG_FLAG_NEW;
- } else {
- dlg->dflags |= DLG_FLAG_CHANGED;
- }
- if (dlg_db_mode == DB_MODE_REALTIME)
- update_dialog_dbinfo(dlg);
- run_dlg_callbacks(DLGCB_EARLY, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
- return;
- }
- LM_DBG("new state is %i and old state is %i\n", new_state, old_state);
- if ((new_state == DLG_STATE_CONFIRMED) && (event == DLG_EVENT_RPL2xx)) {
- LM_DBG("dialog %p confirmed \n", dlg);
- //Remove all the other entries in dialog_out for the same dialog after TM expires the transaction
- //(not before in order to absorb late in-early-dialog requests).
- //remove all other dlg_out objects
- if (dlg_out) {
- if (d_tmb.register_tmcb(req, NULL, TMCB_DESTROY, unlink_dlgouts_from_cb, (void*) dlg, NULL) < 0) {
- LM_ERR("failed to register deletion delay function\n");
- LM_DBG("Removing all other DLGs");
- dlg_remove_dlg_out(dlg_out, dlg, 0);
- } else {
- //mark the outs for deletion
- dlg_remove_dlg_out(dlg_out, dlg, 1);
- }
- } else {
- LM_ERR("There is no dlg_out structure - this is bad\n");
- //TODO: add error handling here
- }
- /* set start time */
- dlg->start_ts = (unsigned int) (time(0));
- /* save the settings to the database,
- * if realtime saving mode configured- save dialog now
- * else: the next time the timer will fire the update*/
- if ((dlg->dflags & DLG_FLAG_INSERTED) == 0) {
- dlg->dflags |= DLG_FLAG_NEW;
- } else {
- dlg->dflags |= DLG_FLAG_CHANGED;
- }
- if (dlg_db_mode == DB_MODE_REALTIME)
- update_dialog_dbinfo(dlg);
-
- if (0 != insert_dlg_timer(&dlg->tl, dlg->lifetime)) {
- LM_CRIT("Unable to insert dlg %p [%u:%u] on event %d [%d->%d] "
- "with clid '%.*s' and tags '%.*s' \n",
- dlg, dlg->h_entry, dlg->h_id, event, old_state, new_state,
- dlg->callid.len, dlg->callid.s,
- dlg->from_tag.len, dlg->from_tag.s);
- } else {
- ref_dlg(dlg, 1);
- }
- run_dlg_callbacks(DLGCB_CONFIRMED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
- if (unref) unref_dlg(dlg, unref);
- return;
- }
- if (new_state == DLG_STATE_CONCURRENTLY_CONFIRMED && (old_state == DLG_STATE_CONFIRMED || old_state == DLG_STATE_CONCURRENTLY_CONFIRMED)) {
- //This is a concurrently confirmed call
- LM_DBG("This is a concurrently confirmed call.");
- //Create a new Dialog ID token “X”
- //Not sure how to do this so just going to use existing Did and add an X character to it
- str new_did;
- create_concurrent_did(dlg, &new_did);
- //assign new did to the created or updated dialog_out entry.
- update_dlg_out_did(dlg_out, &new_did);
- //Then, duplicate the dialog_in entry and set its Dialog ID value to new_did
- //for now rather just create new dlg structure with the correct params - this should be fixed if future use requires
- struct dlg_cell *new_dlg = 0;
- new_dlg = build_new_dlg(&(dlg->callid) /*callid*/,
- &(dlg->from_uri) /*from uri*/,
- &(dlg->from_tag)/*from_tag*/,
- &(dlg->req_uri) /*r-uri*/);
- //assign new did to dlg_in
- update_dlg_did(new_dlg, &new_did);
- if (new_dlg == 0) {
- LM_ERR("failed to create new dialog\n");
- return;
- }
- //link the new_dlg with dlg_out object
- link_dlg_out(new_dlg, dlg_out, 0);
- }
- if (old_state != DLG_STATE_DELETED && new_state == DLG_STATE_DELETED) {
- LM_DBG("dialog %p failed (negative reply)\n", dlg);
- /* dialog setup not completed (3456XX) */
- run_dlg_callbacks(DLGCB_FAILED, dlg, req, rpl, DLG_DIR_UPSTREAM, 0);
- /* do unref */
- if (unref)
- unref_dlg(dlg, unref);
- return;
- }
- if (unref) unref_dlg(dlg, unref);
- return;
- }
- /*!
- * \brief Helper function that run dialog callbacks on forwarded requests
- * \see dlg_seq_up_onreply
- * \see dlg_seq_down_onreply
- * \param t transaction, unused
- * \param type type of the callback, should be TMCB_RESPONSE_FWDED
- * \param param saved dialog structure inside the callback
- * \param direction direction of the request
- */
- static void dlg_seq_onreply_helper(struct cell* t, int type,
- struct tmcb_params *param, const int direction) {
- struct dlg_cell *dlg;
- dlg = (struct dlg_cell *) (*param->param);
- if (shutdown_done || dlg == 0)
- return;
- if (type == TMCB_RESPONSE_FWDED) {
- run_dlg_callbacks(DLGCB_RESPONSE_WITHIN,
- dlg,
- param->req,
- param->rpl,
- direction,
- 0);
- return;
- }
- return;
- }
- /*!
- * \brief Run dialog callbacks on forwarded requests in upstream direction
- * \see dlg_seq_onreply_helper
- * \param t transaction, unused
- * \param type type of the callback, should be TMCB_RESPONSE_FWDED
- * \param param saved dialog structure inside the callback
- */
- static void dlg_seq_up_onreply(struct cell* t, int type, struct tmcb_params *param) {
- return dlg_seq_onreply_helper(t, type, param, DLG_DIR_UPSTREAM);
- }
- /*!
- * \brief Run dialog callbacks on forwarded requests in downstream direction
- * \see dlg_seq_onreply_helper
- * \param t transaction, unused
- * \param type type of the callback, should be TMCB_RESPONSE_FWDED
- * \param param saved dialog structure inside the callback
- */
- static void dlg_seq_down_onreply(struct cell* t, int type, struct tmcb_params *param) {
- return dlg_seq_onreply_helper(t, type, param, DLG_DIR_DOWNSTREAM);
- }
- /*!
- * \brief Return the timeout for a dialog
- * \param req SIP message
- * \return value from timeout AVP if present or default timeout
- */
- inline static int get_dlg_timeout(struct sip_msg *req) {
- pv_value_t pv_val;
- if (timeout_avp) {
- if (pv_get_spec_value(req, timeout_avp, &pv_val) == 0 &&
- pv_val.flags & PV_VAL_INT && pv_val.ri > 0) {
- return pv_val.ri;
- }
- LM_DBG("invalid AVP value, using default timeout\n");
- }
- return default_timeout;
- }
- /*!
- * \brief Helper function to get the necessary content from SIP message
- * \param req SIP request
- * \param callid found callid
- * \param ftag found from tag
- * \param ttag found to tag
- * \param with_ttag flag set if to tag must be found for success
- * \return 0 on success, -1 on failure
- */
- static inline int pre_match_parse(struct sip_msg *req, str *callid,
- str *ftag, str *ttag, int with_ttag) {
- if (parse_headers(req, HDR_CALLID_F | HDR_TO_F, 0) < 0 || !req->callid ||
- !req->to) {
- LM_ERR("bad request or missing CALLID/TO hdr :-/\n");
- return -1;
- }
- if (get_to(req)->tag_value.len == 0) {
- if (with_ttag == 1) {
- /* out of dialog request with preloaded Route headers; ignore. */
- return -1;
- } else {
- ttag->s = NULL;
- ttag->len = 0;
- }
- } else {
- *ttag = get_to(req)->tag_value;
- }
- if (parse_from_header(req) < 0 || get_from(req)->tag_value.len == 0) {
- LM_ERR("failed to get From header\n");
- return -1;
- }
- /* callid */
- *callid = req->callid->body;
- trim(callid);
- /* from tag */
- *ftag = get_from(req)->tag_value;
- return 0;
- }
- /*!
- * \brief Function that is registered as TM callback and called on requests
- * \see dlg_new_dialog
- * \param t transaction, used to created the dialog
- * \param type type of the entered callback
- * \param param saved dialog structure in the callback
- */
- void dlg_onreq(struct cell* t, int type, struct tmcb_params *param) {
- struct sip_msg *req = param->req;
- if ((req->flags & dlg_flag) != dlg_flag)
- return;
- if (current_dlg_pointer != NULL)
- return;
- dlg_new_dialog(req, t, 1);
- }
- /*!
- * \brief Unreference a new dialog, helper function for dlg_onreq
- * \see dlg_onreq
- * \param dialog unreferenced dialog
- */
- static void unref_new_dialog(void *dialog) {
- struct tmcb_params p;
- memset(&p, 0, sizeof (struct tmcb_params));
- p.param = (void*) &dialog;
- dlg_onreply(0, TMCB_DESTROY, &p);
- }
- /*!
- * \brief Unreference a dialog (small wrapper to take care of shutdown)
- * \see unref_dlg
- * \param dialog unreferenced dialog
- */
- static void unreference_dialog(void *dialog) {
- // if the dialog table is gone, it means the system is shutting down.
- if (!dialog || !d_table)
- return;
- unref_dlg((struct dlg_cell*) dialog, 1);
- }
- /*!
- * \brief Dummy callback just to keep the compiler happy
- * \param t unused
- * \param type unused
- * \param param unused
- */
- void dlg_tmcb_dummy(struct cell* t, int type, struct tmcb_params *param) {
- return;
- }
- /*!
- * \brief Register a transaction on a dialog
- * \param t transaction
- * \param type type of the entered callback
- * \param param saved dialog structure in the callback
- */
- static int store_dlg_in_tm(struct sip_msg* msg,
- struct cell* t,
- struct dlg_cell *dlg) {
- if (!msg || msg == FAKED_REPLY || !t || !dlg) {
- LM_ERR("invalid parameter msg(%p), t(%p), dlg(%p)\n", msg, t, dlg);
- return -1;
- }
- if (get_dialog_from_tm(t)) {
- LM_NOTICE("dialog %p is already set for this transaction!\n", dlg);
- return 1;
- }
- // facilitate referencing of dialog through TMCB_MAX
- if (d_tmb.register_tmcb(msg,
- t,
- TMCB_MAX,
- dlg_tmcb_dummy,
- (void*) dlg, unreference_dialog) < 0) {
- LM_ERR("failed cache in T the shortcut to dlg %p\n", dlg);
- return -3;
- }
- // registering succeeded, we must increase the reference counter
- ref_dlg(dlg, 1);
- return 0;
- }
- /*!
- * \brief Callback to register a transaction on a dialog
- * \param t transaction, unused
- * \param type type of the entered callback
- * \param param saved dialog structure in the callback
- */
- static void store_dlg_in_tm_cb(struct cell* t,
- int type,
- struct tmcb_params *param) {
- struct dlg_cell *dlg = (struct dlg_cell *) (*param->param);
- struct sip_msg* msg = param->rpl;
- if (msg == NULL || msg == FAKED_REPLY) {
- msg = param->req;
- }
- store_dlg_in_tm(msg, t, dlg);
- }
- /*!
- * \brief Create a new dialog from a sip message
- *
- * Create a new dialog from a SIP message, register a callback
- * to keep track of the dialog with help of the tm module.
- * This function is either called from the request callback, or
- * from the dlg_manage function in the configuration script.
- * \see dlg_onreq
- * \see w_dlg_manage
- * \param msg SIP message
- * \param t transaction
- * \return 0 on success, -1 on failure
- */
- int dlg_new_dialog(struct sip_msg *req, struct cell *t, const int run_initial_cbs) {
- struct dlg_cell *dlg;
- str s;
- str callid;
- str ftag;
- str ttag;
- str req_uri;
- unsigned int dir;
- LM_DBG("starting dlg_new_dialog and method is [%.*s]\n", req->first_line.u.request.method.len, req->first_line.u.request.method.s);
- if (current_dlg_pointer != NULL)
- return -1;
- if (req->first_line.u.request.method_value == METHOD_CANCEL)
- return -1;
- if (pre_match_parse(req, &callid, &ftag, &ttag, 0) < 0) {
- LM_WARN("pre-matching failed\n");
- return -1;
- }
- if (ttag.s != 0 && ttag.len != 0)
- return -1;
- if (pv_printf_s(req, ruri_param_model, &req_uri) < 0) {
- LM_ERR("error - cannot print the r-uri format\n");
- return -1;
- }
- trim(&req_uri);
- if (detect_spirals) {
- if (spiral_detected == 1)
- return 0;
- dir = DLG_DIR_NONE;
- dlg = get_dlg(&callid, &ftag, &ttag, &dir);
- if (dlg) {
- LM_DBG("Callid '%.*s' found, must be a spiraled request\n",
- callid.len, callid.s);
- spiral_detected = 1;
- if (run_initial_cbs)
- run_dlg_callbacks(DLGCB_SPIRALED, dlg, req, NULL, DLG_DIR_DOWNSTREAM, 0);
- //Add did to rr header for all spiralled requested INVITEs
- if (req->first_line.u.request.method_value == METHOD_INVITE) {
- if (add_dlg_rr_param(dlg, req, dlg->h_entry, dlg->h_id) < 0) {
- LM_ERR("failed to add RR param\n");
- }
- }
- // get_dlg has incremented the ref count by 1
- unref_dlg(dlg, 1);
- goto finish;
- }
- }
- spiral_detected = 0;
- LM_DBG("Building new Dialog for call-id %.*s\n", callid.len, callid.s);
- LM_DBG("SIP Method: %.*s \n", req->first_line.u.request.method.len, req->first_line.u.request.method.s);
- dlg = build_new_dlg(&callid /*callid*/,
- &(get_from(req)->uri) /*from uri*/,
- &ftag/*from_tag*/,
- &req_uri /*r-uri*/);
- if (dlg == 0) {
- LM_ERR("failed to create new dialog\n");
- return -1;
- }
- /* save caller's tag, cseq, contact and record route*/
- if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG,
- &(get_from(req)->tag_value)) != 0) {
- LM_ERR("could not add further info to the dialog\n");
- lock_destroy(dlg->dlg_out_entries_lock);
- lock_dealloc(dlg->dlg_out_entries_lock);
- shm_free(dlg);
- return -1;
- }
- dlg->transaction = t;
- /* Populate initial varlist: */
- dlg->vars = get_local_varlist_pointer(req, 1);
- link_dlg(dlg, 0);
- if (run_initial_cbs) run_create_callbacks(dlg, req);
- //Dialog will *always* use DID cookie so no need for match mode anymore
- if (add_dlg_rr_param(dlg, req, dlg->h_entry, dlg->h_id) < 0) {
- LM_ERR("failed to add RR param\n");
- goto error;
- }
- if (d_tmb.register_tmcb(req, t,
- TMCB_RESPONSE_READY | TMCB_RESPONSE_FWDED | TMCB_RESPONSE_OUT,
- dlg_onreply, (void*) dlg, unref_new_dialog) < 0) {
- LM_ERR("failed to register TMCB\n");
- goto error;
- }
- // increase reference counter because of registered callback
- ref_dlg(dlg, 1);
- dlg->lifetime = get_dlg_timeout(req);
- s.s = _dlg_ctx.to_route_name;
- s.len = strlen(s.s);
- dlg_set_toroute(dlg, &s);
- dlg->sflags |= _dlg_ctx.flags;
- if (_dlg_ctx.to_bye != 0)
- dlg->dflags |= DLG_FLAG_TOBYE;
- finish:
- if (t) {
- // transaction exists ==> keep ref counter large enough to
- // avoid premature cleanup and ensure proper dialog referencing
- if (store_dlg_in_tm(req, t, dlg) < 0) {
- LM_ERR("failed to store dialog in transaction\n");
- goto error;
- }
- } else {
- // no transaction exists ==> postpone work until we see the
- // request being forwarded statefully
- if (d_tmb.register_tmcb(req, NULL, TMCB_REQUEST_FWDED,
- store_dlg_in_tm_cb, (void*) dlg, NULL) < 0) {
- LM_ERR("failed to register callback for storing dialog in transaction\n");
- goto error;
- }
- }
- LM_DBG("Setting current dialog\n");
- set_current_dialog(req, dlg);
- _dlg_ctx.dlg = dlg;
- ref_dlg(dlg, 1);
- return 0;
- error:
- LM_DBG("Error in build_new_dlg");
- if (!spiral_detected)
- unref_dlg(dlg, 1); // undo ref regarding linking
- return -1;
- }
- /*!
- * \brief Parse the record-route parameter, to get dialog information back
- * \param p start of parameter string
- * \param end end of parameter string
- * \param h_entry found dialog hash entry
- * \param h_id found dialog hash id
- * \return 0 on success, -1 on failure
- */
- static inline int parse_dlg_rr_param(char *p, char *end, int *h_entry, int *h_id) {
- char *s;
- for (s = p; p < end && *p != DLG_SEPARATOR; p++);
- if (*p != DLG_SEPARATOR) {
- LM_ERR("malformed rr param '%.*s'\n", (int) (long) (end - s), s);
- return -1;
- }
- if (reverse_hex2int(s, p - s, (unsigned int*) h_entry) < 0) {
- LM_ERR("invalid hash entry '%.*s'\n", (int) (long) (p - s), s);
- return -1;
- }
- if (reverse_hex2int(p + 1, end - (p + 1), (unsigned int*) h_id) < 0) {
- LM_ERR("invalid hash id '%.*s'\n", (int) (long) (end - (p + 1)), p + 1);
- return -1;
- }
- return 0;
- }
- /*!
- * \brief Update the saved CSEQ information in dialog from SIP message
- * \param dlg updated dialog
- * \param req SIP request
- * \param dir direction of request, must DLG_DIR_UPSTREAM or DLG_DIR_DOWNSTREAM
- * \return 0 on success, -1 on failure
- */
- static inline int update_cseqs(struct dlg_cell *dlg, struct sip_msg *req,
- unsigned int dir, str *to_tag) {
- if ((!req->cseq && parse_headers(req, HDR_CSEQ_F, 0) < 0) || !req->cseq ||
- !req->cseq->parsed) {
- LM_ERR("bad sip message or missing CSeq hdr :-/\n");
- return -1;
- }
- if (dir == DLG_DIR_UPSTREAM) {
- return dlg_update_cseq(dlg, DLG_CALLEE_LEG, &((get_cseq(req))->number), to_tag);
- } else if (dir == DLG_DIR_DOWNSTREAM) {
- return dlg_update_cseq(dlg, DLG_CALLER_LEG, &((get_cseq(req))->number), to_tag);
- } else {
- LM_CRIT("dir is not set!\n");
- return -1;
- }
- }
- /*!
- * \brief Function that is registered as RR callback for dialog tracking
- *
- * Function that is registered as RR callback for dialog tracking. It
- * sets the appropriate events after the SIP method and run the state
- * machine to update the dialog state. It updates then the saved
- * dialogs and also the statistics.
- * \param req SIP request
- * \param route_params record-route parameter
- * \param param unused
- */
- void dlg_onroute(struct sip_msg* req, str *route_params, void *param) {
- struct dlg_cell *dlg;
- str val, callid, ftag, ttag;
- int h_entry, h_id, new_state, old_state, unref, event, timeout;
- unsigned int dir;
- int ret = 0;
- if (current_dlg_pointer != NULL)
- return;
- /* skip initial requests - they may end up here because of the
- * preloaded route */
- if ((!req->to && parse_headers(req, HDR_TO_F, 0) < 0) || !req->to) {
- LM_ERR("bad request or missing TO hdr :-/\n");
- return;
- }
- if (get_to(req)->tag_value.len == 0)
- return;
- dlg = 0;
- dir = DLG_DIR_NONE;
- if (seq_match_mode != SEQ_MATCH_NO_ID) {
- if (d_rrb.get_route_param(req, &rr_param, &val) != 0) {
- LM_DBG("Route param '%.*s' not found\n", rr_param.len, rr_param.s);
- if (seq_match_mode == SEQ_MATCH_STRICT_ID)
- return;
- } else {
- LM_DBG("route param is '%.*s' (len=%d)\n", val.len, val.s, val.len);
- if (parse_dlg_rr_param(val.s, val.s + val.len, &h_entry, &h_id) < 0)
- return;
- dlg = lookup_dlg(h_entry, h_id);
- if (dlg == 0) {
- LM_WARN("unable to find dialog for %.*s "
- "with route param '%.*s' [%u:%u]\n",
- req->first_line.u.request.method.len,
- req->first_line.u.request.method.s,
- val.len, val.s, h_entry, h_id);
- if (seq_match_mode == SEQ_MATCH_STRICT_ID)
- return;
- } else {
- if (pre_match_parse(req, &callid, &ftag, &ttag, 1) < 0) {
- // lookup_dlg has incremented the ref count by 1
- unref_dlg(dlg, 1);
- return;
- }
- if (match_dialog(dlg, &callid, &ftag, &ttag, &dir) == 0) {
- LM_WARN("tight matching failed for %.*s with callid='%.*s'/%d, "
- "ftag='%.*s'/%d, ttag='%.*s'/%d and direction=%d\n",
- req->first_line.u.request.method.len,
- req->first_line.u.request.method.s,
- callid.len, callid.s, callid.len,
- ftag.len, ftag.s, ftag.len,
- ttag.len, ttag.s, ttag.len, dir);
- LM_WARN("dialog identification elements are callid='%.*s'/%d, "
- "caller tag='%.*s'/%d\n",
- dlg->callid.len, dlg->callid.s, dlg->callid.len,
- dlg->from_tag.len, dlg->from_tag.s,
- dlg->from_tag.len);
- // lookup_dlg has incremented the ref count by 1
- unref_dlg(dlg, 1);
- // Reset variables in order to do a lookup based on SIP-Elements.
- dlg = 0;
- dir = DLG_DIR_NONE;
- if (seq_match_mode == SEQ_MATCH_STRICT_ID)
- return;
- }
- }
- }
- }
- if (dlg == 0) {
- if (pre_match_parse(req, &callid, &ftag, &ttag, 1) < 0)
- return;
- /* TODO - try to use the RR dir detection to speed up here the
- * search -bogdan */
- dlg = get_dlg(&callid, &ftag, &ttag, &dir);
- if (!dlg) {
- LM_DBG("Callid '%.*s' not found\n",
- req->callid->body.len, req->callid->body.s);
- return;
- }
- }
- /* set current dialog - re-use ref increment from dlg_get() above */
- set_current_dialog(req, dlg);
- _dlg_ctx.dlg = dlg;
- if (d_tmb.register_tmcb(req, NULL, TMCB_REQUEST_FWDED,
- store_dlg_in_tm_cb, (void*) dlg, NULL) < 0) {
- LM_ERR("failed to store dialog in transaction during dialog creation for later reference\n");
- }
- /* run state machine */
- switch (req->first_line.u.request.method_value) {
- case METHOD_PRACK:
- event = DLG_EVENT_REQPRACK;
- break;
- case METHOD_ACK:
- event = DLG_EVENT_REQACK;
- break;
- case METHOD_BYE:
- event = DLG_EVENT_REQBYE;
- break;
- default:
- event = DLG_EVENT_REQ;
- }
- next_state_dlg(dlg, event, &old_state, &new_state, &unref, 0);
- LM_DBG("unref after next state is %i\n", unref);
- CURR_DLG_ID = req->id;
- CURR_DLG_LIFETIME = (unsigned int) (time(0)) - dlg->start_ts;
- CURR_DLG_STATUS = new_state;
- /* run actions for the transition */
- if (event == DLG_EVENT_REQBYE && new_state == DLG_STATE_DELETED &&
- old_state != DLG_STATE_DELETED) {
- LM_DBG("BYE successfully processed\n");
- /* remove from timer */
- 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_WARN("inconsitent dlg timer data 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 {
- unref++;
- }
- /* dialog terminated (BYE) */
- dlg_terminated(req, dlg, dir);
- unref_dlg(dlg, unref);
- return;
- }
- if ((event == DLG_EVENT_REQ || event == DLG_EVENT_REQACK)
- && new_state == DLG_STATE_CONFIRMED) {
- timeout = get_dlg_timeout(req);
- if (timeout != default_timeout) {
- dlg->lifetime = timeout;
- }
- if (update_dlg_timer(&dlg->tl, dlg->lifetime) == -1) {
- LM_ERR("failed to update dialog lifetime\n");
- }
- if (update_cseqs(dlg, req, dir, &ttag) != 0) {
- LM_ERR("cseqs update failed\n");
- } else {
- dlg->dflags |= DLG_FLAG_CHANGED;
- }
- if(dlg_db_mode==DB_MODE_REALTIME && (dlg->dflags&DLG_FLAG_CHANGED)) {
- update_dialog_dbinfo(dlg);
- }
- if (old_state != DLG_STATE_CONFIRMED) {
- LM_DBG("confirming ACK successfully processed\n");
- /* confirming ACK request */
- run_dlg_callbacks(DLGCB_CONFIRMED, dlg, req, NULL, dir, 0);
- } else {
- LM_DBG("sequential request successfully processed\n");
- /* within dialog request */
- run_dlg_callbacks(DLGCB_REQ_WITHIN, dlg, req, NULL, dir, 0);
- if ((event != DLG_EVENT_REQACK) &&
- (dlg->cbs.types) & DLGCB_RESPONSE_WITHIN) {
- /* ref the dialog as registered into the transaction callback.
- * unref will be done when the callback will be destroyed */
- ref_dlg(dlg, 1);
- /* register callback for the replies of this request */
- if (d_tmb.register_tmcb(req, 0, TMCB_RESPONSE_FWDED,
- (dir == DLG_DIR_UPSTREAM) ? dlg_seq_down_onreply : dlg_seq_up_onreply,
- (void*) dlg, unreference_dialog) < 0) {
- LM_ERR("failed to register TMCB (2)\n");
- unref_dlg(dlg, 1);
- }
- }
- }
- }
- if (new_state == DLG_STATE_CONFIRMED && old_state != DLG_STATE_CONFIRMED) {
- dlg->dflags |= DLG_FLAG_CHANGED;
- if(dlg_db_mode == DB_MODE_REALTIME)
- update_dialog_dbinfo(dlg);
- }
- return;
- }
- /*!
- * \brief Timer function that removes expired dialogs, run timeout route
- * \param tl dialog timer list
- */
- void dlg_ontimeout(struct dlg_tl *tl) {
- struct dlg_cell *dlg;
- int new_state, old_state, unref;
- struct sip_msg *fmsg;
- /* get the dialog tl payload */
- dlg = ((struct dlg_cell*) ((char *) (tl) -
- (unsigned long) (&((struct dlg_cell*) 0)->tl)));
- if (dlg->toroute > 0 && dlg->toroute < main_rt.entries
- && main_rt.rlist[dlg->toroute] != NULL) {
- fmsg = faked_msg_next();
- if (exec_pre_script_cb(fmsg, REQUEST_CB_TYPE) > 0) {
- dlg_set_ctx_dialog(dlg);
- LM_DBG("executing route %d on timeout\n", dlg->toroute);
- set_route_type(REQUEST_ROUTE);
- run_top_route(main_rt.rlist[dlg->toroute], fmsg, 0);
- dlg_set_ctx_dialog(0);
- exec_post_script_cb(fmsg, REQUEST_CB_TYPE);
- }
- }
- if ((dlg->dflags & DLG_FLAG_TOBYE)
- && (dlg->state == DLG_STATE_CONFIRMED)) {
- //TODO: dlg_bye_all(dlg, NULL);
- unref_dlg(dlg, 1);
- return;
- }
- next_state_dlg(dlg, DLG_EVENT_REQBYE, &old_state, &new_state, &unref, 0);
- if (new_state == DLG_STATE_DELETED && old_state != DLG_STATE_DELETED) {
- LM_WARN("timeout for dlg with CallID '%.*s' and tags '%.*s'\n",
- dlg->callid.len, dlg->callid.s,
- dlg->from_tag.len, dlg->from_tag.s);
- /* dialog timeout */
- run_dlg_callbacks(DLGCB_EXPIRED, dlg, NULL, NULL, DLG_DIR_NONE, 0);
- unref_dlg(dlg, unref + 1);
- } else {
- unref_dlg(dlg, 1);
- }
- return;
- }
- /*!
- * \brief Function that returns the dialog lifetime as pseudo-variable
- * \param msg SIP message
- * \param param pseudo-variable parameter
- * \param res pseudo-variable result
- * \return 0 on success, -1 on failure
- */
- int pv_get_dlg_lifetime(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
- int l = 0;
- char *ch = NULL;
- if (msg == NULL || res == NULL)
- return -1;
- if (CURR_DLG_ID != msg->id)
- return pv_get_null(msg, param, res);
- res->ri = CURR_DLG_LIFETIME;
- ch = int2str((unsigned long) res->ri, &l);
- res->rs.s = ch;
- res->rs.len = l;
- res->flags = PV_VAL_STR | PV_VAL_INT | PV_TYPE_INT;
- return 0;
- }
- /*!
- * \brief Function that returns the dialog state as pseudo-variable
- * \param msg SIP message
- * \param param pseudo-variable parameter
- * \param res pseudo-variable result
- * \return 0 on success, -1 on failure
- */
- int pv_get_dlg_status(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
- int l = 0;
- char *ch = NULL;
- if (msg == NULL || res == NULL)
- return -1;
- if (CURR_DLG_ID != msg->id)
- return pv_get_null(msg, param, res);
- res->ri = CURR_DLG_STATUS;
- ch = int2str((unsigned long) res->ri, &l);
- res->rs.s = ch;
- res->rs.len = l;
- res->flags = PV_VAL_STR | PV_VAL_INT | PV_TYPE_INT;
- return 0;
- }
- /*!
- * \brief Helper function that prints all the properties of a dialog including all the dlg_out's
- * \param dlg dialog cell
- * \return void
- */
- void internal_print_all_dlg(struct dlg_cell *dlg) {
- LM_DBG("Trying to get lock for printing\n");
- lock_get(dlg->dlg_out_entries_lock);
- struct dlg_cell_out *dlg_out;
- struct dlg_entry_out *d_entry_out = &(dlg->dlg_entry_out);
- LM_DBG("----------------------------");
- LM_DBG("Dialog h_entry:h_id = [%u : %u]\n", dlg->h_entry, dlg->h_id);
- LM_DBG("Dialog call-id: %.*s\n", dlg->callid.len, dlg->callid.s);
- LM_DBG("Dialog state: %d\n", dlg->state);
- LM_DBG("Dialog ref counter: %d\n", dlg->ref);
- LM_DBG("Dialog did: %.*s\n", dlg->did.len, dlg->did.s);
- LM_DBG("Dialog from_tag: %.*s\n", dlg->from_tag.len, dlg->from_tag.s);
- LM_DBG("Dialog from_uri: %.*s\n", dlg->from_uri.len, dlg->from_uri.s);
- LM_DBG("Dialog caller contact: %.*s\n", dlg->caller_contact.len, dlg->caller_contact.s);
- LM_DBG("Dialog first request cseq: %.*s\n", dlg->first_req_cseq.len, dlg->first_req_cseq.s);
- LM_DBG("Dialog caller route set: %.*s\n", dlg->caller_route_set.len, dlg->caller_route_set.s);
- LM_DBG("Dialog lifetime: %d\n", dlg->lifetime);
- LM_DBG("Dialog bind_address: %.*s\n", dlg->caller_bind_addr->sock_str.len, dlg->caller_bind_addr->sock_str.s);
- dlg_out = d_entry_out->first;
- while (dlg_out) {
- LM_DBG("----------");
- LM_DBG("Dialog out h_entry:h_id = [%u : %u]\n", dlg_out->h_entry, dlg_out->h_id);
- LM_DBG("Dialog out did: %.*s\n", dlg_out->did.len, dlg_out->did.s);
- LM_DBG("Dialog out to_tag: %.*s\n", dlg_out->to_tag.len, dlg_out->to_tag.s);
- LM_DBG("Dialog out caller cseq: %.*s\n", dlg_out->caller_cseq.len, dlg_out->caller_cseq.s);
- LM_DBG("Dialog out callee cseq: %.*s\n", dlg_out->callee_cseq.len, dlg_out->callee_cseq.s);
- LM_DBG("Dialog out callee contact: %.*s\n", dlg_out->callee_contact.len, dlg_out->callee_contact.s);
- LM_DBG("Dialog out callee route set: %.*s\n", dlg_out->callee_route_set.len, dlg_out->callee_route_set.s);
- LM_DBG("----------");
- dlg_out = dlg_out->next;
- }
- LM_DBG("Releasing lock for dlgout\n");
- lock_release(dlg->dlg_out_entries_lock);
- LM_DBG("----------------------------");
- }
- /*!
- * \brief Helper function that prints information for all dialogs
- * \return void
- */
- void print_all_dlgs() {
- //print all dialog information - this is just for testing and is set to happen every 10 seconds
- struct dlg_cell *dlg;
- unsigned int i;
- LM_DBG("********************");
- 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) {
- internal_print_all_dlg(dlg);
- }
- dlg_unlock(d_table, &(d_table->entries[i]));
- }
- LM_DBG("********************");
- }
- struct dlg_cell *dlg_get_msg_dialog(sip_msg_t *msg)
- {
- struct dlg_cell *dlg = NULL;
- str callid;
- str ftag;
- str ttag;
- unsigned int dir;
- /* Retrieve the current dialog */
- dlg = dlg_get_ctx_dialog();
- if (dlg != NULL )
- return dlg;
- if (pre_match_parse(msg, &callid, &ftag, &ttag, 0) < 0)
- return NULL ;
- dir = DLG_DIR_NONE;
- dlg = get_dlg(&callid, &ftag, &ttag, &dir);
- if (dlg == NULL ) {
- LM_DBG("dlg with callid '%.*s' not found\n",
- msg->callid->body.len, msg->callid->body.s);
- return NULL ;
- }
- return dlg;
- }
|