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

📄 stun.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005-2006 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 * *//**@internal * @file stun.c STUN client module * * See RFC 3489/3489bis 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>#include <string.h>#include <time.h>#include <stdlib.h>#define SU_ROOT_MAGIC_T struct stun_magic_t#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 HAVE_NETINET_TCP_H#include <netinet/tcp.h>#endif#if HAVE_OPENSSL#include <openssl/opensslv.h>#endif/* Missing socket symbols */#ifndef SOL_TCP#define SOL_TCP IPPROTO_TCP#endif#if HAVE_FUNC#elif HAVE_FUNCTION#define __func__ __FUNCTION__#elsestatic char const __func__[] = "stun";#endif#ifndef SU_DEBUG#define SU_DEBUG 3#endif/** STUN log. */su_log_t stun_log[] = { SU_LOG_INIT("stun", "STUN_DEBUG", SU_DEBUG) }; /**@var char const STUN_DEBUG[] * * Environment variable determining the debug log level for @b stun module. * * The STUN_DEBUG environment variable is used to determine the debug logging * level for @b stun module. The default level is 3. *  * @sa <sofia-sip/su_debug.h>, stun_log, SOFIA_DEBUG */extern char const STUN_DEBUG[];enum {  STUN_SENDTO_TIMEOUT = 1000,  STUN_TLS_CONNECT_TIMEOUT = 8000,};/** * States of STUN requests. See stun_state_e for states * discovery processes. */ typedef enum stun_req_state_e {  stun_req_no_assigned_event,  stun_req_dispose_me,            /**< request can be disposed */  stun_req_discovery_init,  stun_req_discovery_processing,  stun_req_error,  stun_req_timeout} stun_req_state_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;  stun_discovery_f        sd_callback;  stun_discovery_magic_t *sd_magic;  tagi_t          *sd_tags;          /** stored tags for the discovery */  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_mapped_addr_match; /** Mapped addresses match? */  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 {  su_timer_t       *sr_timer;  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_req_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 */  char           *sh_domain;        /**< domain address for DNS-SRV lookups */  stun_dns_lookup_t  *sh_dns_lookup;  stun_action_t       sh_dns_pend_action;   stun_discovery_f    sh_dns_pend_cb;  stun_discovery_magic_t *sh_dns_pend_ctx;  tagi_t             *sh_dns_pend_tags;#if 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_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_req_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_req_discovery_init); */  /* STUN_STATE_STR(stun_req_discovery_processing); */  STUN_STATE_STR(stun_discovery_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_discovery_timeout);  /* STUN_STATE_STR(stun_req_timeout); */    case stun_error:  default: return "stun_error";  }}/**  * Returns the NAT type attached to STUN discovery handle. * * @see stun_nattype_str(). * @see stun_test_nattype(). */char const *stun_nattype_str(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 (endpoint independent filtering and mapping)",    "Restricted Cone NAT (endpoint independent mapping)",    "Port Restricted Cone NAT (endpoint independent mapping)",    "Endpoint independent filtering, endpoint dependent mapping",    "Address dependent filtering, endpoint dependent mapping",    "Symmetric NAT (address and port dependent filtering, endpoint dependent mapping)",  };  if (sd)    return stun_nattype_str[sd->sd_nattype];  else    return stun_nattype_str[stun_nat_unknown];}/** * Returns the detected NAT type. *  * @see stun_nattype_str(). * @see stun_test_nattype(). */stun_nattype_t stun_nattype(stun_discovery_t *sd){  if (!sd)    return stun_nat_unknown;  return sd->sd_nattype;}su_addrinfo_t const *stun_server_address(stun_handle_t *sh){  return &sh->sh_pri_info;}int stun_lifetime(stun_discovery_t *sd){  return sd ? sd->sd_lt_cur : -1;}#if HAVE_OPENSSLchar const stun_version[] =  "sofia-sip-stun using " OPENSSL_VERSION_TEXT;#elsechar const stun_version[] =  "sofia-sip-stun";#endifstatic int do_action(stun_handle_t *sh, stun_msg_t *binding_response);#if HAVE_OPENSSLstatic int stun_tls_callback(su_root_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg);#endifstatic int process_binding_request(stun_request_t *req, stun_msg_t *binding_response);static stun_discovery_t *stun_discovery_create(stun_handle_t *sh,					       stun_action_t action,					       stun_discovery_f sdf,					       stun_discovery_magic_t *magic);static int stun_discovery_destroy(stun_discovery_t *sd);static int action_bind(stun_request_t *req, stun_msg_t *binding_response);static int action_determine_nattype(stun_request_t *req, stun_msg_t *binding_response);static int process_test_lifetime(stun_request_t *req, stun_msg_t *binding_response);static stun_request_t *stun_request_create(stun_discovery_t *sd);static int stun_send_binding_request(stun_request_t *req,			      su_sockaddr_t *srvr_addr);static int stun_bind_callback(stun_magic_t *m, su_wait_t *w, su_wakeup_arg_t *arg);#if defined (__CYGWIN__)static int get_localinfo(int family, su_sockaddr_t *su, socklen_t *return_len);#endif/* timers */static void stun_sendto_timer_cb(su_root_magic_t *magic, 				 su_timer_t *t,				 su_timer_arg_t *arg);#if HAVE_OPENSSLstatic void stun_tls_connect_timer_cb(su_root_magic_t *magic, 				      su_timer_t *t,				      su_timer_arg_t *arg);#endifstatic void stun_test_lifetime_timer_cb(su_root_magic_t *magic, 					su_timer_t *t,					su_timer_arg_t *arg);static void stun_keepalive_timer_cb(su_root_magic_t *magic, 				    su_timer_t *t,				    su_timer_arg_t *arg);static int priv_stun_bind_send(stun_handle_t *sh, stun_request_t *req, stun_discovery_t *sd);static int priv_dns_queue_action(stun_handle_t *sh,				 stun_action_t action,				 stun_discovery_f sdf,				 stun_discovery_magic_t *magic,				 tag_type_t tag, tag_value_t value, ...);/** * 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_root(stun_handle_t *self){  return self ? self->sh_root : NULL;}/** * Check if a STUN handle should be created. * * Return true if STUNTAG_SERVER() or STUNTAG_DOMAIN() tags have  * been specified, or otherwise if STUN_SERVER environment variable  * is set. * * @TAGS * @TAG STUNTAG_DOMAIN() domain to use in DNS-SRV based STUN server * @TAG STUNTAG_SERVER() stun server hostname or dotted IPv4 address * * @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, *t2;  char const *stun_server;  enter;  ta_start(ta, tag, value);  t = tl_find(ta_args(ta), stuntag_server);  t2 = tl_find(ta_args(ta), stuntag_domain);  if (t && t->t_value)     stun_server = (char *)t->t_value;  else if (t2 && t2->t_value)    stun_server = (char *)t2->t_value;  else    stun_server = getenv("STUN_SERVER");  ta_end(ta);  return stun_server != NULL;}/**  * Creates a STUN handle. * * The created handles can be used for STUN binding discovery,  * keepalives, and other STUN usages. * * @param root eventloop to used by the stun state machine * @param tag,value,... tag-value list  * * @TAGS * @TAG STUNTAG_DOMAIN() domain to use in DNS-SRV based STUN server * @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_init(su_root_t *root,				tag_type_t tag, tag_value_t value, ...){  stun_handle_t *stun = NULL;  char const *server = NULL, *domain = 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_DOMAIN_REF(domain),	  STUNTAG_REQUIRE_INTEGRITY_REF(req_msg_integrity),	  TAG_END());  ta_end(ta);  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", 	      __func__, server));  /* fail, if no server or a domain for a DNS-SRV lookup is specified */  if (!server && !domain) {    errno = ENOENT;

⌨️ 快捷键说明

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