Example #1
0
/*!
 * \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;
}
Example #2
0
/*!
 * \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 req SIP message
 * \param t transaction
 * \param run_initial_cbs if set zero, initial callbacks are not executed
 * \return 0 on success, -1 on failure
 */ 
int dlg_new_dialog(sip_msg_t *req, struct cell *t, const int run_initial_cbs)
{
	dlg_cell_t *dlg;
	str s;
	str callid;
    str ftag;
    str ttag;
    str req_uri;
    unsigned int dir;

	dlg = dlg_get_ctx_dialog();
    if(dlg != NULL) {
		dlg_release(dlg);
        return -1;
	}

	if(req->first_line.u.request.method_value != METHOD_INVITE)
		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);

	dir = DLG_DIR_NONE;
	/* search dialog by SIP attributes
	 * - hash table slot is left locked  */
	dlg = dlg_search(&callid, &ftag, &ttag, &dir);
	if(dlg) {
		if (detect_spirals) {
			if (spiral_detected == 1) {
				dlg_hash_release(&callid);
				return 0;
			}

			if ( dlg->state != DLG_STATE_DELETED ) {
				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);
				/* set ctx dlg id shortcuts */
				_dlg_ctx.iuid.h_entry = dlg->h_entry;
				_dlg_ctx.iuid.h_id = dlg->h_id;
				/* search_dlg() has incremented the ref count by 1 */
				dlg_release(dlg);
				dlg_hash_release(&callid);
				return 0;
			}
			dlg_release(dlg);
		}
    }
    spiral_detected = 0;

    dlg = build_new_dlg (&callid /*callid*/,
                         &(get_from(req)->uri) /*from uri*/,
                         &(get_to(req)->uri) /*to uri*/,
                         &ftag/*from_tag*/,
                         &req_uri /*r-uri*/ );

	if (dlg==0) {
		dlg_hash_release(&callid);
		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) {
		dlg_hash_release(&callid);
		LM_ERR("could not add further info to the dialog\n");
		shm_free(dlg);
		return -1;
	}

	/* Populate initial varlist: */
	dlg->vars = get_local_varlist_pointer(req, 1);

	/* after dlg_search() slot was kept locked */
	link_dlg(dlg, 0, 1);
	/* unlock after dlg_search() */
	dlg_hash_release(&callid);

	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;
	dlg->iflags |= _dlg_ctx.iflags;

	if (dlg_send_bye!=0 || _dlg_ctx.to_bye!=0)
		dlg->iflags |= DLG_IFLAG_TIMEOUTBYE;

    if (run_initial_cbs)  run_create_callbacks( dlg, req);

	/* first INVITE seen (dialog created, unconfirmed) */
	if ( seq_match_mode!=SEQ_MATCH_NO_ID &&
			add_dlg_rr_param( req, dlg->h_entry, dlg->h_id)<0 ) {
		LM_ERR("failed to add RR param\n");
		goto error;
	}

    if_update_stat( dlg_enable_stats, processed_dlgs, 1);

	_dlg_ctx.cpid = my_pid();
    _dlg_ctx.iuid.h_entry = dlg->h_entry;
    _dlg_ctx.iuid.h_id = dlg->h_id;
    set_current_dialog(req, dlg);

	return 0;

error:
	if (!spiral_detected)
		dlg_unref(dlg, 1);               // undo ref regarding linking
	return -1;
}