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

📄 stun.c

📁 Internet Phone, Chat, Conferencing
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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 * *//** * @file stun.c STUN client module * * See RFC 3489 for further information. * * @author Martti Mela <Martti.Mela@nokia.com> * @author Tat Chan <Tat.Chan@nokia.com> * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Kai Vehmanen <Kai.Vehmanen@nokia.com> *  * @date Created: Thu Jul 24 17:21:00 2003 ppessi */#include "config.h" #include <assert.h>#define SU_ROOT_MAGIC_T struct stun_magic_t/* #define SU_WAKEUP_ARG_T struct stun_handle_s */#include "sofia-sip/stun.h"#include "stun_internal.h"#include "sofia-sip/stun_tag.h"#include <sofia-sip/su_alloc.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/su_log.h>#include <sofia-sip/su.h>#include <sofia-sip/su_localinfo.h>#if defined(HAVE_OPENSSL)#include <openssl/opensslv.h>#endif#if !defined(ETIMEDOUT) && defined(_WIN32)#define ETIMEDOUT WSAETIMEDOUT#endif/* Missing socket symbols */#ifndef SOL_TCP#define SOL_TCP IPPROTO_TCP#endif/** STUN log. */su_log_t stun_log[] = { SU_LOG_INIT("stun", "STUN_DEBUG", SU_DEBUG) }; enum {  STUN_SENDTO_TIMEOUT = 1000,  STUN_TLS_CONNECT_TIMEOUT = 8000,};int stun_change_map[4][4] = {  {0, 1, 2, 3}, /* no change */  {2, 3, 0, 1}, /* change ip */  {1, 0, 3, 2}, /* change port */  {3, 2, 1, 0}  /* change ip and port, Ca:Cp */};/* NAT TYPES */typedef enum stun_nattype_e {  stun_nat_unknown,  stun_open_internet,  stun_udp_blocked,  stun_sym_udp_fw,  stun_nat_full_cone,  stun_nat_sym,  stun_nat_res_cone,  stun_nat_port_res_cone,} stun_nattype_t;#define CHG_IP		0x001#define CHG_PORT	0x004#define x_insert(l, n, x) \ ((l) ? (l)->x##_prev = &(n)->x##_next : 0, \  (n)->x##_next = (l), (n)->x##_prev = &(l), (l) = (n))#define x_remove(n, x) \  ((*(n)->x##_prev = (n)->x##_next) ? \   (n)->x##_next->x##_prev = (n)->x##_prev : 0)#define x_is_inserted(n, x) ((n)->x##_prev != NULL)struct stun_discovery_s {  stun_discovery_t   *sd_next, **sd_prev; /**< Linked list */  stun_handle_t   *sd_handle;  su_addrinfo_t    sd_pri_info;      /**< server primary info */  su_sockaddr_t    sd_pri_addr[1];   /**< server primary address */  su_addrinfo_t    sd_sec_info;      /**< server secondary info */  su_sockaddr_t    sd_sec_addr[1];   /**< server secondary address */  stun_action_t    sd_action;        /**< My action */  stun_state_t     sd_state;         /**< Progress states */  su_socket_t      sd_socket;        /**< target socket */  su_sockaddr_t    sd_bind_addr[1]; /**< local address */  su_socket_t      sd_socket2;       /**< Alternative socket */  int              sd_index;         /**< root_register index */    /* Binding discovery */  su_sockaddr_t    sd_addr_seen_outside[1];   /**< local address */  /* NAT type related */  stun_nattype_t   sd_nattype;       /**< Determined NAT type */  int              sd_first;         /**< These are the requests  */  int              sd_second;  int              sd_third;  int              sd_fourth;  /* Life time related */  int              sd_lt_cur;  int              sd_lt;  int              sd_lt_max;  /* Keepalive timeout */  unsigned int     sd_timeout;  su_timer_t      *sd_timer;};struct stun_request_s {  stun_request_t   *sr_next, **sr_prev; /**< Linked list */  stun_msg_t       *sr_msg;             /**< STUN message pointer */  stun_handle_t    *sr_handle;          /**< backpointer, STUN object */  su_socket_t       sr_socket;          /**< Alternative socket */  su_localinfo_t    sr_localinfo;       /**< local addrinfo */  su_sockaddr_t     sr_local_addr[1];   /**< local address */  su_sockaddr_t     sr_destination[1];  stun_state_t      sr_state;           /**< Progress states */  int               sr_retry_count;     /**< current retry number */  long              sr_timeout;         /**< timeout for next sendto() */  int               sr_from_y;  int               sr_request_mask;    /**< Mask consisting of chg_ip and chg_port */  stun_discovery_t *sr_discovery;};struct stun_handle_s{  su_home_t       sh_home[1];  su_root_t      *sh_root;          /**< event loop */  int             sh_root_index;    /**< object index of su_root_register() */  stun_request_t *sh_requests; /**< outgoing requests list */  stun_discovery_t *sh_discoveries; /**< Actions list */  int             sh_max_retries;   /**< max resend for sendto() */  su_addrinfo_t   sh_pri_info;      /**< server primary info */  su_sockaddr_t   sh_pri_addr[1];   /**< server primary address */  su_addrinfo_t   sh_sec_info;      /**< server secondary info */  su_sockaddr_t   sh_sec_addr[1];   /**< server secondary address */  su_localinfo_t  sh_localinfo;     /**< local addrinfo */  su_sockaddr_t   sh_local_addr[1]; /**< local address */#if defined(HAVE_OPENSSL)  SSL_CTX        *sh_ctx;           /**< SSL context for TLS */  SSL            *sh_ssl;           /**< SSL handle for TLS */#else  void           *sh_ctx;           /**< SSL context for TLS */  void           *sh_ssl;           /**< SSL handle for TLS */#endif  stun_msg_t      sh_tls_request;  stun_msg_t      sh_tls_response;  int             sh_nattype;       /**< NAT-type, see stun_common.h */  stun_event_f    sh_callback;      /**< callback for calling application */   stun_magic_t   *sh_context;       /**< application context */  stun_buffer_t   sh_username;  stun_buffer_t   sh_passwd;  int             sh_use_msgint;    /**< try message integrity (TLS) */  int             sh_req_msgint;    /**< require use of msg-int (TLS) */};#define STUN_STATE_STR(x) case x: return #xchar const *stun_str_state(stun_state_t state){  switch (state) {  STUN_STATE_STR(stun_no_assigned_event);  STUN_STATE_STR(stun_dispose_me);  STUN_STATE_STR(stun_tls_connecting);  STUN_STATE_STR(stun_tls_writing);  STUN_STATE_STR(stun_tls_closing);  STUN_STATE_STR(stun_tls_reading);  STUN_STATE_STR(stun_tls_done);  STUN_STATE_STR(stun_discovery_init);  STUN_STATE_STR(stun_discovery_processing);  STUN_STATE_STR(stun_discovery_done);  STUN_STATE_STR(stun_bind_init);  STUN_STATE_STR(stun_bind_processing);  STUN_STATE_STR(stun_bind_done);  STUN_STATE_STR(stun_tls_connection_timeout);  STUN_STATE_STR(stun_tls_connection_failed);  STUN_STATE_STR(stun_tls_ssl_connect_failed);  STUN_STATE_STR(stun_request_not_found);  STUN_STATE_STR(stun_bind_error);  STUN_STATE_STR(stun_bind_timeout);  STUN_STATE_STR(stun_discovery_timeout);  STUN_STATE_STR(stun_request_timeout);    case stun_error:  default: return "stun_error";  }}/* char const *stun_nattype(stun_handle_t *sh) */char const *stun_nattype(stun_discovery_t *sd){  char const *stun_nattype_str[] = {    "NAT type undetermined",    "Open Internet",    "UDP traffic is blocked or server unreachable",    "Symmetric UDP Firewall",    "Full-Cone NAT",    "Symmetric NAT",    "Restricted Cone NAT",    "Port Restricted Cone NAT",  };  if (sd)    return stun_nattype_str[sd->sd_nattype];  else    return stun_nattype_str[stun_nat_unknown];}int stun_lifetime(stun_discovery_t *sd){  return sd ? sd->sd_lt_cur : -1;}#if defined(HAVE_OPENSSL)char const stun_version[] =  "sofia-sip-stun using " OPENSSL_VERSION_TEXT;#elsechar const stun_version[] =  "sofia-sip-stun";#endifint do_action(stun_handle_t *sh, stun_msg_t *binding_response);int stun_tls_callback(su_root_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg);int process_binding_request(stun_request_t *req, stun_msg_t *binding_response);stun_discovery_t *stun_discovery_create(stun_handle_t *sh,					stun_action_t action);int stun_discovery_destroy(stun_discovery_t *sd);int action_bind(stun_request_t *req, stun_msg_t *binding_response);int action_determine_nattype(stun_request_t *req, stun_msg_t *binding_response);int process_get_lifetime(stun_request_t *req, stun_msg_t *binding_response);stun_request_t *stun_request_create(stun_discovery_t *sd);int stun_send_binding_request(stun_request_t *req,			      su_sockaddr_t *srvr_addr);int stun_bind_callback(stun_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg);/* timers */void stun_sendto_timer_cb(su_root_magic_t *magic, 			  su_timer_t *t,			  su_timer_arg_t *arg);void stun_tls_connect_timer_cb(su_root_magic_t *magic, 			       su_timer_t *t,			       su_timer_arg_t *arg);void stun_get_lifetime_timer_cb(su_root_magic_t *magic, 				su_timer_t *t,				su_timer_arg_t *arg);void stun_keepalive_timer_cb(su_root_magic_t *magic, 			     su_timer_t *t,			     su_timer_arg_t *arg);/** * Return su_root_t assigned to stun_handle_t. * * @param self stun_handle_t object * @return su_root_t object, NULL if self not given. */su_root_t *stun_handle_root(stun_handle_t *self){  return self ? self->sh_root : NULL;}/** * Check if a STUN handle should be created. * * Return true either there is a tag STUNTAG_SERVER() in list or if * STUN_SERVER environment variable is set. * * @param tag,value,... tag-value list */int stun_is_requested(tag_type_t tag, tag_value_t value, ...){  ta_list ta;  tagi_t const *t;  char const *stun_server;  enter;  ta_start(ta, tag, value);  t = tl_find(ta_args(ta), stuntag_server);  stun_server = t && t->t_value ? (char *)t->t_value : getenv("STUN_SERVER");  ta_end(ta);  return stun_server != NULL;}/**  * Create a STUN handle  * * @param tag,value,... tag-value list  * * @TAGS * @TAG STUNTAG_SERVER() stun server hostname or dotted IPv4 address * @TAG STUNTAG_REQUIRE_INTEGRITY() true if msg integrity should be * used enforced * */stun_handle_t *stun_handle_create(stun_magic_t *context,				  su_root_t *root,				  stun_event_f cb,				  tag_type_t tag, tag_value_t value, ...){  stun_handle_t *stun = NULL;  char const *server = NULL;  int req_msg_integrity = 1;  int err;  ta_list ta;    enter;  ta_start(ta, tag, value);  tl_gets(ta_args(ta),	  STUNTAG_SERVER_REF(server),	  STUNTAG_REQUIRE_INTEGRITY_REF(req_msg_integrity),	  TAG_END());  stun = su_home_clone(NULL, sizeof(*stun));  if (!stun) {    SU_DEBUG_3(("%s: %s failed\n", __func__, "su_home_clone()"));    return NULL;  }  /* Enviroment overrides */  if (getenv("STUN_SERVER")) {    server = getenv("STUN_SERVER");    SU_DEBUG_5(("%s: using STUN_SERVER=%s\n", __func__, server));  }  SU_DEBUG_5(("%s(\"%s\"): called\n", 	      "stun_handle_tcreate", server));  if (!server)    return NULL;    stun->sh_pri_info.ai_addrlen = 16;  stun->sh_pri_info.ai_addr = &stun->sh_pri_addr->su_sa;  stun->sh_sec_info.ai_addrlen = 16;  stun->sh_sec_info.ai_addr = &stun->sh_sec_addr->su_sa;  stun->sh_localinfo.li_addrlen = 16;  stun->sh_localinfo.li_addr = stun->sh_local_addr;  err = stun_atoaddr(AF_INET, &stun->sh_pri_info, server);  if (err < 0)    return NULL;  stun->sh_nattype = stun_nat_unknown;  stun->sh_root     = root;  stun->sh_context  = context;  stun->sh_callback = cb;  /* always try TLS: */  stun->sh_use_msgint = 1;   /* whether use of shared-secret msgint is required */  stun->sh_req_msgint = req_msg_integrity;  stun->sh_max_retries = STUN_MAX_RETRX;  /* initialize username and password */  stun_init_buffer(&stun->sh_username);  stun_init_buffer(&stun->sh_passwd);    stun->sh_nattype = stun_nat_unknown;    /* initialize random number generator */  srand(time(NULL));    ta_end(ta);  return stun;}#if defined(HAVE_OPENSSL)/** Shared secret request/response processing */int stun_handle_request_shared_secret(stun_handle_t *sh){  int events = -1;  int one, err = -1;  su_wait_t wait[1] = { SU_WAIT_INIT };  su_socket_t s = SOCKET_ERROR;  int family;  su_addrinfo_t *ai = NULL;  su_timer_t *connect_timer = NULL;  stun_discovery_t *sd;  /* stun_request_t *req; */  assert(sh);  enter;  ai = &sh->sh_pri_info;  if (sh->sh_use_msgint == 1) {    SU_DEBUG_3(("Contacting Server to obtain shared secret. " \		"Please wait.\n"));  }  else {    SU_DEBUG_3(("No message integrity enabled.\n"));    return errno = EFAULT, -1;  }  /* open tcp connection to server */  s = su_socket(family = AF_INET, SOCK_STREAM, 0);  if (s == -1) {    STUN_ERROR(errno, socket);    return -1;  }  /* asynchronous connect() */  if (su_setblocking(s, 0) < 0) {    STUN_ERROR(errno, su_setblocking);    return -1;  }  if (setsockopt(s, SOL_TCP, TCP_NODELAY,		 (void *)&one, sizeof one) == -1) {    STUN_ERROR(errno, setsockopt);    return -1;  }  /* Do an asynchronous connect(). Three error codes are ok,   * others cause return -1. */  if (connect(s, (struct sockaddr *) &sh->sh_pri_addr, 	      ai->ai_addrlen) == SOCKET_ERROR) {    err = su_errno();    if (err != EINPROGRESS && err != EAGAIN && err != EWOULDBLOCK) {      STUN_ERROR(err, connect);      return -1;    }  }  SU_DEBUG_9(("%s: %s: %s\n", __func__, "connect",	      su_strerror(err)));    sd = stun_discovery_create(sh, stun_action_tls_query);  sd->sd_socket = s;  /* req = stun_request_create(sd); */  events = SU_WAIT_CONNECT | SU_WAIT_ERR;  if (su_wait_create(wait, s, events) == -1)    STUN_ERROR(errno, su_wait_create);  su_root_eventmask(sh->sh_root, sh->sh_root_index, s, events);

⌨️ 快捷键说明

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