示例#1
0
void DNSTaskResolvCallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) {
    struct DNSTask *dnstask = (struct DNSTask *) arg;
    char *query;
    int id, qr, opcode, aa, tc, rd, ra, rcode;
    long len;
    unsigned int qdcount, ancount, nscount, arcount, i;
    const unsigned char *aptr;
    debug("LobjId:%d, Hostname %s", dnstask->task->LObjId, dnstask->task->Record.HostName);
    if (status != ARES_SUCCESS and status != ARES_ENODATA) {
        return;
    }

    /* Parse the answer header. */
    id = DNS_HEADER_QID(abuf);
    qr = DNS_HEADER_QR(abuf);
    opcode = DNS_HEADER_OPCODE(abuf);
    aa = DNS_HEADER_AA(abuf);
    tc = DNS_HEADER_TC(abuf);
    rd = DNS_HEADER_RD(abuf);
    ra = DNS_HEADER_RA(abuf);
    rcode = DNS_HEADER_RCODE(abuf);
    qdcount = DNS_HEADER_QDCOUNT(abuf);
    ancount = DNS_HEADER_ANCOUNT(abuf);
    nscount = DNS_HEADER_NSCOUNT(abuf);
    arcount = DNS_HEADER_ARCOUNT(abuf);

    aptr = abuf + HFIXEDSZ;

    ares_expand_name(aptr, abuf, alen, &query, &len);

    for (i = 0; i < qdcount; i++) {
        aptr = skip_question(aptr, abuf, alen);
        if (aptr == NULL) return;
    }

    dnstask->task->code = STATE_ERROR;

    switch (dnstask->role) {
        case DNS_TASK:
            for (i = 0; i < ancount; i++) {
                debug("try %d %d ", dnstask->task->LObjId, ancount);
                aptr = CheckPatternAfterParseAnswer(dnstask, aptr, abuf, alen);
                if (aptr == NULL) break;
            }
            dnstask->task->callback(dnstask->task);


            break;

    }


}
示例#2
0
文件: adig.c 项目: changloong/gool
static void callback(void *arg, int status, int timeouts,
                     unsigned char *abuf, int alen)
{
  char *name = (char *) arg;
  int id, qr, opcode, aa, tc, rd, ra, rcode;
  unsigned int qdcount, ancount, nscount, arcount, i;
  const unsigned char *aptr;

  (void) timeouts;

  /* Display the query name if given. */
  if (name)
    printf("Answer for query %s:\n", name);

  /* Display an error message if there was an error, but only stop if
   * we actually didn't get an answer buffer.
   */
  if (status != ARES_SUCCESS)
    {
      printf("%s\n", ares_strerror(status));
      if (!abuf)
        return;
    }

  /* Won't happen, but check anyway, for safety. */
  if (alen < HFIXEDSZ)
    return;

  /* Parse the answer header. */
  id = DNS_HEADER_QID(abuf);
  qr = DNS_HEADER_QR(abuf);
  opcode = DNS_HEADER_OPCODE(abuf);
  aa = DNS_HEADER_AA(abuf);
  tc = DNS_HEADER_TC(abuf);
  rd = DNS_HEADER_RD(abuf);
  ra = DNS_HEADER_RA(abuf);
  rcode = DNS_HEADER_RCODE(abuf);
  qdcount = DNS_HEADER_QDCOUNT(abuf);
  ancount = DNS_HEADER_ANCOUNT(abuf);
  nscount = DNS_HEADER_NSCOUNT(abuf);
  arcount = DNS_HEADER_ARCOUNT(abuf);

  /* Display the answer header. */
  printf("id: %d\n", id);
  printf("flags: %s%s%s%s%s\n",
         qr ? "qr " : "",
         aa ? "aa " : "",
         tc ? "tc " : "",
         rd ? "rd " : "",
         ra ? "ra " : "");
  printf("opcode: %d	%s\n", opcode, opcodes[opcode]);
  printf("rcode: %d	%s\n", rcode, rcodes[rcode]);

  printf("qdcount: %d\n", qdcount);
  printf("ancount: %d\n",  ancount);
  printf("nscount: %d\n", nscount);
  printf("arcount: %d\n",  arcount);
  
  /* Display the questions. */
  printf("Questions:\n");
  aptr = abuf + HFIXEDSZ;
  for (i = 0; i < qdcount; i++)
    {
      aptr = display_question(aptr, abuf, alen);
      if (aptr == NULL)
        return;
    }

  /* Display the answers. */
  printf("Answers:\n");
  for (i = 0; i < ancount; i++)
    {
      aptr = display_rr(aptr, abuf, alen);
      if (aptr == NULL)
        return;
    }

  /* Display the NS records. */
  printf("NS records:\n");
  for (i = 0; i < nscount; i++)
    {
      aptr = display_rr(aptr, abuf, alen);
      if (aptr == NULL)
        return;
    }

  /* Display the additional records. */
  printf("Additional records:\n");
  for (i = 0; i < arcount; i++)
    {
      aptr = display_rr(aptr, abuf, alen);
      if (aptr == NULL)
        return;
    }
}
示例#3
0
文件: dns2.c 项目: tjyang/abmon
void dns_detail_callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen)
{
	int id, qr, opcode, aa, tc, rd, ra, rcode;
	unsigned int qdcount, ancount, nscount, arcount, i;
	const unsigned char *aptr;
	dns_resp_t *response = (dns_resp_t *) arg;

	clearstrbuffer(response->msgbuf);
	response->msgstatus = status;

	/*
	 * Display an error message if there was an error, but only stop if
	 * we actually didn't get an answer buffer.
	 */
	switch (status) {
	  case ARES_SUCCESS: 
		  break;
	  case ARES_ENODATA:
		  addtobuffer(response->msgbuf, "No data returned from server\n");
		  if (!abuf) return;
		  break;
	  case ARES_EFORMERR:
		  addtobuffer(response->msgbuf, "Server could not understand query\n");
		  if (!abuf) return;
		  break;
	  case ARES_ESERVFAIL:
		  addtobuffer(response->msgbuf, "Server failed\n");
		  if (!abuf) return;
		  break;
	  case ARES_ENOTFOUND:
		  addtobuffer(response->msgbuf, "Name not found\n");
		  if (!abuf) return;
		  break;
	  case ARES_ENOTIMP:
		  addtobuffer(response->msgbuf, "Not implemented\n");
		  if (!abuf) return;
		  break;
	  case ARES_EREFUSED:
		  addtobuffer(response->msgbuf, "Server refused query\n");
		  if (!abuf) return;
		  break;
	  case ARES_EBADNAME:
		  addtobuffer(response->msgbuf, "Invalid name in query\n");
		  if (!abuf) return;
		  break;
	  case ARES_ETIMEOUT:
		  addtobuffer(response->msgbuf, "Timeout\n");
		  if (!abuf) return;
		  break;
	  case ARES_ECONNREFUSED:
		  addtobuffer(response->msgbuf, "Server unavailable\n");
		  if (!abuf) return;
		  break;
	  case ARES_ENOMEM:
		  addtobuffer(response->msgbuf, "Out of memory\n");
		  if (!abuf) return;
		  break;
	  case ARES_EDESTRUCTION:
		  addtobuffer(response->msgbuf, "Timeout (channel destroyed)\n");
		  if (!abuf) return;
		  break;
	  default:
		  addtobuffer(response->msgbuf, "Undocumented ARES return code\n");
		  if (!abuf) return;
		  break;
	}

	/* Won't happen, but check anyway, for safety. */
	if (alen < HFIXEDSZ) return;

	/* Parse the answer header. */
	id = DNS_HEADER_QID(abuf);
	qr = DNS_HEADER_QR(abuf);
	opcode = DNS_HEADER_OPCODE(abuf);
	aa = DNS_HEADER_AA(abuf);
	tc = DNS_HEADER_TC(abuf);
	rd = DNS_HEADER_RD(abuf);
	ra = DNS_HEADER_RA(abuf);
	rcode = DNS_HEADER_RCODE(abuf);
	qdcount = DNS_HEADER_QDCOUNT(abuf);
	ancount = DNS_HEADER_ANCOUNT(abuf);
	nscount = DNS_HEADER_NSCOUNT(abuf);
	arcount = DNS_HEADER_ARCOUNT(abuf);

	/* Display the answer header. */
	sprintf(msg, "id: %d\n", id);
	addtobuffer(response->msgbuf, msg);
	sprintf(msg, "flags: %s%s%s%s%s\n",
		qr ? "qr " : "",
		aa ? "aa " : "",
		tc ? "tc " : "",
		rd ? "rd " : "",
		ra ? "ra " : "");
	addtobuffer(response->msgbuf, msg);
	sprintf(msg, "opcode: %s\n", opcodes[opcode]);
	addtobuffer(response->msgbuf, msg);
	sprintf(msg, "rcode: %s\n", rcodes[rcode]);
	addtobuffer(response->msgbuf, msg);

	/* Display the questions. */
	addtobuffer(response->msgbuf, "Questions:\n");
	aptr = abuf + HFIXEDSZ;
	for (i = 0; i < qdcount; i++) {
		aptr = display_question(aptr, abuf, alen, response);
		if (aptr == NULL) return;
	}

	/* Display the answers. */
	addtobuffer(response->msgbuf, "Answers:\n");
	for (i = 0; i < ancount; i++) {
		aptr = display_rr(aptr, abuf, alen, response);
		if (aptr == NULL) return;
	}

	/* Display the NS records. */
	addtobuffer(response->msgbuf, "NS records:\n");
	for (i = 0; i < nscount; i++) {
		aptr = display_rr(aptr, abuf, alen, response);
		if (aptr == NULL) return;
	}

	/* Display the additional records. */
	addtobuffer(response->msgbuf, "Additional records:\n");
	for (i = 0; i < arcount; i++) {
		aptr = display_rr(aptr, abuf, alen, response);
		if (aptr == NULL) return;
	}

	return;
}
示例#4
0
文件: evdns.c 项目: 5bruce/sbase
/* parse reply record */
int evdns_parse_reply(unsigned char *buf, int nbuf, HOSTENT *hostent)
{
    unsigned char *p = NULL, *end = NULL, *s = NULL, *ps = NULL; 
    int i = 0, qdcount = 0, ancount = 0, nscount = 0, arcount = 0, 
        qr = 0, opcode = 0, aa = 0, tc = 0, rd = 0, 
        ra = 0, rcode = 0, type = 0, dnsclass = 0, ttl = 0, rrlen = 0;

    if(buf && nbuf > HFIXEDSZ)
    {
        hostent->naddrs = 0;
        hostent->nalias = 0;
        p = buf;
        end = buf + nbuf;
        hostent->qid = DNS_HEADER_QID(p);
        qr = DNS_HEADER_QR(p);
        opcode = DNS_HEADER_OPCODE(p);
        aa = DNS_HEADER_AA(p);
        tc = DNS_HEADER_TC(p);
        rd = DNS_HEADER_RD(p);
        ra = DNS_HEADER_RA(p);
        rcode = DNS_HEADER_RCODE(p);
        qdcount = DNS_HEADER_QDCOUNT(p);
        ancount = DNS_HEADER_ANCOUNT(p);
        nscount = DNS_HEADER_NSCOUNT(p);
        arcount = DNS_HEADER_ARCOUNT(p);
        p += HFIXEDSZ;
        /* Display the answer header. */
        /*
        printf("id: %d\n", id);
        printf("flags: %s%s%s%s%s\n",
                qr ? "qr " : "",
                aa ? "aa " : "",
                tc ? "tc " : "",
                rd ? "rd " : "",
                ra ? "ra " : "");
        printf("opcode: %s\n", opcodes[opcode]);
        printf("rcode: %s\n", rcodes[rcode]);
        fprintf(stdout, "qdcount:%d\nancount:%d\nnscount:%d\narcount:%d\n", 
                qdcount, ancount, nscount, arcount);
        */
        /* parse question */
        for(i = 0; i < qdcount; i++)
        {
            ps = (unsigned char *)hostent->name;
            p = evdns_expand_name(p, buf, end, ps);
            /* Parse the question type and class. */
            type = DNS_QUESTION_TYPE(p);
            dnsclass = DNS_QUESTION_CLASS(p);
            p  += QFIXEDSZ;
            /*
            fprintf(stdout, "qname:%-15s", name);
            fprintf(stdout, "\tqtype:%d", type);
            fprintf(stdout, "\tqclass:%d\r\n", dnsclass);
            */
        }
        /* parse A name */
        for(i = 0; i < ancount; i++)
        {
            ps = (unsigned char *)hostent->alias[hostent->nalias++];
            p = evdns_expand_name(p, buf, end, ps);
            type = DNS_RR_TYPE(p);
            dnsclass = DNS_RR_CLASS(p);
            ttl = DNS_RR_TTL(p);
            rrlen = DNS_RR_LEN(p);
            p += RRFIXEDSZ;
            /*
            fprintf(stdout, "name:%s type:%d dnsclass:%d ttl:%d rrlen:%d ", 
                    name, type, dnsclass, ttl, rrlen);
            */
            /* addr name */
            if(type == TYPE_ANAME)
            {
                hostent->addrs[hostent->naddrs++] = *((int *)p);
            }
            /* Canonical name */
            else if(type == TYPE_CNAME)
            {
                ps = (unsigned char *)hostent->alias[hostent->nalias++];
                s = evdns_expand_name(p, buf, end, ps);
                //fprintf(stdout, "cname:%s ", cname);
            }
            /* pointer */
            else if(type == TYPE_PTR)
            {
                ps = (unsigned char *)hostent->alias[hostent->nalias++];
                s = evdns_expand_name(p, buf, end, ps);
                //fprintf(stdout, "pointer:%s ", cname);
            }
            //fprintf(stdout, "\r\n");
            p += rrlen;
        }
        return 0;
    }
    return -1;
}
示例#5
0
文件: ares_send.c 项目: 005/gevent
void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
               ares_callback callback, void *arg)
{
  struct query *query;
  int i, packetsz;
  struct timeval now;

  /* Verify that the query is at least long enough to hold the header. */
  if (qlen < HFIXEDSZ || qlen >= (1 << 16))
    {
      callback(arg, ARES_EBADQUERY, 0, NULL, 0);
      return;
    }

  /* Allocate space for query and allocated fields. */
  query = malloc(sizeof(struct query));
  if (!query)
    {
      callback(arg, ARES_ENOMEM, 0, NULL, 0);
      return;
    }
  query->tcpbuf = malloc(qlen + 2);
  if (!query->tcpbuf)
    {
      free(query);
      callback(arg, ARES_ENOMEM, 0, NULL, 0);
      return;
    }
  query->server_info = malloc(channel->nservers *
                              sizeof(query->server_info[0]));
  if (!query->server_info)
    {
      free(query->tcpbuf);
      free(query);
      callback(arg, ARES_ENOMEM, 0, NULL, 0);
      return;
    }

  /* Compute the query ID.  Start with no timeout. */
  query->qid = DNS_HEADER_QID(qbuf);
  query->timeout.tv_sec = 0;
  query->timeout.tv_usec = 0;

  /* Form the TCP query buffer by prepending qlen (as two
   * network-order bytes) to qbuf.
   */
  query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff);
  query->tcpbuf[1] = (unsigned char)(qlen & 0xff);
  memcpy(query->tcpbuf + 2, qbuf, qlen);
  query->tcplen = qlen + 2;

  /* Fill in query arguments. */
  query->qbuf = query->tcpbuf + 2;
  query->qlen = qlen;
  query->callback = callback;
  query->arg = arg;

  /* Initialize query status. */
  query->try_count = 0;

  /* Choose the server to send the query to. If rotation is enabled, keep track
   * of the next server we want to use. */
  query->server = channel->last_server;
  if (channel->rotate == 1)
    channel->last_server = (channel->last_server + 1) % channel->nservers;

  for (i = 0; i < channel->nservers; i++)
    {
      query->server_info[i].skip_server = 0;
      query->server_info[i].tcp_connection_generation = 0;
    }

  packetsz = (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : PACKETSZ;
  query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > packetsz;

  query->error_status = ARES_ECONNREFUSED;
  query->timeouts = 0;

  /* Initialize our list nodes. */
  ares__init_list_node(&(query->queries_by_qid),     query);
  ares__init_list_node(&(query->queries_by_timeout), query);
  ares__init_list_node(&(query->queries_to_server),  query);
  ares__init_list_node(&(query->all_queries),        query);

  /* Chain the query into the list of all queries. */
  ares__insert_in_list(&(query->all_queries), &(channel->all_queries));
  /* Keep track of queries bucketed by qid, so we can process DNS
   * responses quickly.
   */
  ares__insert_in_list(
    &(query->queries_by_qid),
    &(channel->queries_by_qid[query->qid % ARES_QID_TABLE_SIZE]));

  /* Perform the first query action. */
  now = ares__tvnow();
  ares__send_query(channel, query, &now);
}
示例#6
0
/* Handle an answer from a server. */
static void process_answer(ares_channel channel, unsigned char *abuf,
                           int alen, int whichserver, int tcp,
                           struct timeval *now)
{
  int tc, rcode, packetsz;
  unsigned short id;
  struct query *query;
  struct list_node* list_head;
  struct list_node* list_node;

