⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nua_session.c

📁 this is simple sip stack.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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_session.c * @brief SIP session handling * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Wed Mar  8 16:17:27 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/sip_protos.h>#include <sofia-sip/sip_status.h>#include <sofia-sip/sip_util.h>#define NTA_LEG_MAGIC_T      struct nua_handle_s#define NTA_OUTGOING_MAGIC_T struct nua_handle_s#define NTA_INCOMING_MAGIC_T struct nua_handle_s#define NTA_RELIABLE_MAGIC_T struct nua_handle_s#include "nua_stack.h"#include <sofia-sip/soa.h>#if !defined(random) && defined(_WIN32)#define random rand#endif#ifndef SDP_Htypedef struct sdp_session_s sdp_session_t;#endif/* ---------------------------------------------------------------------- *//* Session event usage */struct session_usage;static char const *nua_session_usage_name(nua_dialog_usage_t const *du);static int nua_session_usage_add(nua_handle_t *nh,				 nua_dialog_state_t *ds,				 nua_dialog_usage_t *du);static void nua_session_usage_remove(nua_handle_t *nh,				     nua_dialog_state_t *ds,				     nua_dialog_usage_t *du);static nua_usage_class const nua_session_usage[1] = {  {    0 /* sizeof (struct session_usage) */,    sizeof nua_session_usage,    nua_session_usage_add,    nua_session_usage_remove,    nua_session_usage_name,  }};static char const *nua_session_usage_name(nua_dialog_usage_t const *du){  return "session";}staticint nua_session_usage_add(nua_handle_t *nh,			   nua_dialog_state_t *ds,			   nua_dialog_usage_t *du){  if (ds->ds_has_session)    return -1;  ds->ds_has_session = 1;  return 0;}staticvoid nua_session_usage_remove(nua_handle_t *nh,			       nua_dialog_state_t *ds,			       nua_dialog_usage_t *du){  ds->ds_has_session = 0;}/* ======================================================================== *//* INVITE and call (session) processing */static int ua_invite2(nua_t *, nua_handle_t *, nua_event_t e,		      int restarted, tagi_t const *tags);static int process_response_to_invite(nua_handle_t *nh,				      nta_outgoing_t *orq,				      sip_t const *sip);static int process_100rel(nua_handle_t *nh,			  nta_outgoing_t *orq,			  sip_t const *sip);static void  cancel_invite(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now),  refresh_invite(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now),  session_timeout(nua_handle_t *nh, nua_dialog_usage_t *du, sip_time_t now);static void restart_invite(nua_handle_t *nh, tagi_t *tags);static int process_response_to_prack(nua_handle_t *nh,				     nta_outgoing_t *orq,				     sip_t const *sip);static void nsession_destroy(nua_handle_t *nh);static int  use_session_timer(nua_handle_t *nh, int uas, msg_t *msg, sip_t *);static int  init_session_timer(nua_handle_t *nh, sip_t const *);static void set_session_timer(nua_handle_t *nh);static int nh_referral_check(nua_handle_t *nh, tagi_t const *tags);static void nh_referral_respond(nua_handle_t *,				int status, char const *phrase);static void signal_call_state_change(nua_handle_t *nh,				     int status, char const *phrase,				     enum nua_callstate next_state,				     char const *oa_recv,				     char const *oa_sent);staticint session_get_description(msg_t *msg,			    sip_t const *sip,			    char const **return_sdp,			    size_t *return_len);staticint session_include_description(soa_session_t *soa,				msg_t *msg,				sip_t *sip);staticint session_make_description(su_home_t *home,			     soa_session_t *soa,			     sip_content_disposition_t **return_cd,			     sip_content_type_t **return_ct,			     sip_payload_t **return_pl);staticint session_process_response(nua_handle_t *nh,			     struct nua_client_request *cr,			     nta_outgoing_t *orq,			     sip_t const *sip,			     char const **return_received);intnua_stack_invite(nua_t *nua, nua_handle_t *nh, nua_event_t e,		 tagi_t const *tags){  nua_session_state_t *ss = nh->nh_ss;  struct nua_client_request *cr = ss->ss_crequest;  char const *what;  if (nh_is_special(nh))    what = "Invalid handle for INVITE";  else if (cr->cr_orq) {    what = "INVITE request already in progress";  }  else if (nh_referral_check(nh, tags) < 0) {    what = "Invalid referral";  }  else if (nua_stack_init_handle(nua, nh, nh_has_invite, NULL,				 TAG_NEXT(tags)) < 0) {    what = "Handle initialization failed";  }  else    return ua_invite2(nua, nh, e, 0, tags);  UA_EVENT2(e, 900, what);  signal_call_state_change(nh, 900, what, nua_callstate_init, 0, 0);  return e;}static intua_invite2(nua_t *nua, nua_handle_t *nh, nua_event_t e, int restarted,	   tagi_t const *tags){  nua_session_state_t *ss = nh->nh_ss;  struct nua_client_request *cr = ss->ss_crequest;  nua_dialog_usage_t *du;  int offer_sent = 0;  msg_t *msg = NULL;  sip_t *sip;  char const *what;  if (ss->ss_state == nua_callstate_terminated)    ss->ss_state = nua_callstate_init;  du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL);  what = nua_internal_error;		/* Internal error */  msg = du ? nua_creq_msg(nua, nh, cr, restarted,			      SIP_METHOD_INVITE,			      NUTAG_USE_DIALOG(1),			      NUTAG_ADD_CONTACT(1),			      TAG_NEXT(tags)) : NULL;  sip = sip_object(msg);  if (du && sip && nh->nh_soa) {    soa_init_offer_answer(nh->nh_soa);    if (sip->sip_payload)      offer_sent = 0;    else if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0)      offer_sent = -1;    else      offer_sent = 1;  }  assert(cr->cr_orq == NULL);  if (du && sip && offer_sent >= 0) {    sip_time_t invite_timeout = NH_PGET(nh, invite_timeout);    if (invite_timeout == 0)      invite_timeout = UINT_MAX;    /* Cancel if we don't get response */    nua_dialog_usage_set_refresh(du, invite_timeout);    /* Add session timer headers */    use_session_timer(nh, 0, msg, sip);    ss->ss_100rel = NH_PGET(nh, early_media);    ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition");    if (ss->ss_precondition)      ss->ss_update_needed = ss->ss_100rel = 1;    if (offer_sent > 0 &&	session_include_description(nh->nh_soa, msg, sip) < 0)      sip = NULL, what = "Internal media error";    if (sip && nh->nh_soa &&	NH_PGET(nh, media_features) && !nua_dialog_is_established(nh->nh_ds) &&	!sip->sip_accept_contact && !sip->sip_reject_contact) {      sip_accept_contact_t ac[1];      sip_accept_contact_init(ac);      ac->cp_params = (msg_param_t *)	soa_media_features(nh->nh_soa, 1, msg_home(msg));      if (ac->cp_params) {	msg_header_replace_param(msg_home(msg), ac->cp_common, "explicit");	sip_add_dup(msg, sip, (sip_header_t *)ac);      }    }    if (sip && nh->nh_auth) {      if (auc_authorize(&nh->nh_auth, msg, sip) < 0)	sip = NULL, what = "Internal authentication error";    }    if (sip)      cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,					process_response_to_invite, nh, NULL,					msg,					NTATAG_REL100(ss->ss_100rel),					SIPTAG_END(), TAG_NEXT(tags));    if (cr->cr_orq) {      cr->cr_offer_sent = offer_sent;      cr->cr_usage = du;      du->du_pending = cancel_invite;      du->du_refresh = 0;      signal_call_state_change(nh, 0, "INVITE sent",			       nua_callstate_calling, 0,			       offer_sent ? "offer" : 0);      return cr->cr_event = e;    }  }  msg_destroy(msg);  if (du && !du->du_ready)    nua_dialog_usage_remove(nh, nh->nh_ds, du);  UA_EVENT2(e, 900, what);  signal_call_state_change(nh, 900, what, nua_callstate_init, 0, 0);  return e;}static int process_response_to_invite(nua_handle_t *nh,				      nta_outgoing_t *orq,				      sip_t const *sip){  nua_t *nua = nh->nh_nua;  nua_session_state_t *ss = nh->nh_ss;  nua_client_request_t *cr = ss->ss_crequest;  nua_dialog_usage_t *du = cr->cr_usage;  int status = sip->sip_status->st_status;  char const *phrase = sip->sip_status->st_phrase;  int terminated = 0;  int gracefully = 1;  char const *received = NULL;  assert(du);#if HAVE_SOFIA_SMIME  if (status < 300) {    int sm_status;    msg_t *response;    /* decrypt sdp payload if it's S/MIME */    /* XXX msg had a problem!!?? */    response = nta_outgoing_getresponse(orq);    sm_status = sm_decode_message(nua->sm, response, sip);    switch (sm_status) {    case SM_SMIME_DISABLED:    case SM_ERROR:      status = 493, phrase = "Undecipherable";      break;    case SM_SUCCESS:      break;    default:      break;    }  }#endif  if (status >= 300) {    if (sip->sip_retry_after)      gracefully = 0;    terminated = sip_response_terminates_dialog(status, sip_method_invite,						&gracefully);    if (!terminated) {      if (nua_creq_check_restart(nh, cr, orq, sip, restart_invite))	return 0;      if (nh->nh_ss->ss_state < nua_callstate_ready)	terminated = 1;    }  }  else if (status >= 200) {    du->du_ready = 1;    if (!ss->ss_usage)      ss->ss_usage = du;    cr->cr_usage = NULL;    /* XXX - check remote tag, handle forks */    /* Set route, contact, nh_ds->ds_remote_tag */    nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);    init_session_timer(nh, sip);    set_session_timer(nh);    /* signal_call_state_change */    if (session_process_response(nh, cr, orq, sip, &received) >= 0) {      ss->ss_ack_needed = received ? received : "";      if (NH_PGET(nh, auto_ack) ||	  /* Auto-ACK response to re-INVITE unless auto_ack is set to 0 */	  (ss->ss_state == nua_callstate_ready &&	   !NH_PISSET(nh, auto_ack)))	nua_stack_ack(nua, nh, nua_r_ack, NULL);      else	signal_call_state_change(nh, status, phrase,				 nua_callstate_completing, received, 0);      nh_referral_respond(nh, SIP_200_OK);      return 0;    }    status = 900, phrase = "Malformed Session in Response";    nua_stack_ack(nua, nh, nua_r_ack, NULL);    gracefully = 1;  }  else if (sip->sip_rseq) {    /* Reliable provisional response */    nh_referral_respond(nh, status, phrase);    return process_100rel(nh, orq, sip); /* signal_call_state_change */  }  else {    /* Provisional response */    nh_referral_respond(nh, status, phrase);    session_process_response(nh, cr, orq, sip, &received);    signal_call_state_change(nh, status, phrase,			     nua_callstate_proceeding, received, 0);    return 0;  }  cr->cr_usage = NULL;  nh_referral_respond(nh, status, phrase);  nua_stack_process_response(nh, cr, orq, sip, TAG_END());  if (terminated)    signal_call_state_change(nh, status, phrase,			     nua_callstate_terminated, 0, 0);  if (terminated < 0) {    nua_dialog_terminated(nh, nh->nh_ds, status, phrase);  }  else if (terminated > 0) {    nua_dialog_usage_remove(nh, nh->nh_ds, du);  }  else if (gracefully) {    char *reason =      su_sprintf(NULL, "SIP;cause=%u;text=\"%s\"", status, phrase);    signal_call_state_change(nh, status, phrase,			     nua_callstate_terminating, 0, 0);    nua_stack_post_signal(nh, nua_r_bye,			  SIPTAG_REASON_STR(reason),			  TAG_END());    su_free(NULL, reason);  }  return 0;}int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,		  tagi_t const *tags){  nua_session_state_t *ss = nh->nh_ss;  struct nua_client_request *cr = ss->ss_crequest;  nta_outgoing_t *ack = NULL;  msg_t *msg;  sip_t *sip;  int status = 200;  char const *phrase = "OK", *reason = NULL, *sent = NULL;  char const *received = ss->ss_ack_needed;  if (!ss->ss_ack_needed)    return UA_EVENT2(nua_i_error, 900, "No response to ACK");  ss->ss_ack_needed = 0;  if (!received[0])    received = NULL;  if (tags) {    nua_stack_set_params(nua, nh, nua_r_ack, tags);  }  msg = nua_creq_msg(nua, nh, cr, 0,			 SIP_METHOD_ACK,			 /* NUTAG_COPY(0), */			 TAG_NEXT(tags));  sip = sip_object(msg);  if (sip && nh->nh_soa) {    if (tags)      soa_set_params(nh->nh_soa, TAG_NEXT(tags));    if (cr->cr_offer_recv && !cr->cr_answer_sent) {      if (soa_generate_answer(nh->nh_soa, NULL) < 0 ||

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -