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

📄 nua_session.c

📁 this is simple sip stack.
💻 C
📖 第 1 页 / 共 5 页
字号:
/** Add timer featuretag and Session-Expires/Min-SE headers */static intuse_session_timer(nua_handle_t *nh, int uas, msg_t *msg, sip_t *sip){  struct nua_session_state *ss = nh->nh_ss;  sip_min_se_t min_se[1];  sip_session_expires_t session_expires[1];  static sip_param_t const x_params_uac[] = {"refresher=uac", NULL};  static sip_param_t const x_params_uas[] = {"refresher=uas", NULL};  /* Session-Expires timer */  if ((NH_PGET(nh, refresher) == 0 &&       NH_PGET(nh, session_timer) == 0) ||      /* Is timer feature supported? */      !sip_has_supported(NH_PGET(nh, supported), "timer"))    return 0;  sip_min_se_init(min_se)->min_delta = ss->ss_min_se;  sip_session_expires_init(session_expires)->x_delta = ss->ss_session_timer;  if (ss->ss_refresher == nua_remote_refresher)    session_expires->x_params = uas ? x_params_uac : x_params_uas;  else if (ss->ss_refresher == nua_local_refresher)    session_expires->x_params = uas ? x_params_uas : x_params_uac;  sip_add_tl(msg, sip,	     TAG_IF(ss->ss_session_timer,		    SIPTAG_SESSION_EXPIRES(session_expires)),	     TAG_IF(ss->ss_min_se != 0		    /* Min-SE: 0 is optional with initial INVITE */		    || ss->ss_state != nua_callstate_init,		    SIPTAG_MIN_SE(min_se)),	     TAG_IF(ss->ss_refresher == nua_remote_refresher,		    SIPTAG_REQUIRE_STR("timer")),	     TAG_END());  return 1;}static intinit_session_timer(nua_handle_t *nh, sip_t const *sip){  struct nua_session_state *ss = nh->nh_ss;  int server;  ss->ss_refresher = nua_no_refresher;  /* Check if we support the timer feature */  if (!sip->sip_session_expires ||      !sip_has_supported(NH_PGET(nh, supported), "timer")) {    return 0;  }  ss->ss_session_timer = sip->sip_session_expires->x_delta;  if (sip->sip_min_se != NULL      && sip->sip_min_se->min_delta > ss->ss_min_se)    ss->ss_min_se = sip->sip_min_se->min_delta;  server = sip->sip_request != NULL;  if (!str0casecmp("uac", sip->sip_session_expires->x_refresher))    ss->ss_refresher = server ? nua_remote_refresher : nua_local_refresher;  else if (!str0casecmp("uas", sip->sip_session_expires->x_refresher))    ss->ss_refresher = server ? nua_local_refresher : nua_remote_refresher;  else if (!server)    return 0;			/* XXX */  /* User preferences */  else if (nua_local_refresher == NH_PGET(nh, refresher))    ss->ss_refresher = nua_local_refresher;  else    ss->ss_refresher = nua_remote_refresher;  return 0;}static voidset_session_timer(nua_handle_t *nh){  struct nua_session_state *ss = nh->nh_ss;  nua_dialog_usage_t *du = ss->ss_usage;  assert(du);  if (du == NULL)    ;  else if (ss->ss_refresher == nua_local_refresher) {    nua_dialog_usage_set_refresh(du, ss->ss_session_timer);    du->du_pending = refresh_invite; /* Set timer */  }  else if (ss->ss_refresher == nua_remote_refresher) {    nua_dialog_usage_set_refresh(du, ss->ss_session_timer + 32);    du->du_pending = session_timeout; /* Set timer */  }  else {    du->du_refresh = 0;    du->du_pending = NULL;  }}static intis_session_timer_set(nua_session_state_t *ss){  return ss->ss_usage &&    (ss->ss_usage->du_pending == refresh_invite ||     ss->ss_usage->du_pending == session_timeout);}/* ---------------------------------------------------------------------- *//* Automatic notifications from a referral */static intnh_referral_check(nua_handle_t *nh, tagi_t const *tags){  sip_event_t const *event = NULL;  int pause = 1;  struct nua_referral *ref = nh->nh_referral;  nua_handle_t *ref_handle = ref->ref_handle;  if (!ref_handle      &&      tl_gets(tags,	      NUTAG_NOTIFY_REFER_REF(ref_handle),	      NUTAG_REFER_EVENT_REF(event),	      NUTAG_REFER_PAUSE_REF(pause),	      TAG_END()) == 0      &&      tl_gets(nh->nh_tags,	      NUTAG_NOTIFY_REFER_REF(ref_handle),	      NUTAG_REFER_EVENT_REF(event),	      NUTAG_REFER_PAUSE_REF(pause),	      TAG_END()) == 0)    return 0;  if (!ref_handle)    return 0;  /* Remove nh_referral and nh_notevent */  tl_tremove(nh->nh_tags,	     NUTAG_NOTIFY_REFER(ref_handle),	     TAG_IF(event, NUTAG_REFER_EVENT(event)),	     TAG_END());  if (event)    ref->ref_event = sip_event_dup(nh->nh_home, event);  if (!nh_validate(nh->nh_nua, ref_handle)) {    SU_DEBUG_3(("nua: invalid NOTIFY_REFER handle\n"));    return -1;  }  else if (!ref->ref_event) {    SU_DEBUG_3(("nua: NOTIFY event missing\n"));    return -1;  }  if (ref_handle != ref->ref_handle) {    if (ref->ref_handle)      nua_handle_unref(ref->ref_handle);    ref->ref_handle = nua_handle_ref(ref_handle);  }#if 0  if (pause) {    /* Pause media on REFER handle */    nmedia_pause(nua, ref_handle->nh_nm, NULL);  }#endif  return 0;}static voidnh_referral_respond(nua_handle_t *nh, int status, char const *phrase){  char payload[128];  char const *substate;  struct nua_referral *ref = nh->nh_referral;  if (!nh_validate(nh->nh_nua, ref->ref_handle)) {    if (ref) {      if (ref->ref_handle)	SU_DEBUG_1(("nh_handle_referral: stale referral handle %p\n",		    ref->ref_handle));      ref->ref_handle = NULL;    }    return;  }  /* XXX - we should have a policy here whether to send 101..199 */  assert(ref->ref_event);  if (status >= 300)    status = 503, phrase = sip_503_Service_unavailable;  snprintf(payload, sizeof(payload), "SIP/2.0 %03u %s\r\n", status, phrase);  if (status < 200)    substate = "active";  else    substate = "terminated ;reason=noresource";  nua_stack_post_signal(ref->ref_handle,			nua_r_notify,			SIPTAG_EVENT(ref->ref_event),			SIPTAG_SUBSCRIPTION_STATE_STR(substate),			SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),			SIPTAG_PAYLOAD_STR(payload),			TAG_END());  if (status < 200)    return;  su_free(nh->nh_home, ref->ref_event), ref->ref_event = NULL;  nua_handle_unref(ref->ref_handle), ref->ref_handle = NULL;}/** Zap the session associated with the handle */staticvoid nsession_destroy(nua_handle_t *nh){  struct nua_session_state *ss = nh->nh_ss;  ss->ss_active = 0;  ss->ss_state = nua_callstate_init;  /* Remove usage */  if (ss->ss_usage)    nua_dialog_usage_remove(nh, nh->nh_ds, ss->ss_usage);  ss->ss_usage = 0;  nh->nh_has_invite = 0;  if (nh->nh_soa)    soa_destroy(nh->nh_soa), nh->nh_soa = NULL;  ss->ss_srequest->sr_respond = NULL;  SU_DEBUG_5(("nua: terminated session %p\n", nh));}/* ======================================================================== *//* INFO */static int process_response_to_info(nua_handle_t *nh,				       nta_outgoing_t *orq,				       sip_t const *sip);intnua_stack_info(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){  struct nua_client_request *cr = nh->nh_cr;  msg_t *msg;  if (nh_is_special(nh)) {    return UA_EVENT2(e, 900, "Invalid handle for INFO");  }  else if (cr->cr_orq) {    return UA_EVENT2(e, 900, "Request already in progress");  }  nua_stack_init_handle(nua, nh, nh_has_nothing, NULL, TAG_NEXT(tags));  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,			 SIP_METHOD_INFO ,			 NUTAG_ADD_CONTACT(1),			 TAG_NEXT(tags));  cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,				    process_response_to_info, nh, NULL,				    msg,				    SIPTAG_END(), TAG_NEXT(tags));  if (!cr->cr_orq) {    msg_destroy(msg);    return UA_EVENT1(e, NUA_INTERNAL_ERROR);  }  return cr->cr_event = e;}void restart_info(nua_handle_t *nh, tagi_t *tags){  nua_creq_restart(nh, nh->nh_cr, process_response_to_info, tags);}static int process_response_to_info(nua_handle_t *nh,				    nta_outgoing_t *orq,				    sip_t const *sip){  if (nua_creq_check_restart(nh, nh->nh_cr, orq, sip, restart_info))    return 0;  return nua_stack_process_response(nh, nh->nh_cr, orq, sip, TAG_END());}int nua_stack_process_info(nua_t *nua,			   nua_handle_t *nh,			   nta_incoming_t *irq,			   sip_t const *sip){  nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),	   nua_i_info, SIP_200_OK, TAG_END());  return 200;		/* Respond automatically with 200 Ok */}/* ======================================================================== *//* UPDATE */static int process_response_to_update(nua_handle_t *nh,				       nta_outgoing_t *orq,				       sip_t const *sip);intnua_stack_update(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){  struct nua_session_state *ss = nh->nh_ss;  struct nua_client_request *cr = nh->nh_cr;  struct nua_client_request *cri = ss->ss_crequest;  struct nua_server_request *sri = ss->ss_srequest;  msg_t *msg;  sip_t *sip;  char const *offer_sent = 0;  if (!nh_has_session(nh))    return UA_EVENT2(e, 900, "Invalid handle for UPDATE");  else if (cr->cr_orq)    return UA_EVENT2(e, 900, "Request already in progress");  nua_stack_init_handle(nua, nh, nh_has_nothing, NULL, TAG_NEXT(tags));  msg = nua_creq_msg(nua, nh, cr, cr->cr_retry_count,			 SIP_METHOD_UPDATE,			 NUTAG_USE_DIALOG(1),			 NUTAG_ADD_CONTACT(1),			 TAG_NEXT(tags));  sip = sip_object(msg);  if (sip) {    if (nh->nh_soa && !sip->sip_payload &&	!(cri->cr_offer_sent && !cri->cr_answer_recv) &&	!(cri->cr_offer_recv && !cri->cr_answer_sent) &&	!(sri->sr_offer_sent && !sri->sr_answer_recv) &&	!(sri->sr_offer_recv && !sri->sr_answer_sent)) {      soa_init_offer_answer(nh->nh_soa);      if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0 ||	  session_include_description(nh->nh_soa, msg, sip) < 0) {	if (ss->ss_state < nua_callstate_ready) {	  /* XXX */	}	msg_destroy(msg);	return UA_EVENT2(e, 900, "Local media failed");      }      offer_sent = "offer";    }    if (is_session_timer_set(ss))      /* Add session timer headers */      use_session_timer(nh, 0, msg, sip);    if (nh->nh_auth) {      if (auc_authorize(&nh->nh_auth, msg, sip) < 0)	/* xyzzy */;    }    cr->cr_orq = nta_outgoing_mcreate(nua->nua_nta,				      process_response_to_update, nh, NULL,				      msg,				      SIPTAG_END(), TAG_NEXT(tags));    if (cr->cr_orq) {      if (offer_sent)	cr->cr_offer_sent = 1;      ss->ss_update_needed = 0;      signal_call_state_change(nh, 0, "UPDATE sent",			       ss->ss_state, 0, offer_sent);      return cr->cr_event = e;    }  }  msg_destroy(msg);  return UA_EVENT1(e, NUA_INTERNAL_ERROR);}void restart_update(nua_handle_t *nh, tagi_t *tags){  nua_creq_restart(nh, nh->nh_cr, process_response_to_update, tags);}static int process_response_to_update(nua_handle_t *nh,				       nta_outgoing_t *orq,				       sip_t const *sip){  nua_t *nua = nh->nh_nua;  struct nua_session_state *ss = nh->nh_ss;  struct nua_client_request *cr = nh->nh_cr;  int status = sip->sip_status->st_status;  char const *phrase = sip->sip_status->st_phrase;  char const *recv = NULL;  int terminate = 0, gracefully = 1;  if (status >= 300) {    if (sip->sip_retry_after)      gracefully = 0;    terminate = sip_response_terminates_dialog(status, sip_method_invite,					       &gracefully);    if (!terminate &&	nua_creq_check_restart(nh, cr, orq, sip, restart_update)) {      return 0;    }    /* XXX - if we have a concurrent INVITE, what we do with it? */  }  else if (status >= 200) {    /* XXX - check remote tag, handle forks */    /* Set (route), contact, (remote tag) */    nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);    nua_dialog_store_peer_info(nh, nh->nh_ds, sip);    if (is_session_timer_set(ss)) {      init_session_timer(nh, sip);      set_session_timer(nh);    }    if (session_process_response(nh, cr, orq, sip, &recv) < 0) {      nua_stack_event(nua, nh, NULL, nua_i_error,	       400, "Bad Session Description", TAG_END());    }    signal_call_state_change(nh, status, phrase, ss->ss_state, recv, 0);    return 0;  }  else    gracefully = 0;  nua_stack_process_response(nh, cr, orq, sip, TAG_END());  if (terminate || gracefully)    nh_referral_respond(nh, status, phrase);  if (terminate) {    signal_call_state_change(nh, status, phrase,			     nua_callstate_terminated, recv, 0);    nsession_destroy(nh);  }  else if (gracefully) {    signal_call_state_change(nh, status, phrase,			     nua_callstate_terminating, recv, 0);#if 0    if (nh->nh_ss->ss_crequest->cr_orq)      nua_stack_post_signal(nh, nua_r_cancel, TAG_END());    else#endif      nua_stack_post_signal(nh, nua_r_bye, TAG_END());  }  return 0;}int nua_stack_process_update(nua_t *nua,			     nua_handle_t *nh,			     nta_incoming_t *irq,			     sip_t const *sip){  struct nua_session_state *ss = nh->nh_ss;  nua_dialog_usage_t *du = ss->ss_usage;  msg_t *msg = nta_incoming_getrequest(irq);  char const *sdp;  size_t len;  int original_status = 200, status = 200;

⌨️ 快捷键说明

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