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

📄 sres.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) 2006 Nokia Corporation. * Copyright (C) 2006 Dimitri E. Prado. * * 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 sres.c * @brief Sofia DNS Resolver implementation. *  * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Teemu Jalava <Teemu.Jalava@nokia.com> * @author Mikko Haataja * @author Kai Vehmanen <kai.vehmanen@nokia.com>  *         (work on the win32 nameserver discovery)  * @author Dimitri E. Prado  *         (initial version of win32 nameserver discovery) * * @todo The resolver should allow handling arbitrary records, too. */#include "config.h"#if HAVE_STDINT_H#include <stdint.h>#elif HAVE_INTTYPES_H#include <inttypes.h>#else#if defined(HAVE_WIN32)typedef _int8 int8_t;typedef unsigned _int8 uint8_t;typedef unsigned _int16 uint16_t;typedef unsigned _int32 uint32_t;#endif#endif#if HAVE_NETINET_IN_H#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#endif#if HAVE_ARPA_INET_H#include <arpa/inet.h>#endif#if HAVE_WINSOCK2_H#include <winsock2.h>#include <ws2tcpip.h>#ifndef IPPROTO_IPV6		/* socklen_t is used with @RFC2133 API */typedef int socklen_t;#endif#endif#if HAVE_IPHLPAPI_H#include <iphlpapi.h>#endif#include <time.h>#include "sofia-resolv/sres.h"#include "sofia-resolv/sres_cache.h"#include "sofia-resolv/sres_record.h"#include "sofia-resolv/sres_async.h"#include <sofia-sip/su_alloc.h>#include <sofia-sip/su_strlst.h>#include <sofia-sip/su_errno.h>#include "sofia-sip/htable.h"#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <stdarg.h>#include <stddef.h>#include <string.h>#include <stdio.h>#include <errno.h>#include <limits.h>#include <assert.h>#if HAVE_WINSOCK2_H/* Posix send() */su_inline ssize_t sres_send(sres_socket_t s, void *b, size_t length, int flags){  if (length > INT_MAX)    length = INT_MAX;  return (ssize_t)send(s, b, (int)length, flags);}/* Posix recvfrom() */su_inline ssize_t sres_recvfrom(sres_socket_t s, void *buffer, size_t length, int flags,		      struct sockaddr *from, socklen_t *fromlen){  int retval, ilen;  if (fromlen)    ilen = *fromlen;  if (length > INT_MAX)    length = INT_MAX;  retval = recvfrom(s, buffer, (int)length, flags, 		    (void *)from, fromlen ? &ilen : NULL);  if (fromlen)    *fromlen = ilen;  return (ssize_t)retval;}su_inlineint sres_close(sres_socket_t s){  return closesocket(s);}#if !defined(IPPROTO_IPV6) && (_WIN32_WINNT < 0x0600)#if HAVE_SIN6#include <tpipv6.h>#else#if !defined(__MINGW32__)struct sockaddr_storage {    short ss_family;    char ss_pad[126];};#endif#endif#endif#else#define sres_send(s,b,len,flags) send((s),(b),(len),(flags))#define sres_recvfrom(s,b,len,flags,a,alen) \  recvfrom((s),(b),(len),(flags),(a),(alen))#define sres_close(s) close((s))#define SOCKET_ERROR   (-1)#define INVALID_SOCKET ((sres_socket_t)-1)#endif#define SRES_TIME_MAX ((time_t)LONG_MAX)#if !HAVE_INET_PTONint su_inet_pton(int af, char const *src, void *dst);#else#define su_inet_pton inet_pton#endif#if !HAVE_INET_NTOPconst char *su_inet_ntop(int af, void const *src, char *dst, size_t size);#else#define su_inet_ntop inet_ntop#endif#if defined(va_copy)#elif defined(__va_copy)#define va_copy(dst, src) __va_copy((dst), (src))#else#define va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))#endif/** * How often to recheck nameserver information (seconds). */#ifndef HAVE_WIN32#define SRES_UPDATE_INTERVAL_SECS        5#else#define SRES_UPDATE_INTERVAL_SECS        180#endifvoid sres_cache_clean(sres_cache_t *cache, time_t now);typedef struct sres_message    sres_message_t;typedef struct sres_config     sres_config_t;typedef struct sres_server     sres_server_t;typedef struct sres_nameserver sres_nameserver_t;/** Default path to resolv.conf */static char const sres_conf_file_path[] = "/etc/resolv.conf";/** EDNS0 support. @internal */enum edns {   edns_not_tried = -1,  edns_not_supported = 0,  edns0_configured = 1,  edns0_supported = 2,};struct sres_server {  sres_socket_t           dns_socket;  char                    dns_name[48];     /**< Server name */  struct sockaddr_storage dns_addr[1];  /**< Server node address */  ssize_t                 dns_addrlen;  /**< Size of address */  enum edns               dns_edns;	/**< Server supports edns. */  /** ICMP/temporary error received, zero when successful. */  time_t                  dns_icmp;  /** Persistent error, zero when successful or timeout.    *   * Never selected if dns_error is SRES_TIME_MAX.   */  time_t                  dns_error;};HTABLE_DECLARE_WITH(sres_qtable, qt, sres_query_t, unsigned, size_t);struct sres_resolver_s {  su_home_t           res_home[1];  void               *res_userdata;  sres_cache_t       *res_cache;  time_t              res_now;  sres_qtable_t       res_queries[1];   /**< Table of active queries */  char const         *res_cnffile;      /**< Configuration file name */  char const        **res_options;      /**< Option strings */  sres_config_t const *res_config;  time_t              res_checked;  unsigned long       res_updated;  sres_update_f      *res_updcb;  sres_async_t       *res_async;  sres_schedule_f    *res_schedulecb;  short               res_update_all;  uint16_t            res_id;  short               res_i_server;  /**< Current server to try 					(when doing round-robin) */  short               res_n_servers; /**< Number of servers */  sres_server_t     **res_servers;};/* Parsed configuration. @internal */struct sres_config {  su_home_t c_home[1];  time_t c_modified;  char const *c_filename;  /* domain and search */  char const *c_search[SRES_MAX_SEARCH + 1];  /* nameserver */  struct sres_nameserver {    struct sockaddr_storage ns_addr[1];    ssize_t ns_addrlen;  } *c_nameservers[SRES_MAX_NAMESERVERS + 1];  /* sortlist */  struct sres_sortlist {    struct sockaddr_storage addr[1];    ssize_t addrlen;    char const *name;  } *c_sortlist[SRES_MAX_SORTLIST + 1];  uint16_t    c_port;	     /**< Server port to use */  /* options */  struct sres_options {    uint16_t timeout;    uint16_t attempts;    uint16_t ndots;    enum edns edns;    unsigned debug:1;    unsigned rotate:1;    unsigned check_names:1;    unsigned inet6:1;    unsigned ip6int:1;    unsigned ip6bytestring:1;  } c_opt;};struct sres_query_s {  unsigned        q_hash;  sres_resolver_t*q_res;  sres_answer_f  *q_callback;  sres_context_t *q_context;  char           *q_name;  time_t          q_timestamp;  uint16_t        q_type;  uint16_t        q_class;  uint16_t        q_id;			/**< If nonzero, not answered */  uint16_t        q_retry_count;  uint8_t         q_n_servers;  uint8_t         q_i_server;  int8_t          q_edns;  uint8_t         q_n_subs;  sres_query_t   *q_subqueries[1 + SRES_MAX_SEARCH];  sres_record_t **q_subanswers[1 + SRES_MAX_SEARCH];};struct sres_message {  uint16_t m_offset;  uint16_t m_size;  char const *m_error;  union {    struct {      /* Header defined in RFC 1035 section 4.1.1 (page 26) */      uint16_t mh_id;		/* Query ID */      uint16_t mh_flags;	/* Flags */      uint16_t mh_qdcount;	/* Question record count */      uint16_t mh_ancount;	/* Answer record count */      uint16_t mh_nscount;	/* Authority records count */      uint16_t mh_arcount;	/* Additional records count */    } mp_header;    uint8_t mp_data[1500 - 40];	/**< IPv6 datagram */  } m_packet;#define m_id      m_packet.mp_header.mh_id#define m_flags   m_packet.mp_header.mh_flags#define m_qdcount m_packet.mp_header.mh_qdcount#define m_ancount m_packet.mp_header.mh_ancount#define m_nscount m_packet.mp_header.mh_nscount#define m_arcount m_packet.mp_header.mh_arcount #define m_data    m_packet.mp_data};#define sr_refcount sr_record->r_refcount#define sr_name     sr_record->r_name#define sr_status   sr_record->r_status#define sr_size     sr_record->r_size#define sr_type     sr_record->r_type#define sr_class    sr_record->r_class#define sr_ttl      sr_record->r_ttl#define sr_rdlen    sr_record->r_rdlen#define sr_parsed   sr_record->r_parsed#define sr_rdata    sr_generic->g_dataenum {  SRES_HDR_QR = (1 << 15),  SRES_HDR_QUERY = (0 << 11),  SRES_HDR_IQUERY = (1 << 11),  SRES_HDR_STATUS = (2 << 11),  SRES_HDR_OPCODE = (15 << 11),	/* mask */  SRES_HDR_AA = (1 << 10),  SRES_HDR_TC = (1 << 9),  SRES_HDR_RD = (1 << 8),  SRES_HDR_RA = (1 << 7),  SRES_HDR_RCODE = (15 << 0)	/* mask of return code */};HTABLE_PROTOS_WITH(sres_qtable, qt, sres_query_t, unsigned, size_t);#define CHOME(cache) ((su_home_t *)(cache))/** Get address from sockaddr storage. */#if HAVE_SIN6#define SS_ADDR(ss) \  ((ss)->ss_family == AF_INET ? \   (void *)&((struct sockaddr_in *)ss)->sin_addr : \  ((ss)->ss_family == AF_INET6 ? \   (void *)&((struct sockaddr_in6 *)ss)->sin6_addr : \   (void *)&((struct sockaddr *)ss)->sa_data))#else#define SS_ADDR(ss) \  ((ss)->ss_family == AF_INET ? \   (void *)&((struct sockaddr_in *)ss)->sin_addr : \   (void *)&((struct sockaddr *)ss)->sa_data)#endifstatic int sres_config_changed_servers(sres_config_t const *new_c, 				       sres_config_t const *old_c);static sres_server_t **sres_servers_new(sres_resolver_t *res,					sres_config_t const *c);/** Generate new 16-bit identifier for DNS query. */static uint16_tsres_new_id(sres_resolver_t *res){  return res->res_id ? res->res_id++ : (res->res_id = 2, 1);}/** Return true if we have a search list or a local domain name. */static int sres_has_search_domain(sres_resolver_t *res) {  return res->res_config->c_search[0] != NULL;}static void sres_resolver_destructor(void *);sres_resolver_t *sres_resolver_new_with_cache_va(char const *conf_file_path,				sres_cache_t *cache,				char const *options, 				va_list va);staticsres_resolver_t *sres_resolver_new_internal(sres_cache_t *cache,			   sres_config_t const *config,			   char const *conf_file_path,			   char const **options);static void sres_servers_close(sres_resolver_t *res,			       sres_server_t **servers);static int sres_servers_count(sres_server_t * const *servers);static sres_socket_t sres_server_socket(sres_resolver_t *res,					sres_server_t *dns);static sres_query_t * sres_query_alloc(sres_resolver_t *res,				       sres_answer_f *callback,				       sres_context_t *context,				       uint16_t type,				       char const * domain);static void sres_free_query(sres_resolver_t *res, sres_query_t *q);static int sres_sockaddr2string(sres_resolver_t *, 			 char name[], size_t namelen, 			 struct sockaddr const *);static sres_config_t *sres_parse_resolv_conf(sres_resolver_t *res,				      char const **options);staticsres_server_t *sres_next_server(sres_resolver_t *res, 				uint8_t *in_out_i,				int always);staticint sres_send_dns_query(sres_resolver_t *res, sres_query_t *q);static void sres_answer_subquery(sres_context_t *context, 			  sres_query_t *query,			  sres_record_t **answers);staticsres_record_t **sres_combine_results(sres_resolver_t *res,		     sres_record_t **search_results[SRES_MAX_SEARCH + 1]);staticvoid sres_query_report_error(sres_query_t *q,			     sres_record_t **answers);static voidsres_resend_dns_query(sres_resolver_t *res, sres_query_t *q, int timeout);static sres_server_t *sres_server_by_socket(sres_resolver_t const *ts,				     sres_socket_t socket);staticint sres_resolver_report_error(sres_resolver_t *res, 			       sres_socket_t socket,			       int errcode,			       struct sockaddr_storage *remote,			       socklen_t remotelen, 

⌨️ 快捷键说明

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