  /* 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. The queries are
   * hashed/bucketed by query id, so this lookup should be quick.  Note that
   * both the query id and the questions must be the same; when the query id
   * wraps around we can have multiple outstanding queries with the same query
   * id, so we need to check both the id and question.
   */
  query = NULL;
  list_head = &(channel->queries_by_qid[id % ARES_QID_TABLE_SIZE]);
  for (list_node = list_head->next; list_node != list_head;
       list_node = list_node->next)
    {
      struct query *q = list_node->data;
      if ((q->qid == id) && same_questions(q->qbuf, q->qlen, abuf, alen))
        {
          query = q;
          break;
        }
    }
  if (!query)
    return;

  packetsz = PACKETSZ;
  /* If we use EDNS and server answers with one of these RCODES, the protocol
   * extension is not understood by the responder. We must retry the query
   * without EDNS enabled.
   */
  if (channel->flags & ARES_FLAG_EDNS)
  {
      packetsz = channel->ednspsz;
      if (rcode == NOTIMP || rcode == FORMERR || rcode == SERVFAIL)
      {
          int qlen = alen - EDNSFIXEDSZ;
          channel->flags ^= ARES_FLAG_EDNS;
          query->tcplen -= EDNSFIXEDSZ;
          query->qlen -= EDNSFIXEDSZ;
          query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff);
          query->tcpbuf[1] = (unsigned char)(qlen & 0xff);
          DNS_HEADER_SET_ARCOUNT(query->tcpbuf + 2, 0);
          query->tcpbuf = realloc(query->tcpbuf, query->tcplen);
          ares__send_query(channel, query, now);
          return;
      }
示例#7
0
/* If any TCP sockets select true for writing, write out queued data
 * we have for them.
 */
static void write_tcp_data_core(ares_channel channel, int server_idx,
	time_t now)
{
  struct server_state *server;
  struct send_request *sendreq;
#ifdef WIN32
  WSABUF *vec;
#else
  struct iovec *vec;
#endif
  int n, count;

  server = &channel->servers[server_idx];
  if (!server->qhead || server->tcp_socket == -1 )
    return;

  /* 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, server_idx, now);
	  return;
	}

      /* 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;
	      free(sendreq);
	      if (server->qhead == NULL)
	      {
		server->qtail = NULL;
		assert(count==0);
		break;
	      }
	    }
	  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, server_idx, now);
	  return;
	}

      /* 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 ( server->qhead==NULL && channel->poll_cb_func ) {
        (*(channel->poll_cb_func))( channel->poll_cb_data, channel, server_idx,
	  server->tcp_socket, ARES_POLLACTION_WRITEOFF);
    }
}


static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
{
  struct server_state *server;
  int i;

  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 )
        continue;
      if ( write_fds && !FD_ISSET(server->tcp_socket, write_fds))
	continue;

     write_tcp_data_core(channel, i, now);
  }
}

/* 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, int server_idx, 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. */
      if ( server_idx>=0 && i != server_idx )
         continue;
      server = &channel->servers[i];
      if (server->tcp_socket == -1 )
        continue;
      if (!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, int server_idx,
			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++)
    {
      if ( server_idx>=0 && i != server_idx )
          continue;
      /* Make sure the server has a socket and is selected in read_fds. */
      server = &channel->servers[i];
      if ( (server->udp_socket == -1) )
          continue;
      if ( read_fds && !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:
			    if ( read_fds ) {
			       // read_fds is only null when using epoll
			       // which shouldn't happen under windows
			       // don't know why CLR is here anyways
			       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)
	{
	  //fprintf(stderr, "kennard:ares:process_timeouts: got timeout\n");
	  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);
}
示例#8
0
void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
	       ares_callback callback, void *arg)
{
  struct query *query;
  int i;
  time_t now;

  /* Verify that the query is at least long enough to hold the header. */
  if (qlen < HFIXEDSZ || qlen >= (1 << 16))
    {
      callback(arg, ARES_EBADQUERY, NULL, 0);
      return;
    }

  /* Allocate space for query and allocated fields. */
  query = malloc(sizeof(struct query));
  if (!query)
    {
      callback(arg, ARES_ENOMEM, NULL, 0);
      return;
    }
  query->tcpbuf = malloc(qlen + 2);
  if (!query->tcpbuf)
    {
      free(query);
      callback(arg, ARES_ENOMEM, NULL, 0);
      return;
    }
    if (channel->nservers)
    {
      query->skip_server = malloc(channel->nservers * sizeof(int));
    }
    else
    {
        query->skip_server = 0;
    }
  
    if (!query->skip_server)
    {
      free(query->tcpbuf);
      free(query);
      callback(arg, ARES_ENOMEM, NULL, 0);
      return;
    }

  /* Compute the query ID.  Start with no timeout. */
  query->qid = DNS_HEADER_QID(qbuf);
  query->timeout = 0;

  /* Form the TCP query buffer by prepending qlen (as two
   * network-order bytes) to qbuf.
   */
  query->tcpbuf[0] = (qlen >> 8) & 0xff;
  query->tcpbuf[1] = qlen & 0xff;
  memcpy(query->tcpbuf + 2, qbuf, qlen);
  query->tcplen = qlen + 2;

  /* Fill in query arguments. */
  query->qbuf = query->tcpbuf + 2;
  query->qlen = qlen;
  query->callback = callback;
  query->arg = arg;

  /* Initialize query status. */
  query->itry = 0;
  query->server = 0;
  for (i = 0; i < channel->nservers; i++)
    query->skip_server[i] = 0;
  query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ;
  query->error_status = ARES_ECONNREFUSED;

  /* Chain the query into this channel's query list. */
  query->next = channel->queries;
  channel->queries = query;

  /* Perform the first query action. */
  time(&now);
  ares__send_query(channel, query, now);
}