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

📄 outbound.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 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 outbound.c * @brief Implementation of SIP NAT traversal and outbound * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Kai Vehmanen <Kai.Vehmanen@nokia.com> * @author Martti Mela <Martti Mela@nokia.com> * * @date Created: Wed May 10 12:11:54 EEST 2006 ppessi */#include "config.h"#define NTA_OUTGOING_MAGIC_T struct outbound#include "outbound.h"#include <sofia-sip/hostdomain.h>#include <sofia-sip/sip.h>#include <sofia-sip/sip_protos.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/sip_status.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/tport.h>#include <sofia-sip/nta_tport.h>#include <sofia-sip/su_md5.h>#include <sofia-sip/su_uniqueid.h>#include <sofia-sip/token64.h>#define SU_LOG (nua_log)#include <sofia-sip/su_debug.h>#include <stddef.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <assert.h>struct outbound {  su_home_t ob_home[1];  outbound_owner_vtable  const *ob_oo;			/**< Callbacks */  outbound_owner_t *ob_owner;	/**< Backpointer */  su_root_t *ob_root;		/**< Root for timers and stuff */  nta_agent_t *ob_nta;		/**< SIP transactions */  char ob_cookie[32];		/**< Our magic cookie */  struct outbound_prefs {    unsigned interval;	/**< Default keepalive interval for datagram */    unsigned stream_interval;	/**< Default keepalive interval for streams */    unsigned gruuize:1;		/**< Establish a GRUU */    unsigned outbound:1;	/**< Try to use outbound */    unsigned natify:1;		/**< Try to detect NAT */    unsigned okeepalive:1;	/**< Connection keepalive with OPTIONS */    unsigned validate:1;	/**< Validate registration with OPTIONS */    /* How to detect NAT binding or connect to outbound: */    unsigned use_connect:1;	/**< Use HTTP connect */    unsigned use_rport:1;	/**< Use received/rport */    unsigned use_socks:1;	/**< Detect and use SOCKS V5 */    unsigned use_upnp:1;	/**< Detect and use UPnP */    unsigned use_stun:1;	/**< Detect and try to use STUN */    unsigned :0;  } ob_prefs;  struct outbound_info {    /* See enum outbound_feature: */    /* 0 do not support, 1 - perhaps supports, 2 - supports, 3 - requires */    unsigned gruu:2, outbound:2, pref:2;  } ob_info;  /** Source of Contact header */  unsigned ob_by_stack:1;  /** Self-generated contacts */  unsigned ob_contacts:1;  /* The registration state machine. */  /** Initial REGISTER containing ob_rcontact has been sent */  unsigned ob_registering:1;  /** 2XX response to REGISTER containg ob_rcontact has been received */  unsigned ob_registered:1;  /** The registration has been validated:   *  We have successfully sent OPTIONS to ourselves.   */  unsigned ob_validated:1;  /** The registration has been validated once.   *   We have successfully sent OPTIONS to ourselves, so do not give   *   up if OPTIONS probe fails.   */  unsigned ob_once_validated:1;  unsigned ob_proxy_override:1;	/**< Override stack default proxy */  unsigned :0;  url_string_t *ob_proxy;	/**< Outbound-specific proxy */  char const *ob_instance;	/**< Our instance ID */  int32_t ob_reg_id;		/**< Flow-id */  sip_contact_t *ob_rcontact;	/**< Our contact */  sip_contact_t *ob_dcontact;	/**< Contact for dialogs */  sip_contact_t *ob_previous;	/**< Stale contact */  sip_contact_t *ob_gruu;	/**< Contact added to requests */  sip_via_t *ob_via;		/**< Via header used to generate contacts */  sip_contact_t *ob_obp;	/**< Contacts from outbound proxy */  char *ob_nat_detected;	/**< Our public address */  char *ob_nat_port;		/**< Our public port number */  void *ob_stun;		/**< Stun context */  void *ob_upnp;		/**< UPnP context  */  struct {    char *sipstun;		/**< Stun server usable for keep-alives */    unsigned interval;		/**< Interval. */    su_timer_t *timer;		/**< Keep-alive timer */    msg_t *msg;			/**< Keep-alive OPTIONS message */    nta_outgoing_t *orq;	/**< Keep-alive OPTIONS transaction */    auth_client_t *auc[1];	/**< Authenticator for OPTIONS */    /** Progress of registration validation */    unsigned validating:1, validated:1,:0;  } ob_keepalive;		/**< Keepalive informatio */};staticint outbound_nat_detect(outbound_t *ob,       			 sip_t const *request,       			 sip_t const *response);/** Return values for outbound_nat_detect(). */enum {  ob_nat_error = -1,		/* or anything below zero */  ob_no_nat = 0,  ob_nat_detected = 1,  ob_nat_changed = 2};/* ---------------------------------------------------------------------- */#define SIP_METHOD_UNKNOWN sip_method_unknown, NULL/** Content-Type sent in OPTIONS probing connectivity */char const * const outbound_content_type = "application/vnd.nokia-register-usage";staticint outbound_check_for_nat(outbound_t *ob,			   sip_t const *request,			   sip_t const *response);enum outbound_feature {  outbound_feature_unsupported = 0,  outbound_feature_unsure = 1,  outbound_feature_supported = 2,  outbound_feature_required = 3};static enum outbound_feature feature_level(sip_t const *sip,					   char const *tag, int level);static int outbound_contacts_from_via(outbound_t *ob,				      sip_via_t const *via);/* ---------------------------------------------------------------------- *//** Create a new outbound object */outbound_t *outbound_new(outbound_owner_t *owner,	     outbound_owner_vtable const *owner_methods,	     su_root_t *root,	     nta_agent_t *agent,	     char const *instance){  outbound_t *ob;  if (!owner || !owner_methods || !root || !agent)    return NULL;  ob = su_home_clone((su_home_t *)owner, sizeof *ob);    if (ob) {    su_md5_t md5[1];    uint8_t digest[SU_MD5_DIGEST_SIZE];    su_guid_t guid[1];    ob->ob_owner = owner;    ob->ob_oo = owner_methods;    ob->ob_root = root;    ob->ob_nta = agent;    if (instance)      ob->ob_instance =	su_sprintf(ob->ob_home, "+sip.instance=\"<%s>\"", instance);    ob->ob_reg_id = 0;    /* Generate a random cookie (used as Call-ID) for us */    su_md5_init(md5);    su_guid_generate(guid);    if (instance)      su_md5_update(md5, (void *)instance, strlen(instance));    su_md5_update(md5, (void *)guid, sizeof guid);    su_md5_digest(md5, digest);    token64_e(ob->ob_cookie, sizeof ob->ob_cookie, digest, sizeof digest);        if (instance && !ob->ob_instance)      su_home_unref(ob->ob_home), ob = NULL;  }  return ob;}void outbound_unref(outbound_t *ob){  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;  su_home_unref(ob->ob_home);}#include <sofia-sip/bnf.h>/** Set various outbound and nat-traversal related options. */int outbound_set_options(outbound_t *ob,			 char const *_options,			 unsigned interval,			 unsigned stream_interval){  struct outbound_prefs prefs[1] = {{ 0 }};  char *s, *options = su_strdup(NULL, _options);  int invalid;  prefs->interval = interval;  prefs->stream_interval = stream_interval;#define MATCH(v) (len == sizeof(#v) - 1 && strncasecmp(#v, s, len) == 0)  if (options) {    for (s = options; s[0]; s++) if (s[0] == '-') s[0] = '_';  }  prefs->gruuize = 1;  prefs->outbound = 0;  prefs->natify = 1;  prefs->okeepalive = 1;  prefs->validate = 1;  prefs->use_rport = 1;  for (s = options; s && s[0]; ) {    size_t len = span_token(s);    int value = 1;    if (len > 3 && strncasecmp(s, "no_", 3) == 0)      value = 0, s += 3, len -= 3;    else if (len > 4 && strncasecmp(s, "not_", 4) == 0)      value = 0, s += 4, len -= 4;    if (len == 0)      break;    else if (MATCH(gruuize)) prefs->gruuize = value;    else if (MATCH(outbound)) prefs->outbound = value;    else if (MATCH(natify)) prefs->natify = value;    else if (MATCH(validate)) prefs->validate = value;    else if (MATCH(options_keepalive)) prefs->okeepalive = value;    else if (MATCH(use_connect)) prefs->use_connect = value;    else if (MATCH(use_rport)) prefs->use_rport = value;    else if (MATCH(use_socks)) prefs->use_socks = value;    else if (MATCH(use_upnp)) prefs->use_upnp = value;    else if (MATCH(use_stun)) prefs->use_stun = value;    else      SU_DEBUG_1(("outbound(%p): unknown option \"%.*s\"\n",		  (void *)ob->ob_owner, (int)len, s));    s += len;    len = strspn(s, " \t\n\r,;");    if (len == 0)      break;    s += len;  }  invalid = s && s[0];  su_free(NULL, options);  if (invalid) {    SU_DEBUG_1(("outbound(%p): invalid options \"%s\"\n", 		(void *)ob->ob_owner, options));    return -1;  }  if (prefs->natify &&      !(prefs->outbound ||	prefs->use_connect ||	prefs->use_rport ||	prefs->use_socks ||	prefs->use_upnp ||	prefs->use_stun)) {    SU_DEBUG_1(("outbound(%p): no nat traversal method given\n",		(void *)ob->ob_owner));  }  ob->ob_prefs = *prefs;  ob->ob_reg_id = prefs->outbound ? 1 : 0;  return 0;}/** Override stack default proxy for outbound */int outbound_set_proxy(outbound_t *ob,		       url_string_t *proxy){  url_string_t *new_proxy = NULL, *old_proxy = ob->ob_proxy;  if (proxy)    new_proxy = (url_string_t *)url_as_string(ob->ob_home, proxy->us_url);  if (proxy == NULL || new_proxy != NULL) {    ob->ob_proxy_override = 1;    ob->ob_proxy = new_proxy;    su_free(ob->ob_home, old_proxy);    return 0;  }  return -1;}/* ---------------------------------------------------------------------- *//** Obtain contacts for REGISTER */int outbound_get_contacts(outbound_t *ob, 			  sip_contact_t **return_current_contact, 			  sip_contact_t **return_previous_contact){  if (ob) {    if (ob->ob_contacts)      *return_current_contact = ob->ob_rcontact;    else {      sip_contact_t *contact = *return_current_contact;      if (contact) {	if (ob->ob_rcontact)	  msg_header_free_all(ob->ob_home, (msg_header_t*)ob->ob_rcontact);	ob->ob_rcontact = sip_contact_dup(ob->ob_home, contact);      }    }    *return_previous_contact = ob->ob_previous;  }  return 0;}/** REGISTER request has been sent */int outbound_start_registering(outbound_t *ob){  if (ob)    ob->ob_registering = 1;  return 0;}/** Process response to REGISTER request */int outbound_register_response(outbound_t *ob,			       int terminating,			       sip_t const *request,			       sip_t const *response){  int status, reregister;  if (!ob)    return 0;  if (terminating) {    ob->ob_registering = ob->ob_registered = 0;    return 0;			/* Cleanup is done separately */  }    if (!response || !request)    return 0;  assert(request->sip_request); assert(response->sip_status);    reregister = outbound_check_for_nat(ob, request, response);  if (reregister)    return reregister;  status = response->sip_status->st_status;  if (status < 300) {    if (request->sip_contact && response->sip_contact)      ob->ob_registered = ob->ob_registering;    else      ob->ob_registered = 0;    if (ob->ob_previous)      msg_header_free(ob->ob_home, (void *)ob->ob_previous);    ob->ob_previous = NULL;  }

⌨️ 快捷键说明

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