📄 nua_dialog.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2006 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE nua_dialog.c * @brief Dialog and dialog usage handling * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Wed Mar 8 11:48:49 EET 2006 ppessi */#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include <assert.h>#include <sofia-sip/string0.h>#include <sofia-sip/su_uniqueid.h>#include <sofia-sip/sip_protos.h>#include <sofia-sip/sip_status.h>#define NUA_OWNER_T su_home_t#include "nua_dialog.h"#define SU_LOG (nua_log)#include <sofia-sip/su_debug.h>#ifndef NONE#define NONE ((void *)-1)#endif/* ======================================================================== *//* Dialog handling */static void nua_dialog_usage_remove_at(nua_owner_t*, nua_dialog_state_t*, nua_dialog_usage_t**, nua_client_request_t *cr, nua_server_request_t *sr);static void nua_dialog_log_usage(nua_owner_t *, nua_dialog_state_t *);/**@internal * UAS tag and route. * * Update dialog tags and route on the UAS side. * * @param own dialog owner * @param ds dialog state * @param sip SIP message containing response used to update dialog * @param rtag if true, set remote tag within the leg */void nua_dialog_uas_route(nua_owner_t *own, nua_dialog_state_t *ds, sip_t const *sip, int rtag){ int established = nua_dialog_is_established(ds); if (!established && sip->sip_from->a_tag) ds->ds_remote_tag = su_strdup(own, sip->sip_from->a_tag); if (ds->ds_leg == NULL) return; nta_leg_server_route(ds->ds_leg, sip->sip_record_route, sip->sip_contact); ds->ds_route = ds->ds_route || sip->sip_record_route || sip->sip_contact; if (rtag && !established && sip->sip_from->a_tag) nta_leg_rtag(ds->ds_leg, sip->sip_from->a_tag);}/**@internal * UAC tag and route. * * Update dialog tags and route on the UAC side. * * @param own dialog owner * @param ds dialog state * @param sip SIP message containing response used to update dialog * @param rtag if true, set remote tag within the leg */void nua_dialog_uac_route(nua_owner_t *own, nua_dialog_state_t *ds, sip_t const *sip, int rtag){ int established = nua_dialog_is_established(ds); if (!established && sip->sip_to->a_tag) ds->ds_remote_tag = su_strdup(own, sip->sip_to->a_tag); if (ds->ds_leg == NULL) return; nta_leg_client_route(ds->ds_leg, sip->sip_record_route, sip->sip_contact); ds->ds_route = ds->ds_route || sip->sip_record_route || sip->sip_contact; if (rtag && !established && sip->sip_to->a_tag) nta_leg_rtag(ds->ds_leg, sip->sip_to->a_tag);}/**@internal Store information from remote endpoint. */void nua_dialog_store_peer_info(nua_owner_t *own, nua_dialog_state_t *ds, sip_t const *sip){ nua_dialog_peer_info_t *nr = ds->ds_remote_ua; nua_dialog_usage_t *du; nua_dialog_peer_info_t old[1]; *old = *nr; if (sip && sip->sip_status && sip->sip_status->st_status >= 300 && sip->sip_status->st_status <= 399) sip = NULL; /* Redirected */ if (sip == NULL) { nr->nr_allow = NULL, su_free(own, old->nr_allow); nr->nr_accept = NULL, su_free(own, old->nr_accept); nr->nr_require = NULL, su_free(own, old->nr_require); nr->nr_supported = NULL, su_free(own, old->nr_supported); nr->nr_user_agent = NULL, su_free(own, old->nr_user_agent); return; } if (sip->sip_allow) { nr->nr_allow = sip_allow_dup(own, sip->sip_allow); su_free(own, old->nr_allow); } if (sip->sip_accept) { nr->nr_accept = sip_accept_dup(own, sip->sip_accept); su_free(own, old->nr_accept); } if (sip->sip_require) { nr->nr_require = sip_require_dup(own, sip->sip_require); su_free(own, old->nr_require); } if (sip->sip_supported) { nr->nr_supported = sip_supported_dup(own, sip->sip_supported); su_free(own, old->nr_supported); } if (sip->sip_user_agent) { nr->nr_user_agent = sip_user_agent_dup(own, sip->sip_user_agent); su_free(own, old->nr_user_agent); } else if (sip->sip_server) { nr->nr_user_agent = sip_user_agent_dup(own, sip->sip_server); su_free(own, old->nr_user_agent); } for (du = ds->ds_usage; du; du = du->du_next) { if (du->du_class->usage_peer_info) du->du_class->usage_peer_info(du, ds, sip); }}/** Remove dialog information. */int nua_dialog_zap(nua_owner_t *own, nua_dialog_state_t *ds){ /* zap peer info */ nua_dialog_store_peer_info(own, ds, NULL); /* Local Contact */ msg_header_free(own, (msg_header_t *)ds->ds_ltarget), ds->ds_ltarget = NULL; /* Leg */ nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL; /* Remote tag */ su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL; /* Ready to set route/remote target */ ds->ds_route = 0; return 0;}/** Remove dialog (if there is no other usages). */int nua_dialog_remove(nua_owner_t *own, nua_dialog_state_t *ds, nua_dialog_usage_t *usage){ if (ds->ds_usage == usage && (usage == NULL || usage->du_next == NULL)) { return nua_dialog_zap(own, ds); } return 0;}/** @internal Get dialog usage slot. */nua_dialog_usage_t **nua_dialog_usage_at(nua_dialog_state_t const *ds, nua_usage_class const *kind, sip_event_t const *event){ static nua_dialog_usage_t *none = NULL; if (ds) { nua_dialog_usage_t *du, * const * prev; sip_event_t const *o; for (prev = &ds->ds_usage; (du = *prev); prev = &du->du_next) { if (du->du_class != kind) continue; if (event == NONE) return (nua_dialog_usage_t **)prev; o = du->du_event; if (!event && !o) return (nua_dialog_usage_t **)prev; if (event != o) { if (event == NULL || o == NULL) continue; if (strcmp(event->o_type, o->o_type)) continue; if (str0casecmp(event->o_id, o->o_id)) { if (event->o_id || strcmp(event->o_type, "refer")) continue; } } return (nua_dialog_usage_t **)prev; } } return &none;}/** @internal Get a dialog usage */nua_dialog_usage_t *nua_dialog_usage_get(nua_dialog_state_t const *ds, nua_usage_class const *kind, sip_event_t const *event){ return *nua_dialog_usage_at(ds, kind, event);}/** @internal Get dialog usage name */char const *nua_dialog_usage_name(nua_dialog_usage_t const *du){ if (du == NULL) return "<NULL>"; return du->du_class->usage_name(du);} /** @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_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -