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

📄 nua_session.c

📁 this is simple sip stack.
💻 C
📖 第 1 页 / 共 5 页
字号:
  char const *phrase = sip_200_OK;  char const *offer_recv = NULL, *answer_sent = NULL;  int do_timer = 0;  msg_t *rmsg;  sip_t *rsip;  assert(nh);  if (!du) {    nua_dialog_state_t *ds = nh->nh_ds;    /* No session for this dialog */    nta_incoming_treply(irq,			SET_STATUS1(SIP_405_METHOD_NOT_ALLOWED),			TAG_IF(ds->ds_has_subscribes,			       SIPTAG_ALLOW_STR("NOTIFY")),			TAG_IF(ds->ds_has_notifys,			       SIPTAG_ALLOW_STR("SUBSCRIBE, REFER")),			TAG_END());  }  /* Do session timer negotiation if there is no ongoing INVITE transaction */  if (status < 300 &&      sip->sip_session_expires &&      is_session_timer_set(ss))    do_timer = 1, init_session_timer(nh, sip);  if (status < 300 && nh->nh_soa &&      session_get_description(msg, sip, &sdp, &len)) {    offer_recv = "offer";    if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {      SU_DEBUG_5(("nua(%p): error parsing SDP in UPDATE\n", nh));      msg_destroy(msg);      status = soa_error_as_sip_response(nh->nh_soa, &phrase);      offer_recv = NULL;    }    /* Respond to UPDATE */    else if (soa_generate_answer(nh->nh_soa, NULL) < 0) {      SU_DEBUG_5(("nua(%p): error processing SDP in UPDATE\n", nh));      msg_destroy(msg);      status = soa_error_as_sip_response(nh->nh_soa, &phrase);    }    else if (soa_activate(nh->nh_soa, NULL) < 0) {      SU_DEBUG_5(("nua(%p): error activating media after %s\n",		  nh, "UPDATE"));      /* XXX */    }    else {      answer_sent = "answer";    }  }  rmsg = nh_make_response(nua, nh, irq,			  status, phrase,			  TAG_IF(status < 300, NUTAG_ADD_CONTACT(1)),			  SIPTAG_SUPPORTED(NH_PGET(nh, supported)),			  TAG_NEXT(NULL));  rsip = sip_object(rmsg);  assert(sip);			/* XXX */  if (answer_sent && session_include_description(nh->nh_soa, rmsg, rsip) < 0) {    status = 500, phrase = sip_500_Internal_server_error;    answer_sent = NULL;  }  if (do_timer && 200 <= status && status < 300) {    use_session_timer(nh, 1, rmsg, rsip);    set_session_timer(nh);  }  if (status == original_status) {    if (nta_incoming_mreply(irq, rmsg) < 0)      status = 500, phrase = sip_500_Internal_server_error;  }  if (status != original_status) {    nua_stack_event(nua, nh, NULL, nua_i_error, status, phrase, TAG_END());    nta_incoming_treply(irq, status, phrase, TAG_END());    msg_destroy(rmsg), rmsg = NULL;  }  nua_stack_event(nh->nh_nua, nh, msg, nua_i_update, status, phrase, TAG_END());  if (offer_recv || answer_sent)    /* signal offer received, answer sent */    signal_call_state_change(nh, 200, "OK", ss->ss_state,			     offer_recv, answer_sent);  if (NH_PGET(nh, auto_alert)      && ss->ss_state < nua_callstate_ready      && !ss->ss_alerting      && ss->ss_precondition)    respond_to_invite(nh->nh_nua, nh, SIP_180_RINGING, NULL);  return status;}/* ======================================================================== *//* BYE */static int process_response_to_bye(nua_handle_t *nh,				   nta_outgoing_t *orq,				   sip_t const *sip);intnua_stack_bye(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags){  nua_session_state_t *ss = nh->nh_ss;  nua_client_request_t *cr = nh->nh_cr;  nua_client_request_t *cr_invite = ss->ss_crequest;  msg_t *msg;  nta_outgoing_t *orq;  if (nh_is_special(nh))    return UA_EVENT2(e, 900, "Invalid handle for BYE");  if (!nua_dialog_is_established(nh->nh_ds)) {    if (cr_invite->cr_orq == NULL)      return UA_EVENT2(e, 900, "No session to BYE");    /* No (early) dialog. BYE is invalid action, do CANCEL instead */    orq = nta_outgoing_tcancel(cr_invite->cr_orq,			       process_response_to_bye, nh,			       TAG_NEXT(tags));    if (!cr->cr_orq)      cr->cr_orq = orq, cr->cr_event = e;    return 0;  }  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_BYE,			 TAG_NEXT(tags));  orq = nta_outgoing_mcreate(nua->nua_nta,			     process_response_to_bye, nh, NULL,			     msg,			     SIPTAG_END(), TAG_NEXT(tags));  ss->ss_state = nua_callstate_terminating;  if (nh->nh_soa)    soa_terminate(nh->nh_soa, 0);  if (!orq) {    msg_destroy(msg);    UA_EVENT2(e, 400, "Internal error");    if (cr_invite->cr_orq == NULL)      signal_call_state_change(nh, 400, "Failure sending BYE",			       nua_callstate_terminated, 0, 0);    return 0;  }  if (cr->cr_orq == NULL)    cr->cr_orq = orq, cr->cr_event = e;  return 0;}void restart_bye(nua_handle_t *nh, tagi_t *tags){  nua_creq_restart(nh, nh->nh_cr, process_response_to_bye, tags);}static int process_response_to_bye(nua_handle_t *nh,				   nta_outgoing_t *orq,				   sip_t const *sip){  nua_session_state_t *ss = nh->nh_ss;  nua_client_request_t *cr_invite = ss->ss_crequest;  nua_client_request_t *cr = nh->nh_cr;  int status = sip ? sip->sip_status->st_status : 400;  if (nua_creq_check_restart(nh, cr, orq, sip, restart_bye))    return 0;  nua_stack_process_response(nh, cr, orq, sip, TAG_END());  if (status >= 200 && cr_invite->cr_orq == NULL) {    signal_call_state_change(nh, status, "to BYE",			     nua_callstate_terminated, 0, 0);    nsession_destroy(nh);  }  return 0;}int nua_stack_process_bye(nua_t *nua,			  nua_handle_t *nh,			  nta_incoming_t *irq,			  sip_t const *sip){  struct nua_session_state *ss = nh->nh_ss;  nua_server_request_t *sr = ss->ss_srequest;  int early = 0;  assert(nh);  nua_stack_event(nh->nh_nua, nh, nta_incoming_getrequest(irq),	   nua_i_bye, SIP_200_OK, TAG_END());  nta_incoming_treply(irq, SIP_200_OK, TAG_END());  nta_incoming_destroy(irq), irq = NULL;  if (sr->sr_irq) {    char const *phrase;    early = ss->ss_state < nua_callstate_ready;    phrase = early ? "Early Session Terminated" : "Session Terminated";    nta_incoming_treply(sr->sr_irq, 487, phrase, TAG_END());    nta_incoming_destroy(sr->sr_irq);    memset(sr, 0, sizeof *sr);  }  nsession_destroy(nh);  signal_call_state_change(nh, 200,			   early ? "Received early BYE" : "Received BYE",			   nua_callstate_terminated, 0, 0);  return 200;			/* Respond automatically with 200 Ok */}/* ---------------------------------------------------------------------- *//** * Delivers call state changed event to the nua client. * * @param nh call handle * @param status status code * @param tr_event SIP transaction event triggering this change * @param oa_recv Received SDP * @param oa_sent Sent SDP */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){  struct nua_session_state *ss = nh->nh_ss;  nua_server_request_t *sr = ss->ss_srequest;  enum nua_callstate ss_state = ss->ss_state;  sdp_session_t const *remote_sdp = NULL;  char const *remote_sdp_str = NULL;  sdp_session_t const *local_sdp = NULL;  char const *local_sdp_str = NULL;  int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;  if (ss_state != nua_callstate_ready || next_state > nua_callstate_ready)    SU_DEBUG_5(("nua(%p): call state changed: %s -> %s%s%s%s%s\n",		nh, nua_callstate_name(ss_state),		nua_callstate_name(next_state),		oa_recv ? ", received " : "", oa_recv ? oa_recv : "",		oa_sent && oa_recv ? ", and sent " :		oa_sent ? ", sent " : "", oa_sent ? oa_sent : ""));  else    SU_DEBUG_5(("nua(%p): ready call updated: %s%s%s%s%s\n",		nh, nua_callstate_name(next_state),		oa_recv ? " received " : "", oa_recv ? oa_recv : "",		oa_sent && oa_recv ? ", sent " :		oa_sent ? " sent " : "", oa_sent ? oa_sent : ""));  if (oa_recv) {    soa_get_remote_sdp(nh->nh_soa, &remote_sdp, &remote_sdp_str, 0);    offer_recv = strcasecmp(oa_recv, "offer") == 0;    answer_recv = strcasecmp(oa_recv, "answer") == 0;  }  if (oa_sent) {    soa_get_local_sdp(nh->nh_soa, &local_sdp, &local_sdp_str, 0);    offer_sent = strcasecmp(oa_sent, "offer") == 0;    answer_sent = strcasecmp(oa_sent, "answer") == 0;  }  if (answer_recv || answer_sent) {    /* Update ss->ss_hold_remote */    char const *held;    soa_get_params(nh->nh_soa, SOATAG_HOLD_REF(held), TAG_END());    ss->ss_hold_remote = held && strlen(held) > 0;  }  (void)sr;  /* Update state variables */  if (next_state > ss_state)    ss->ss_state = next_state;  else if (next_state == nua_callstate_init && ss_state < nua_callstate_ready)    ss->ss_state = nua_callstate_init, next_state = nua_callstate_terminated;  if (next_state == nua_callstate_ready)    ss->ss_active = 1;  else if (next_state == nua_callstate_terminated)    ss->ss_active = 0;  /* Send events */  if (phrase == NULL)    phrase = "Call state";  nua_stack_event(nh->nh_nua, nh, NULL, nua_i_state,	   status, phrase,	   NUTAG_CALLSTATE(next_state),	   NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa),	   /* NUTAG_SOA_SESSION(nh->nh_soa), */	   TAG_IF(offer_recv, NUTAG_OFFER_RECV(offer_recv)),	   TAG_IF(answer_recv, NUTAG_ANSWER_RECV(answer_recv)),	   TAG_IF(offer_sent, NUTAG_OFFER_SENT(offer_sent)),	   TAG_IF(answer_sent, NUTAG_ANSWER_SENT(answer_sent)),	   TAG_IF(oa_recv, SOATAG_REMOTE_SDP(remote_sdp)),	   TAG_IF(oa_recv, SOATAG_REMOTE_SDP_STR(remote_sdp_str)),	   TAG_IF(oa_sent, SOATAG_LOCAL_SDP(local_sdp)),	   TAG_IF(oa_sent, SOATAG_LOCAL_SDP_STR(local_sdp_str)),	   TAG_END());  if (next_state == nua_callstate_ready && ss_state <= nua_callstate_ready) {    nua_stack_event(nh->nh_nua, nh, NULL, nua_i_active, status, "Call active",	     NH_ACTIVE_MEDIA_TAGS(1, nh->nh_soa),	     /* NUTAG_SOA_SESSION(nh->nh_soa), */	     TAG_END());  }  else if (next_state == nua_callstate_terminated) {    nua_stack_event(nh->nh_nua, nh, NULL, nua_i_terminated, status, phrase,	     TAG_END());  }}/* ======================================================================== *//** Get SDP from a SIP message */staticint session_get_description(msg_t *msg,			    sip_t const *sip,			    char const **return_sdp,			    size_t *return_len){  sip_payload_t const *pl = sip->sip_payload;  sip_content_type_t const *ct = sip->sip_content_type;  int matching_content_type = 0;  if (pl == NULL)    return 0;  else if (pl->pl_len == 0 || pl->pl_data == NULL)    return 0;  else if (ct == NULL)    /* Be bug-compatible with our old gateways */    SU_DEBUG_3(("nua: no %s, assuming %s\n",		"Content-Type", SDP_MIME_TYPE));  else if (ct->c_type == NULL)    SU_DEBUG_3(("nua: empty %s, assuming %s\n",		"Content-Type", SDP_MIME_TYPE));  else if (strcasecmp(ct->c_type, SDP_MIME_TYPE)) {    SU_DEBUG_5(("nua: unknown %s: %s\n", "Content-Type", ct->c_type));    return 0;  }  else    matching_content_type = 1;  if (pl == NULL)    return 0;  if (!matching_content_type) {    /* Make sure we got SDP */    if (pl->pl_len < 3 || strncasecmp(pl->pl_data, "v=0", 3))      return 0;  }  *return_sdp = pl->pl_data;  *return_len = pl->pl_len;  return 1;}/** Insert SDP into SIP message */staticint session_include_description(soa_session_t *soa,				msg_t *msg,				sip_t *sip){  su_home_t *home = msg_home(msg);  sip_content_disposition_t *cd;  sip_content_type_t *ct;  sip_payload_t *pl;  if (!soa)    return 0;  if (session_make_description(home, soa, &cd, &ct, &pl) < 0)    return -1;  if (pl == NULL || ct == NULL || cd == NULL ||      sip_header_insert(msg, sip, (sip_header_t *)cd) < 0 ||      sip_header_insert(msg, sip, (sip_header_t *)ct) < 0 ||      sip_header_insert(msg, sip, (sip_header_t *)pl) < 0)    return -1;  return 0;}/** Generate SDP headers */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){  char const *sdp;  int len;  if (!soa)    return 0;  if (soa_get_local_sdp(soa, 0, &sdp, &len) < 0)    return -1;  *return_pl = sip_payload_create(home, sdp, len);  *return_ct = sip_content_type_make(home, SDP_MIME_TYPE);  *return_cd = sip_content_disposition_make(home, "session");  return 0;}/** * Stores and processes SDP from incoming response, then calls * nua_stack_process_response(). * * @retval 1 if there was SDP to process. */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){  char const *method = nta_outgoing_method_name(orq);  msg_t *msg = nta_outgoing_getresponse(orq);  int retval = 0;  char const *sdp = NULL;  size_t len;  if (nh->nh_soa == NULL)    /* Xyzzy */;  else if (!session_get_description(msg, sip, &sdp, &len))    /* No SDP */;  else if (cr->cr_answer_recv) {    /* Ignore spurious answers after completing O/A */    SU_DEBUG_3(("nua(%p): %s: ignoring duplicate SDP in %u %s\n",		nh, method,		sip->sip_status->st_status, sip->sip_status->st_phrase));    sdp = NULL;  }  else if (!cr->cr_offer_sent &&	   nta_outgoing_method(orq) != sip_method_invite) {    /* If non-invite request did not have offer, ignore SDP in response */    SU_DEBUG_3(("nua(%p): %s: ignoring extra SDP in %u %s\n",		nh, method,		sip->sip_status->st_status, sip->sip_status->st_phrase));    sdp = NULL;  }  else {    if (cr->cr_offer_sent) {      cr->cr_answer_recv = sip->sip_status->st_status;      *return_received = "answer";    }    else {      cr->cr_offer_recv = 1, cr->cr_answer_sent = 0;      *return_received = "offer";    }    if (soa_s

⌨️ 快捷键说明

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