Ejemplo n.º 1
0
void dlg_callback_received(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
    LM_DBG("Received dialog callback event [%d]\n", type);
    unsigned int termcode = 0;
    switch (type) {
        case DLGCB_CONFIRMED:
            dlg_answered(dlg, type, _params);
            break;
        case DLGCB_TERMINATED:
            dlg_terminated(dlg, type, termcode, "normal call clearing", _params);
            break;
        case DLGCB_FAILED:
            dlg_terminated(dlg, type, termcode, "call failed", _params);
            break;
        case DLGCB_EXPIRED:
            dlg_terminated(dlg, type, termcode, "dialog timeout", _params);
            break;
        default:
            LM_WARN("Received unknown dialog callback [%d]\n", type);
    }
}
Ejemplo n.º 2
0
void dlg_callback_received(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) {
    LM_DBG("Received dialog callback event [%d]\n", type);
    switch (type) {
        case DLGCB_CONFIRMED:
            dlg_answered(dlg, type, _params);
            break;
        case DLGCB_TERMINATED:
        case DLGCB_FAILED:
        case DLGCB_EXPIRED:
            dlg_terminated(dlg, type, _params);
            break;
        default:
            LM_WARN("Received unknown dialog callback [%d]\n", type);
    }
}
Ejemplo n.º 3
0
/*!
 * \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 (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;
    }
    return;
}
Ejemplo n.º 4
0
/*!
 * \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)
{
	dlg_cell_t *dlg;
	dlg_iuid_t *iuid;
	str val, callid, ftag, ttag;
	int h_entry, h_id, new_state, old_state, unref, event, timeout, reset;
	unsigned int dir;
	int ret = 0;

	dlg = dlg_get_ctx_dialog();
	if (dlg!=NULL) {
		dlg_release(dlg);
		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 = dlg_lookup(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
					dlg_release(dlg);
					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, callee tag='%.*s'/%d\n",
							dlg->callid.len, dlg->callid.s, dlg->callid.len,
							dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
							dlg->tag[DLG_CALLER_LEG].len,
							dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s,
							dlg->tag[DLG_CALLEE_LEG].len);
					// lookup_dlg has incremented the ref count by 1
					dlg_release(dlg);

					// 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==0){
			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.iuid.h_entry = dlg->h_entry;
    _dlg_ctx.iuid.h_id = dlg->h_id;

	if (req->first_line.u.request.method_value != METHOD_ACK) {
		iuid = dlg_get_iuid_shm_clone(dlg);
		if(iuid!=NULL)
		{
			/* register callback for the replies of this request */
			if ( d_tmb.register_tmcb( req, 0, TMCB_RESPONSE_IN|TMCB_ON_FAILURE,
					dlg_onreply, (void*)iuid, dlg_iuid_sfree)<0 ) {
				LM_ERR("failed to register TMCB (3)\n");
				shm_free(iuid);
			}
			iuid = NULL;
		}
	}
	
	/* 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);

	CURR_DLG_ID = req->id;
	CURR_DLG_LIFETIME = (unsigned int)(time(0))-dlg->start_ts;
	CURR_DLG_STATUS = new_state;

	dlg_run_event_route(dlg, req, old_state, new_state);

	/* delay deletion of dialog until transaction has died off in order
	 * to absorb in-air messages */
	if (new_state==DLG_STATE_DELETED && old_state!=DLG_STATE_DELETED) {
		iuid = dlg_get_iuid_shm_clone(dlg);
		if(iuid!=NULL) {
			if ( d_tmb.register_tmcb(req, NULL, TMCB_DESTROY,
					unref_dlg_from_cb, (void*)iuid, dlg_iuid_sfree)<0 ) {
				LM_ERR("failed to register deletion delay function\n");
				shm_free(iuid);
			} else {
				dlg_ref(dlg, 1);
			}
		}
	}

	if (new_state==DLG_STATE_CONFIRMED && old_state!=DLG_STATE_CONFIRMED)
		dlg_ka_add(dlg);

	/* 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' '%.*s'\n",
				dlg, dlg->h_entry, dlg->h_id,
				dlg->callid.len, dlg->callid.s,
				dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
				dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
		} else if (ret > 0) {
			LM_WARN("inconsitent dlg timer data on dlg %p [%u:%u] "
				"with clid '%.*s' and tags '%.*s' '%.*s'\n",
				dlg, dlg->h_entry, dlg->h_id,
				dlg->callid.len, dlg->callid.s,
				dlg->tag[DLG_CALLER_LEG].len, dlg->tag[DLG_CALLER_LEG].s,
				dlg->tag[DLG_CALLEE_LEG].len, dlg->tag[DLG_CALLEE_LEG].s);
		} else {
			/* one extra unref due to removal from timer list */
			unref++;
		}
		/* dialog terminated (BYE) */
        dlg_terminated( req, dlg, dir);

		dlg_unref(dlg, unref);

		_dlg_ctx.cpid = my_pid();
		_dlg_ctx.expect_t = 1;
		dlg_set_ctx_iuid(dlg);

		if_update_stat( dlg_enable_stats, active_dlgs, -1);
		goto done;
	}

	if ( (event==DLG_EVENT_REQ || event==DLG_EVENT_REQACK)
	&& (new_state==DLG_STATE_CONFIRMED || new_state==DLG_STATE_EARLY)) {

		timeout = get_dlg_timeout(req);
		if (timeout!=default_timeout) {
			dlg->lifetime = timeout;
		}
		reset = !((dlg->iflags & DLG_IFLAG_TIMER_NORESET) || dlg_timeout_noreset);

		if ((new_state!=DLG_STATE_EARLY) && (old_state!=DLG_STATE_CONFIRMED || reset)) {
			if (update_dlg_timer( &dlg->tl, dlg->lifetime )==-1) {
				LM_ERR("failed to update dialog lifetime\n");
			} else {
				dlg->dflags |= DLG_FLAG_CHANGED;
			}
		}
		if(event != DLG_EVENT_REQACK) {
			if(dlg_refresh_contacts(dlg, req, dir)!=0) {
				LM_ERR("contacts update failed\n");
			} else {
				dlg->dflags |= DLG_FLAG_CHANGED;
			}
			if(update_cseqs(dlg, req, dir)!=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_NA) {
			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 ) {
				iuid = dlg_get_iuid_shm_clone(dlg);
				if(iuid!=NULL)
				{
					/* 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*)iuid, dlg_iuid_sfree)<0 ) {
						LM_ERR("failed to register TMCB (2)\n");
						shm_free(iuid);
					}
				}
			}
		}
	}

	if(new_state==DLG_STATE_CONFIRMED && old_state==DLG_STATE_CONFIRMED_NA){
		dlg->dflags |= DLG_FLAG_CHANGED;
		if(dlg_db_mode == DB_MODE_REALTIME)
			update_dialog_dbinfo(dlg);
	}

done:
	dlg_release(dlg);
	return;
}