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

📄 nua_session.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 5 页
字号:
    ss->ss_reporting = 1;	/* We report terminated state here if BYE fails */    error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL);    ss->ss_reporting = 0;    signal_call_state_change(nh, ss, 500, "Internal Error", 			     error 			     ? nua_callstate_terminated			     : nua_callstate_terminating);  }  else if (ss)    signal_call_state_change(nh, ss, 200, "ACK sent", nua_callstate_ready);  if (!nua_client_is_queued(cr) && !nua_client_is_bound(cr))    nua_client_request_destroy(cr);  nua_client_next_request(nh->nh_ds->ds_cr, 1);  return 0;}/** Send ACK, destroy INVITE transaction. * *  @retval 1 if successful *  @retval < 0 if an error occurred */staticint nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags){  nua_handle_t *nh = cr->cr_owner;  nua_dialog_state_t *ds = nh->nh_ds;  nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage);  msg_t *msg;  sip_t *sip;  int error = -1;  sip_authorization_t *wa;  sip_proxy_authorization_t *pa;  sip_cseq_t *cseq;  int proxy_is_set;  url_string_t *proxy;  nta_outgoing_t *ack;  int status = 200;  char const *phrase = "OK", *reason = NULL;  char const *invite_branch;  assert(cr->cr_orq);  assert(cr->cr_method == sip_method_invite);  if (!ds->ds_leg) {    /* XXX - fix nua_dialog_usage_remove_at() instead! */    nta_outgoing_destroy(cr->cr_orq);    return -1;  }  assert(ds->ds_leg);  msg = nta_outgoing_getrequest(cr->cr_orq);  sip = sip_object(msg);  if (!msg)    return -1;  invite_branch = nta_outgoing_branch(cr->cr_orq);  wa = sip_authorization(sip);  pa = sip_proxy_authorization(sip);    msg_destroy(msg);  msg = nta_msg_create(nh->nh_nua->nua_nta, 0);  sip = sip_object(msg);    if (!msg)    return -1;  cseq = sip_cseq_create(msg_home(msg), cr->cr_seq, SIP_METHOD_ACK);  if (!cseq)    ;  else if (nh->nh_tags && sip_add_tl(msg, sip, TAG_NEXT(nh->nh_tags)) < 0)    ;  else if (tags && sip_add_tl(msg, sip, TAG_NEXT(tags)) < 0)    ;  else if (wa && sip_add_dup(msg, sip, (sip_header_t *)wa) < 0)    ;  else if (pa && sip_add_dup(msg, sip, (sip_header_t *)pa) < 0)    ;  else if (sip_header_insert(msg, sip, (sip_header_t *)cseq) < 0)    ;  else if (nta_msg_request_complete(msg, ds->ds_leg, SIP_METHOD_ACK, NULL) < 0)    ;  else {    /* Remove extra headers */    while (sip->sip_allow)      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_allow);    while (sip->sip_priority)      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_priority);    while (sip->sip_proxy_require)      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_proxy_require);    while (sip->sip_require)      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_require);    while (sip->sip_subject)      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_subject);    while (sip->sip_supported)      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_supported);    if (ss == NULL || ss->ss_state >= nua_callstate_ready)      ;    else if (cr->cr_offer_recv && !cr->cr_answer_sent) {      if (nh->nh_soa == NULL) {	if (session_get_description(sip, NULL, NULL))	  cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer;      }      else if (soa_generate_answer(nh->nh_soa, NULL) < 0 ||	  session_include_description(nh->nh_soa, 1, msg, sip) < 0) {	status = 900, phrase = "Internal media error";	reason = "SIP;cause=500;text=\"Internal media error\"";	/* reason = soa_error_as_sip_reason(nh->nh_soa); */      }      else {	cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer;      }    }    if (ss == NULL || ss->ss_state >= nua_callstate_ready || reason)      ;    else if (nh->nh_soa && soa_is_complete(nh->nh_soa)) {      /* signal SOA that O/A round(s) is (are) complete */	soa_activate(nh->nh_soa, NULL);    }    else if (nh->nh_soa == NULL	     /* NUA does not necessarily know dirty details */	     /* && !(cr->cr_offer_sent && !cr->cr_answer_recv) */) {      ;    }    else {      nua_client_request_t *cru;      /* Final response to UPDATE or PRACK may be on its way ... */      for (cru = ds->ds_cr; cru; cru = cru->cr_next) {	if (cr != cru && cru->cr_offer_sent && !cru->cr_answer_recv)	  break;      }      if (cru == NULL) {	/* No SDP answer -> terminate call */	status = 988, phrase = "Incomplete offer/answer";	reason = "SIP;cause=488;text=\"Incomplete offer/answer\"";      }    }        proxy_is_set = NH_PISSET(nh, proxy);    proxy = NH_PGET(nh, proxy);    if ((ack = nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL, NULL, NULL,				    msg,				    NTATAG_ACK_BRANCH(invite_branch),				    TAG_IF(proxy_is_set,					   NTATAG_DEFAULT_PROXY(proxy)),				    SIPTAG_END(),				    TAG_NEXT(tags)))) {      /* TR engine keeps this around for T2 so it catches all 2XX retransmissions  */      nta_outgoing_destroy(ack);      if (nh->nh_soa && reason && ss && ss->ss_state <= nua_callstate_ready)	nua_stack_event(nh->nh_nua, nh, NULL,			nua_i_media_error, status, phrase,			NULL);    }    else if (!reason) {      status = 900, phrase = "Cannot send ACK";      reason = "SIP;cause=500;text=\"Internal Error\"";    }    if (ss && reason)      ss->ss_reason = reason;    if (status < 300)      error = 1;    else      error = -2;  }  if (error == -1)    msg_destroy(msg);  nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL;  nua_client_request_remove(cr);    return error;}/** Complete client request */static int nua_invite_client_complete(nua_client_request_t *cr){  if (cr->cr_orq == NULL)    /* Xyzzy */;  else if (cr->cr_status < 200)    nta_outgoing_cancel(cr->cr_orq);  else    nua_invite_client_ack(cr, NULL);  return 0;}/**@fn void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...); * * Cancel an INVITE operation  * * @param nh              Pointer to operation handle * @param tag, value, ... List of tagged parameters * * @return  *    nothing * * @par Related Tags: *    Header tags defined in <sofia-sip/sip_tag.h> * * @par Events: *    #nua_r_cancel, #nua_i_state  (#nua_i_active, #nua_i_terminated) * * @sa @ref nua_call_model, nua_invite(), #nua_i_cancel */static int nua_cancel_client_request(nua_client_request_t *cr,				     msg_t *msg, sip_t *sip,				     tagi_t const *tags);nua_client_methods_t const nua_cancel_client_methods = {  SIP_METHOD_CANCEL,		/* crm_method, crm_method_name */  0,				/* crm_extra */  {				/* crm_flags */    /* create_dialog */ 0,    /* in_dialog */ 1,    /* target refresh */ 0  },  NULL,				/* crm_template */  NULL,				/* crm_init */  nua_cancel_client_request,	/* crm_send */  NULL,				/* crm_check_restart */  NULL,				/* crm_recv */  NULL,				/* crm_preliminary */  NULL,				/* crm_report */  NULL,				/* crm_complete */};int nua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e,		     tagi_t const *tags){  return nua_client_create(nh, e, &nua_cancel_client_methods, tags);}static int nua_cancel_client_request(nua_client_request_t *cr,				     msg_t *msg, sip_t *sip,				     tagi_t const *tags){  nua_handle_t *nh = cr->cr_owner;  nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);  if (!du || !du->du_cr || !du->du_cr->cr_orq ||       nta_outgoing_status(du->du_cr->cr_orq) >= 200) {    return nua_client_return(cr, 481, "No transaction to CANCEL", msg);  }  cr->cr_orq = nta_outgoing_tcancel(du->du_cr->cr_orq,				    nua_client_orq_response, cr,				    TAG_NEXT(tags));  return cr->cr_orq ? 0 : -1;}/** @NUA_EVENT nua_r_cancel * * Answer to outgoing CANCEL. * * The CANCEL may be sent explicitly by nua_cancel() or implicitly by NUA * state machine. * * @param status response status code  * @param phrase a short textual description of @a status code * @param nh     operation handle associated with the call * @param hmagic application context associated with the call * @param sip    response to CANCEL request or NULL upon an error *               (status code is in @a status and  *                descriptive message in @a phrase parameters) * @param tags   empty * * @sa nua_cancel(), @ref nua_uac_call_model, #nua_r_invite, nua_invite(), * #nua_i_state * * @END_NUA_EVENT */static void nua_session_usage_refresh(nua_handle_t *nh,				      nua_dialog_state_t *ds,				      nua_dialog_usage_t *du,				      sip_time_t now){  nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du);  nua_client_request_t const *cr = du->du_cr;  nua_server_request_t const *sr;  if (ss->ss_state >= nua_callstate_terminating ||       /* INVITE is in progress or being authenticated */      (cr && (cr->cr_orq || cr->cr_wait_for_cred)))    return;  /* UPDATE has been queued */  for (cr = ds->ds_cr; cr; cr = cr->cr_next)     if (cr->cr_method == sip_method_update)      return;  /* INVITE or UPDATE in progress on server side */  for (sr = ds->ds_sr; sr; sr = sr->sr_next)    if (sr->sr_usage == du && 	(sr->sr_method == sip_method_invite || 	 sr->sr_method == sip_method_update))      return;  if (ss->ss_timer->refresher == nua_remote_refresher) {    ss->ss_reason = "SIP;cause=408;text=\"Session timeout\"";     nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL);    return;  }  else if (NH_PGET(nh, update_refresh)) {    nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL);  }  else if (du->du_cr) {    nua_client_resend_request(du->du_cr, 0);  }  else {    nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL);  }}/** @interal Shut down session usage.  * * @retval >0  shutdown done * @retval 0   shutdown in progress * @retval <0  try again later */static int nua_session_usage_shutdown(nua_handle_t *nh,				      nua_dialog_state_t *ds,				      nua_dialog_usage_t *du){  nua_session_usage_t *ss = NUA_DIALOG_USAGE_PRIVATE(du);  nua_server_request_t *sr, *sr_next;  nua_client_request_t *cri;  assert(ss == nua_session_usage_for_dialog(nh->nh_ds));  /* Zap server-side transactions */  for (sr = ds->ds_sr; sr; sr = sr_next) {    sr_next = sr->sr_next;    if (sr->sr_usage == du) {      assert(sr->sr_usage == du);      sr->sr_usage = NULL;      if (nua_server_request_is_pending(sr)) {	SR_STATUS1(sr, SIP_480_TEMPORARILY_UNAVAILABLE);	nua_server_respond(sr, NULL);	if (nua_server_report(sr) >= 2)	  return 480;      }      else	nua_server_request_destroy(sr);    }  }  cri = du->du_cr;  switch (ss->ss_state) {  case nua_callstate_calling:  case nua_callstate_proceeding:    return nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL);  case nua_callstate_completing:  case nua_callstate_completed:  case nua_callstate_ready:    if (cri && cri->cr_orq) {      if (cri->cr_status < 200)	nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL);      else if (cri->cr_status < 300)	nua_invite_client_ack(cri, NULL);    }    if (nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL) != 0)      break;    signal_call_state_change(nh, ss, 487, "BYE sent",			     nua_callstate_terminating);    return 0;  case nua_callstate_terminating:  case nua_callstate_terminated: /* XXX */    return 0;  default:    break;

⌨️ 快捷键说明

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