/** @internal Add dialog usage */ nua_dialog_usage_t *nua_dialog_usage_add(nua_owner_t *own, struct nua_dialog_state *ds, nua_usage_class const *uclass, sip_event_t const *event) { if (ds) { sip_event_t *o; nua_dialog_usage_t *du, **prev_du; prev_du = nua_dialog_usage_at(ds, uclass, event); du = *prev_du; if (du) { /* Already exists */ SU_DEBUG_5(("nua(%p): adding already existing %s usage%s%s\n", (void *)own, nua_dialog_usage_name(du), event ? " with event " : "", event ? event->o_type : "")); if (prev_du != &ds->ds_usage) { /* Move as a first usage in the list */ *prev_du = du->du_next; du->du_next = ds->ds_usage; ds->ds_usage = du; } return du; } o = event ? sip_event_dup(own, event) : NULL; if (o != NULL || event == NULL) du = su_zalloc(own, sizeof *du + uclass->usage_size); if (du) { su_home_ref(own); du->du_dialog = ds; du->du_class = uclass; du->du_event = o; if (uclass->usage_add(own, ds, du) < 0) { su_home_unref(own); su_free(own, o); su_free(own, du); return NULL; } SU_DEBUG_5(("nua(%p): adding %s usage%s%s\n", (void *)own, nua_dialog_usage_name(du), o ? " with event " : "", o ? o->o_type :"")); du->du_next = ds->ds_usage, ds->ds_usage = du; return du; } su_free(own, o); } return NULL; }
/** Set absolute refresh time */ void nua_dialog_usage_set_refresh_at(nua_dialog_usage_t *du, sip_time_t target) { SU_DEBUG_7(("nua(): refresh %s after %lu seconds\n", nua_dialog_usage_name(du), target - sip_now())); du->du_refresh = target; }
/**@internal Set refresh in range min..max seconds in the future. */ void nua_dialog_usage_set_refresh_range(nua_dialog_usage_t *du, unsigned min, unsigned max) { sip_time_t now = sip_now(), target; unsigned delta; if (max < min) max = min; if (min != max) delta = su_randint(min, max); else delta = min; if (now + delta >= now) target = now + delta; else target = SIP_TIME_MAX; SU_DEBUG_7(("nua(): refresh %s after %lu seconds (in [%u..%u])\n", nua_dialog_usage_name(du), target - now, min, max)); du->du_refquested = now; du->du_refresh = target; }
/**@internal Set refresh in range min..max seconds in the future. */ void nua_dialog_usage_set_refresh_range(nua_dialog_usage_t *du, unsigned min, unsigned max) { su_duration_t max_defer = nua_dialog_usage_get_max_defer(du); unsigned delta; int make_deferrable = 0; if (max <= min) { max = min; delta = min * 1000; } else if (max_defer > 0 && (int)(max - min) >= max_defer / 1000) { delta = su_randint(min * 1000, max * 1000 - (max_defer + 999)); make_deferrable = 1; } else delta = su_randint(min * 1000, max * 1000); SU_DEBUG_7(("nua(): refresh %s in %.3f seconds (in [%u..%u]%s)\n", nua_dialog_usage_name(du), 1e-3 * delta, min, max, make_deferrable? ", deferrable" : "")); delta += delta == 0; nua_dialog_usage_set_refresh_timer(du, delta, make_deferrable); }
/** @internal Remove dialog usage. * * Zap dialog state (leg, tag and route) if no usages remain. */ static void nua_dialog_usage_remove_at(nua_owner_t *own, nua_dialog_state_t *ds, nua_dialog_usage_t **at, nua_client_request_t *cr0, nua_server_request_t *sr0) { if (*at) { nua_dialog_usage_t *du = *at; sip_event_t const *o = NULL; nua_client_request_t *cr, *cr_next; nua_server_request_t *sr, *sr_next; *at = du->du_next; o = du->du_event; SU_DEBUG_5(("nua(%p): removing %s usage%s%s\n", (void *)own, nua_dialog_usage_name(du), o ? " with event " : "", o ? o->o_type :"")); du->du_class->usage_remove(own, ds, du, cr0, sr0); /* Clean reference to saved client request */ if (du->du_cr) nua_client_bind(du->du_cr, NULL); /* Clean references from queued client requests */ for (cr = ds->ds_cr; cr; cr = cr_next) { cr_next = cr->cr_next; if (cr->cr_usage == du) cr->cr_usage = NULL; } /* Clean references from queued server requests */ for (sr = ds->ds_sr; sr; sr = sr_next) { sr_next = sr->sr_next; if (sr->sr_usage == du) { sr->sr_usage = NULL; if (sr != sr0) nua_server_request_destroy(sr); } } su_home_unref(own); su_free(own, du); } /* Zap dialog if there are no more usages */ if (ds->ds_terminating) ; else if (ds->ds_usage == NULL) { nua_dialog_remove(own, ds, NULL); ds->ds_has_events = 0; return; } else { nua_dialog_log_usage(own, ds); } }
/**@internal Set refresh before delta seconds elapse */ void nua_dialog_usage_set_refresh_in(nua_dialog_usage_t *du, unsigned delta) { su_duration_t max_defer = nua_dialog_usage_get_max_defer(du); su_duration_t timeout = delta * 1000L; int make_deferrable = 0; if (max_defer > 0 && timeout >= max_defer) { timeout -= max_defer; make_deferrable = 1; } SU_DEBUG_7(("nua(): refresh %s in %u seconds%s\n", nua_dialog_usage_name(du), delta, make_deferrable? " (deferrable)" : "")); nua_dialog_usage_set_refresh_timer(du, timeout, make_deferrable); }