ares_send.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /* $Id$ */
  2. /* Copyright 1998 by the Massachusetts Institute of Technology.
  3. *
  4. * Permission to use, copy, modify, and distribute this
  5. * software and its documentation for any purpose and without
  6. * fee is hereby granted, provided that the above copyright
  7. * notice appear in all copies and that both that copyright
  8. * notice and this permission notice appear in supporting
  9. * documentation, and that the name of M.I.T. not be used in
  10. * advertising or publicity pertaining to distribution of the
  11. * software without specific, written prior permission.
  12. * M.I.T. makes no representations about the suitability of
  13. * this software for any purpose. It is provided "as is"
  14. * without express or implied warranty.
  15. */
  16. #include "setup.h"
  17. #ifdef HAVE_SYS_SOCKET_H
  18. # include <sys/socket.h>
  19. #endif
  20. #ifdef HAVE_NETINET_IN_H
  21. # include <netinet/in.h>
  22. #endif
  23. #ifdef HAVE_ARPA_NAMESER_H
  24. # include <arpa/nameser.h>
  25. #else
  26. # include "nameser.h"
  27. #endif
  28. #ifdef HAVE_ARPA_NAMESER_COMPAT_H
  29. # include <arpa/nameser_compat.h>
  30. #endif
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <time.h>
  34. #include "ares.h"
  35. #include "ares_dns.h"
  36. #include "ares_private.h"
  37. void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
  38. ares_callback callback, void *arg)
  39. {
  40. struct query *query;
  41. int i;
  42. struct timeval now;
  43. /* Verify that the query is at least long enough to hold the header. */
  44. if (qlen < HFIXEDSZ || qlen >= (1 << 16))
  45. {
  46. callback(arg, ARES_EBADQUERY, 0, NULL, 0);
  47. return;
  48. }
  49. /* Allocate space for query and allocated fields. */
  50. query = malloc(sizeof(struct query));
  51. if (!query)
  52. {
  53. callback(arg, ARES_ENOMEM, 0, NULL, 0);
  54. return;
  55. }
  56. query->tcpbuf = malloc(qlen + 2);
  57. if (!query->tcpbuf)
  58. {
  59. free(query);
  60. callback(arg, ARES_ENOMEM, 0, NULL, 0);
  61. return;
  62. }
  63. query->server_info = malloc(channel->nservers *
  64. sizeof(query->server_info[0]));
  65. if (!query->server_info)
  66. {
  67. free(query->tcpbuf);
  68. free(query);
  69. callback(arg, ARES_ENOMEM, 0, NULL, 0);
  70. return;
  71. }
  72. /* Compute the query ID. Start with no timeout. */
  73. query->qid = (unsigned short)DNS_HEADER_QID(qbuf);
  74. query->timeout.tv_sec = 0;
  75. query->timeout.tv_usec = 0;
  76. /* Form the TCP query buffer by prepending qlen (as two
  77. * network-order bytes) to qbuf.
  78. */
  79. query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff);
  80. query->tcpbuf[1] = (unsigned char)(qlen & 0xff);
  81. memcpy(query->tcpbuf + 2, qbuf, qlen);
  82. query->tcplen = qlen + 2;
  83. /* Fill in query arguments. */
  84. query->qbuf = query->tcpbuf + 2;
  85. query->qlen = qlen;
  86. query->callback = callback;
  87. query->arg = arg;
  88. /* Initialize query status. */
  89. query->try = 0;
  90. /* Choose the server to send the query to. If rotation is enabled, keep track
  91. * of the next server we want to use. */
  92. query->server = channel->last_server;
  93. if (channel->rotate == 1)
  94. channel->last_server = (channel->last_server + 1) % channel->nservers;
  95. for (i = 0; i < channel->nservers; i++)
  96. {
  97. query->server_info[i].skip_server = 0;
  98. query->server_info[i].tcp_connection_generation = 0;
  99. }
  100. query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ;
  101. query->error_status = ARES_ECONNREFUSED;
  102. query->timeouts = 0;
  103. /* Initialize our list nodes. */
  104. ares__init_list_node(&(query->queries_by_qid), query);
  105. ares__init_list_node(&(query->queries_by_timeout), query);
  106. ares__init_list_node(&(query->queries_to_server), query);
  107. ares__init_list_node(&(query->all_queries), query);
  108. /* Chain the query into the list of all queries. */
  109. ares__insert_in_list(&(query->all_queries), &(channel->all_queries));
  110. /* Keep track of queries bucketed by qid, so we can process DNS
  111. * responses quickly.
  112. */
  113. ares__insert_in_list(
  114. &(query->queries_by_qid),
  115. &(channel->queries_by_qid[query->qid % ARES_QID_TABLE_SIZE]));
  116. /* Perform the first query action. */
  117. now = ares__tvnow();
  118. ares__send_query(channel, query, &now);
  119. }