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

📄 outbound.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 3 页
字号:
  return 0;}/** @internal Check if there is a NAT between us and registrar. * * @retval -1 upon an error * @retval #ob_register_ok (0) if the registration was OK * @retval #ob_reregister (1) if client needs to re-register * @retval #ob_reregister_now (2) if client needs to re-register immediately */staticint outbound_check_for_nat(outbound_t *ob,			   sip_t const *request,			   sip_t const *response){  int binding_changed;  sip_contact_t *m = ob->ob_rcontact;  /* Update NAT information */  binding_changed = outbound_nat_detect(ob, request, response);  if (!ob->ob_nat_detected)    return ob_no_nat;  /* Contact was set by application, do not change it */  if (!ob->ob_by_stack)    return ob_no_nat;  /* Application does not want us to do any NAT traversal */   if (!ob->ob_prefs.natify)    return ob_no_nat;  /* We have detected NAT. Now, what to do?   * 1) do nothing - register as usual and let proxy take care of it?   * 2) try to detect our public nat binding and use it   * 2A) use public vias from nta generated by STUN or UPnP   * 2B) use SIP Via header   */  /* Do we have to ask for reregistration */  if (!m || binding_changed >= ob_nat_changed) {    if (ob->ob_stun) {      /* Use STUN? */      return ob_reregister;    }    else if (ob->ob_upnp) {      /* Use UPnP */      return ob_reregister;    }    else {      if (outbound_contacts_from_via(ob, response->sip_via) < 0)        return -1;    }    return ob_reregister_now;  }  return 0;}/**@internal * * Detect NAT. * * Based on "received" and possible "rport" parameters in the top-most Via, * check and update our NAT status. * * @retval ob_nat_changed (2) change in public NAT binding detected * @retval ob_nat_detected (1) NAT binding detected * @retval ob_no_nat (0) no NAT binding detected * @retval -1 an error occurred */staticint outbound_nat_detect(outbound_t *ob,			sip_t const *request,			sip_t const *response){  sip_via_t const *v;  int one = 1;  char const *received, *rport;  char *nat_detected, *nat_port;  char *new_detected, *new_port;  assert(request && request->sip_request);  assert(response && response->sip_status);  if (!ob || !response || !response->sip_via || !request->sip_via)    return -1;  v = response->sip_via;  received = v->v_received;  if (!received || !strcmp(received, request->sip_via->v_host))    return 0;  if (!host_is_ip_address(received)) {    if (received[0])      SU_DEBUG_3(("outbound(%p): Via with invalid received=%s\n",		  (void *)ob->ob_owner, received));    return 0;  }  rport = sip_via_port(v, &one); assert(rport);  nat_detected = ob->ob_nat_detected;  nat_port = ob->ob_nat_port;  if (nat_detected && host_cmp(received, nat_detected) == 0) {    if (nat_port && strcasecmp(rport, nat_port) == 0)      return 1;    if (!v->v_rport || !v->v_rport[0])      return 1;  }  if (!nat_detected) {    SU_DEBUG_5(("outbound(%p): detected NAT: %s != %s\n",		(void *)ob->ob_owner, v->v_host, received));    if (ob->ob_oo && ob->ob_oo->oo_status)      ob->ob_oo->oo_status(ob->ob_owner, ob, 101, "NAT detected", TAG_END());  }  else {    SU_DEBUG_5(("outbound(%p): NAT binding changed: "		"[%s]:%s != [%s]:%s\n",		(void *)ob->ob_owner, nat_detected, nat_port, received, rport));    if (ob->ob_oo && ob->ob_oo->oo_status)      ob->ob_oo->oo_status(ob->ob_owner, ob, 102, "NAT binding changed", TAG_END());  }  /* Save our nat binding */  new_detected = su_strdup(ob->ob_home, received);  new_port = su_strdup(ob->ob_home, rport);  if (!new_detected || !new_port) {    su_free(ob->ob_home, new_detected);    su_free(ob->ob_home, new_port);    return -1;  }  ob->ob_nat_detected = new_detected;  ob->ob_nat_port = new_port;  su_free(ob->ob_home, nat_detected);  su_free(ob->ob_home, nat_port);  return 2;}/* ---------------------------------------------------------------------- *//** Convert "gruu" parameter returned by registrar to Contact header. */int outbound_gruuize(outbound_t *ob, sip_t const *sip){  sip_contact_t *m = NULL;  char *gruu;  if (!ob)    return 0;  if (ob->ob_rcontact == NULL)    return -1;  if (!ob->ob_prefs.gruuize && ob->ob_instance) {    char const *my_instance, *my_reg_id = NULL;    char const *instance, *reg_id;    m = ob->ob_rcontact;    my_instance = msg_header_find_param(m->m_common, "+sip.instance=");    if (my_instance)      my_reg_id = msg_header_find_param(m->m_common, "reg-id=");    for (m = sip->sip_contact; m; m = m->m_next) {      if (my_instance) {	instance = msg_header_find_param(m->m_common, "+sip.instance=");	if (!instance || strcmp(instance, my_instance))	  continue;	if (my_reg_id) {	  reg_id = msg_header_find_param(m->m_common, "reg-id=");	  if (!reg_id || strcmp(reg_id, my_reg_id))	    continue;	}      }      if (url_cmp_all(ob->ob_rcontact->m_url, m->m_url) == 0)	break;    }  }  if (m == NULL) {    if (ob->ob_gruu)      msg_header_free(ob->ob_home, (void *)ob->ob_gruu), ob->ob_gruu = NULL;    return 0;  }  gruu = (char *)msg_header_find_param(m->m_common, "pub-gruu=");    if (gruu == NULL || gruu[0] == '\0')    gruu = (char *)msg_header_find_param(m->m_common, "gruu=");  if (gruu == NULL || gruu[0] == '\0')    return 0;  gruu = msg_unquote_dup(NULL, gruu);  m = gruu ? sip_contact_format(ob->ob_home, "<%s>", gruu) : NULL;  su_free(NULL, gruu);  if (!m)    return -1;  if (ob->ob_gruu)    msg_header_free(ob->ob_home, (void *)ob->ob_gruu);  ob->ob_gruu = m;  return 0;}/* ---------------------------------------------------------------------- */static int create_keepalive_message(outbound_t *ob,				    sip_t const *register_request);static int keepalive_options(outbound_t *ob);static int keepalive_options_with_registration_probe(outbound_t *ob);static int response_to_keepalive_options(outbound_t *ob,					 nta_outgoing_t *orq,					 sip_t const *sip);static void keepalive_timer(su_root_magic_t *root_magic,			    su_timer_t *t,			    su_timer_arg_t *ob_as_timer_arg);/** Start OPTIONS keepalive or contact validation process */void outbound_start_keepalive(outbound_t *ob,			      nta_outgoing_t *register_transaction){  unsigned interval = 0;  int need_to_validate;  if (!ob)    return;  if (ob->ob_prefs.natify && ob->ob_prefs.okeepalive)    interval = ob->ob_prefs.interval;  need_to_validate = ob->ob_prefs.validate && !ob->ob_validated;  if (!ob->ob_nat_detected || !register_transaction ||      !(need_to_validate || interval != 0)) {    outbound_stop_keepalive(ob);    return;  }  if (ob->ob_keepalive.timer)    su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL;  if (interval)    ob->ob_keepalive.timer =      su_timer_create(su_root_task(ob->ob_root), interval);  ob->ob_keepalive.interval = interval;  if (!ob->ob_validated && ob->ob_keepalive.sipstun       && 0 /* Stun is disabled for now */) {    nta_tport_keepalive(register_transaction);  }  else {    if (register_transaction) {      msg_t *msg = nta_outgoing_getrequest(register_transaction);      sip_t const *register_request = sip_object(msg);      create_keepalive_message(ob, register_request);      msg_destroy(msg);    }    keepalive_options(ob);  }}void outbound_stop_keepalive(outbound_t *ob){  if (!ob)    return;  ob->ob_keepalive.interval = 0;  if (ob->ob_keepalive.timer)    su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL;  if (ob->ob_keepalive.orq)    nta_outgoing_destroy(ob->ob_keepalive.orq), ob->ob_keepalive.orq = NULL;  if (ob->ob_keepalive.msg)    msg_destroy(ob->ob_keepalive.msg), ob->ob_keepalive.msg = NULL;}/** @internal Create a message template for keepalive. */static int create_keepalive_message(outbound_t *ob, sip_t const *regsip){  msg_t *msg = nta_msg_create(ob->ob_nta, MSG_FLG_COMPACT), *previous;  sip_t *osip = sip_object(msg);  sip_contact_t *m = ob->ob_rcontact;  unsigned d = ob->ob_keepalive.interval;  if (msg == NULL)    return -1;  assert(regsip); assert(regsip->sip_request);  if (m && m->m_params) {    sip_accept_contact_t *ac;    size_t i;    int features = 0;    ac = sip_accept_contact_make(msg_home(msg), "*;require;explicit");    for (i = 0; m->m_params[i]; i++) {      char const *s = m->m_params[i];      if (!sip_is_callerpref(s))	continue;      features++;      s = su_strdup(msg_home(msg), s);      msg_header_add_param(msg_home(msg), ac->cp_common, s);    }        if (features)      msg_header_insert(msg, NULL, (void *)ac);    else      msg_header_free(msg_home(msg), (void *)ac);  }  if (0 >      /* Duplicate essential headers from REGISTER request: */      sip_add_tl(msg, osip,		 SIPTAG_TO(regsip->sip_to),		 SIPTAG_FROM(regsip->sip_from),		 /* XXX - we should only use loose routing here */		 /* XXX - if we used strict routing,		    the route header/request_uri must be restored		 */		 SIPTAG_ROUTE(regsip->sip_route),		 /* Add Max-Forwards 0 */		 TAG_IF(d, SIPTAG_MAX_FORWARDS_STR("0")),		 TAG_IF(d, SIPTAG_SUBJECT_STR("KEEPALIVE")),		 SIPTAG_CALL_ID_STR(ob->ob_cookie),		 SIPTAG_ACCEPT_STR(outbound_content_type),		 TAG_END()) ||      /* Create request-line, Call-ID, CSeq */      nta_msg_request_complete(msg,       			nta_default_leg(ob->ob_nta),       			SIP_METHOD_OPTIONS,       			(void *)regsip->sip_to->a_url) < 0 ||      msg_serialize(msg, (void *)osip) < 0 ||      msg_prepare(msg) < 0)    return msg_destroy(msg), -1;  previous = ob->ob_keepalive.msg;  ob->ob_keepalive.msg = msg;  msg_destroy(previous);  return 0;}static int keepalive_options(outbound_t *ob){  msg_t *req;  sip_t *sip;  if (ob->ob_keepalive.orq)    return 0;  if (ob->ob_prefs.validate && ob->ob_registered && !ob->ob_validated)    return keepalive_options_with_registration_probe(ob);  req = msg_copy(ob->ob_keepalive.msg);  if (!req)    return -1;  sip = sip_object(req); assert(sip); assert(sip->sip_request);  if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta),			       SIP_METHOD_UNKNOWN, NULL) < 0)    return msg_destroy(req), -1;  if (ob->ob_keepalive.auc[0])    auc_authorization(ob->ob_keepalive.auc, req, (void *)sip,		      "OPTIONS", sip->sip_request->rq_url, sip->sip_payload);  ob->ob_keepalive.orq =    nta_outgoing_mcreate(ob->ob_nta,			 response_to_keepalive_options,			 ob,			 NULL,			 req,			 TAG_IF(ob->ob_proxy_override,				NTATAG_DEFAULT_PROXY(ob->ob_proxy)),			 TAG_END());  if (!ob->ob_keepalive.orq)    return msg_destroy(req), -1;  return 0;}static int response_to_keepalive_options(outbound_t *ob,					 nta_outgoing_t *orq,					 sip_t const *sip){  int status = 408;  char const *phrase = sip_408_Request_timeout;  int binding_check;  int challenged = 0, credentials = 0;  msg_t *_reqmsg = nta_outgoing_getrequest(orq);  sip_t *request = sip_object(_reqmsg); msg_destroy(_reqmsg);  if (sip && sip->sip_status) {    status = sip->sip_status->st_status;    phrase = sip->sip_status->st_phrase;  }  if (status == 100) {    /* This probably means that we are in trouble. whattodo, whattodo */

⌨️ 快捷键说明

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