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

📄 ares_process.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright 1998 by the Massachusetts Institute of Technology. * * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * M.I.T. makes no representations about the suitability of * this software for any purpose.  It is provided "as is" * without express or implied warranty. */#include <sys/types.h>#include <assert.h>#ifndef WIN32#include <sys/socket.h>#include <sys/uio.h>#include <netinet/in.h>#ifndef __CYGWIN__#  include <arpa/nameser.h>#endif#include <unistd.h>#endif#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <time.h>#include <errno.h>#include "ares.h"#include "ares_dns.h"#include "ares_private.h"#include "ares_local.h"#ifdef WIN32static int getErrno() { return WSAGetLastError(); }#elsestatic int getErrno() { return errno; }#endifstatic void write_tcp_data(ares_channel channel, fd_set *write_fds,			   time_t now);static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now);static void read_udp_packets(ares_channel channel, fd_set *read_fds,			     time_t now);static void process_timeouts(ares_channel channel, time_t now);static void process_answer(ares_channel channel, unsigned char *abuf,			   int alen, int whichserver, int tcp, time_t now);static void handle_error(ares_channel channel, int whichserver, time_t now);static void next_server(ares_channel channel, struct query *query, time_t now);static int next_server_new_network(ares_channel channel, struct query *query, time_t now);static int open_tcp_socket(ares_channel channel, struct server_state *server);static int open_udp_socket(ares_channel channel, struct server_state *server);static int same_questions(const unsigned char *qbuf, int qlen,			  const unsigned char *abuf, int alen);static void end_query(ares_channel channel, struct query *query, int status,		      unsigned char *abuf, int alen);/* Something interesting happened on the wire, or there was a timeout. * See what's up and respond accordingly. */void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds){  time_t now;  time(&now);  write_tcp_data(channel, write_fds, now);  read_tcp_data(channel, read_fds, now);  read_udp_packets(channel, read_fds, now);  process_timeouts(channel, now);  /* See if our local pseudo-db has any results. */  /* Querying this only on timeouts is OK (is not high-performance) */  ares_local_process_requests();}/* If any TCP sockets select true for writing, write out queued data * we have for them. */static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now){  struct server_state *server;  struct send_request *sendreq;#ifdef WIN32  WSABUF *vec;#else  struct iovec *vec;#endif  int i, n, count;  for (i = 0; i < channel->nservers; i++)    {      /* Make sure server has data to send and is selected in write_fds. */      server = &channel->servers[i];      if (!server->qhead || server->tcp_socket == -1	  || !FD_ISSET(server->tcp_socket, write_fds))	continue;      /* Count the number of send queue items. */      n = 0;      for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)	n++;#ifdef WIN32      /* Allocate iovecs so we can send all our data at once. */      vec = malloc(n * sizeof(WSABUF));      if (vec)	{		int err;	  /* Fill in the iovecs and send. */	  n = 0;	  for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)	    {	      vec[n].buf = (char *) sendreq->data;	      vec[n].len = sendreq->len;	      n++;	    }	  err = WSASend(server->tcp_socket, vec, n, &count,0,0,0 );	  if ( err == SOCKET_ERROR )	  {		  count =-1;	  }	  free(vec);#else	     /* Allocate iovecs so we can send all our data at once. */      vec = malloc(n * sizeof(struct iovec));      if (vec)	{			// int err;	  /* Fill in the iovecs and send. */	  n = 0;	  for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)	    {	      vec[n].iov_base = (char *) sendreq->data;	      vec[n].iov_len = sendreq->len;	      n++;	    }	  count = writev(server->tcp_socket, vec, n);	  free(vec);#endif	  if (count < 0)	    {	      handle_error(channel, i, now);	      continue;	    }	  /* Advance the send queue by as many bytes as we sent. */	  while (count)	    {	      sendreq = server->qhead;	      if (count >= sendreq->len)		{		  count -= sendreq->len;		  server->qhead = sendreq->next;		  if (server->qhead == NULL)		    server->qtail = NULL;		  free(sendreq);		}	      else		{		  sendreq->data += count;		  sendreq->len -= count;		  break;		}	    }	}      else	{	  /* Can't allocate iovecs; just send the first request. */	  sendreq = server->qhead;#ifndef UNDER_CE	  count = write(server->tcp_socket, sendreq->data, sendreq->len);#else          count = send(server->tcp_socket, sendreq->data, sendreq->len,0);#endif	  if (count < 0)	    {	      handle_error(channel, i, now);	      continue;	    }	  /* Advance the send queue by as many bytes as we sent. */	  if (count == sendreq->len)	    {	      server->qhead = sendreq->next;	      if (server->qhead == NULL)		server->qtail = NULL;	      free(sendreq);	    }	  else	    {	      sendreq->data += count;	      sendreq->len -= count;	    }	}    }}/* If any TCP socket selects true for reading, read some data, * allocate a buffer if we finish reading the length word, and process * a packet if we finish reading one. */static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now){  struct server_state *server;  int i, count;  for (i = 0; i < channel->nservers; i++)    {      /* Make sure the server has a socket and is selected in read_fds. */      server = &channel->servers[i];      if (server->tcp_socket == -1 || !FD_ISSET(server->tcp_socket, read_fds))	continue;      if (server->tcp_lenbuf_pos != 2)	{	  /* We haven't yet read a length word, so read that (or	   * what's left to read of it).	   */#if defined UNDER_CE || defined WIN32      count = recv(server->tcp_socket,                       server->tcp_lenbuf + server->tcp_lenbuf_pos,                       2 - server->tcp_lenbuf_pos,0);#else      count = read(server->tcp_socket,		       server->tcp_lenbuf + server->tcp_lenbuf_pos,		       2 - server->tcp_lenbuf_pos);#endif	  if (count <= 0)	    {	      handle_error(channel, i, now);	      continue;	    }	  server->tcp_lenbuf_pos += count;	  if (server->tcp_lenbuf_pos == 2)	    {	      /* We finished reading the length word.  Decode the               * length and allocate a buffer for the data.	       */	      server->tcp_length = server->tcp_lenbuf[0] << 8		| server->tcp_lenbuf[1];	      server->tcp_buffer = malloc(server->tcp_length);	      if (!server->tcp_buffer)		handle_error(channel, i, now);	      server->tcp_buffer_pos = 0;	    }	}      else	{	  /* Read data into the allocated buffer. */#if defined UNDER_CE || defined WIN32      count = recv(server->tcp_socket,		       server->tcp_buffer + server->tcp_buffer_pos,		       server->tcp_length - server->tcp_buffer_pos,0);#else      count = read(server->tcp_socket,		       server->tcp_buffer + server->tcp_buffer_pos,		       server->tcp_length - server->tcp_buffer_pos);#endif	  if (count <= 0)	    {	      handle_error(channel, i, now);	      continue;	    }	  server->tcp_buffer_pos += count;	  if (server->tcp_buffer_pos == server->tcp_length)	    {	      /* We finished reading this answer; process it and               * prepare to read another length word.	       */	      process_answer(channel, server->tcp_buffer, server->tcp_length,			     i, 1, now);	      free(server->tcp_buffer);	      server->tcp_buffer = NULL;	      server->tcp_lenbuf_pos = 0;	    }	}    }}/* If any UDP sockets select true for reading, process them. */static void read_udp_packets(ares_channel channel, fd_set *read_fds,			     time_t now){  struct server_state *server;  int i, count;  unsigned char buf[PACKETSZ + 1];  for (i = 0; i < channel->nservers; i++)    {      /* Make sure the server has a socket and is selected in read_fds. */      server = &channel->servers[i];      if ( (server->udp_socket == -1) || (!FD_ISSET(server->udp_socket, read_fds) ))	  {	     continue;	  }	  assert( server->udp_socket != -1 );	        count = recv(server->udp_socket, buf, sizeof(buf), 0);      if (count <= 0)	  {#if defined(WIN32)		//int err;		//err = WSAGetLastError();		//err = errno;		switch (getErrno())		{			case WSAEWOULDBLOCK:                FD_CLR(server->udp_socket, read_fds);               continue;			case WSAECONNABORTED:				break;			case WSAECONNRESET: // got an ICMP error on a previous send 				break;		}#endif		handle_error(channel, i, now);	  }	  else	  {		process_answer(channel, buf, count, i, 0, now);	  }    }}/* If any queries have timed out, note the timeout and move them on. */static void process_timeouts(ares_channel channel, time_t now){  struct query *query, *next;  for (query = channel->queries; query; query = next)    {      next = query->next;      if (query->timeout != 0 && now >= query->timeout)	{	  query->error_status = ARES_ETIMEOUT;	  next_server(channel, query, now);	}    }}/* Handle an answer from a server. */static void process_answer(ares_channel channel, unsigned char *abuf,			   int alen, int whichserver, int tcp, time_t now){  int id, tc, rcode;  struct query *query;  /* If there's no room in the answer for a header, we can't do much   * with it. */  if (alen < HFIXEDSZ)    return;  /* Grab the query ID, truncate bit, and response code from the packet. */  id = DNS_HEADER_QID(abuf);  tc = DNS_HEADER_TC(abuf);  rcode = DNS_HEADER_RCODE(abuf);  /* Find the query corresponding to this packet. */  for (query = channel->queries; query; query = query->next)    {      if (query->qid == id)	break;    }  if (!query)    return;  /* If we got a truncated UDP packet and are not ignoring truncation,   * don't accept the packet, and switch the query to TCP if we hadn't   * done so already.   */  if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))    {      if (!query->using_tcp)	{	  query->using_tcp = 1;	  ares__send_query(channel, query, now);	}      return;    }  /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we   * are ignoring truncation.   */  if (alen > PACKETSZ && !tcp)    alen = PACKETSZ;  /* If we aren't passing through all error packets, discard packets   * with SERVFAIL, NOTIMP, or REFUSED response codes.   */  if (!(channel->flags & ARES_FLAG_NOCHECKRESP))    {      if (rcode == SERVFAIL || rcode == NOTIMP || rcode == REFUSED)	{	  query->skip_server[whichserver] = 1;	  if (query->server == whichserver)	    next_server(channel, query, now);	  return;	}      if (!same_questions((unsigned char*)query->qbuf, query->qlen, abuf, alen))	{	  if (query->server == whichserver)	    next_server(channel, query, now);	  return;	}      /* 'No such name' */      if ((channel->flags & ARES_FLAG_TRY_NEXT_SERVER_ON_RCODE3) && rcode == NXDOMAIN)        {          if (query->server == whichserver)            {              if (next_server_new_network(channel, query, now))                return;            }        }    }  end_query(channel, query, ARES_SUCCESS, abuf, alen);}static void handle_error(ares_channel channel, int whichserver, time_t now){  struct query *query;  /* Reset communications with this server. */  ares__close_sockets(&channel->servers[whichserver]);  /* Tell all queries talking to this server to move on and not try   * this server again.   */  for (query = channel->queries; query != 0; query = query->next)

⌨️ 快捷键说明

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