1 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 17 #include "ares_setup.h" 18 19 #ifdef HAVE_SYS_SOCKET_H 20 # include <sys/socket.h> 21 #endif 22 #ifdef HAVE_NETINET_IN_H 23 # include <netinet/in.h> 24 #endif 25 #ifdef HAVE_ARPA_NAMESER_H 26 # include <arpa/nameser.h> 27 #else 28 # include "nameser.h" 29 #endif 30 #ifdef HAVE_ARPA_NAMESER_COMPAT_H 31 # include <arpa/nameser_compat.h> 32 #endif 33 34 #include <stdlib.h> 35 #include <string.h> 36 #include <time.h> 37 #include "ares.h" 38 #include "ares_dns.h" 39 #include "ares_private.h" 40 41 void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen, 42 ares_callback callback, void *arg) 43 { 44 struct query *query; 45 int i; 46 struct timeval now; 47 48 /* Verify that the query is at least long enough to hold the header. */ 49 if (qlen < HFIXEDSZ || qlen >= (1 << 16)) 50 { 51 callback(arg, ARES_EBADQUERY, 0, NULL, 0); 52 return; 53 } 54 55 /* Allocate space for query and allocated fields. */ 56 query = malloc(sizeof(struct query)); 57 if (!query) 58 { 59 callback(arg, ARES_ENOMEM, 0, NULL, 0); 60 return; 61 } 62 query->tcpbuf = malloc(qlen + 2); 63 if (!query->tcpbuf) 64 { 65 free(query); 66 callback(arg, ARES_ENOMEM, 0, NULL, 0); 67 return; 68 } 69 query->server_info = malloc(channel->nservers * 70 sizeof(query->server_info[0])); 71 if (!query->server_info) 72 { 73 free(query->tcpbuf); 74 free(query); 75 callback(arg, ARES_ENOMEM, 0, NULL, 0); 76 return; 77 } 78 79 /* Compute the query ID. Start with no timeout. */ 80 query->qid = (unsigned short)DNS_HEADER_QID(qbuf); 81 query->timeout.tv_sec = 0; 82 query->timeout.tv_usec = 0; 83 84 /* Form the TCP query buffer by prepending qlen (as two 85 * network-order bytes) to qbuf. 86 */ 87 query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff); 88 query->tcpbuf[1] = (unsigned char)(qlen & 0xff); 89 memcpy(query->tcpbuf + 2, qbuf, qlen); 90 query->tcplen = qlen + 2; 91 92 /* Fill in query arguments. */ 93 query->qbuf = query->tcpbuf + 2; 94 query->qlen = qlen; 95 query->callback = callback; 96 query->arg = arg; 97 98 /* Initialize query status. */ 99 query->try_count = 0; 100 101 /* Choose the server to send the query to. If rotation is enabled, keep track 102 * of the next server we want to use. */ 103 query->server = channel->last_server; 104 if (channel->rotate == 1) 105 channel->last_server = (channel->last_server + 1) % channel->nservers; 106 107 for (i = 0; i < channel->nservers; i++) 108 { 109 query->server_info[i].skip_server = 0; 110 query->server_info[i].tcp_connection_generation = 0; 111 } 112 query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ; 113 query->error_status = ARES_ECONNREFUSED; 114 query->timeouts = 0; 115 116 /* Initialize our list nodes. */ 117 ares__init_list_node(&(query->queries_by_qid), query); 118 ares__init_list_node(&(query->queries_by_timeout), query); 119 ares__init_list_node(&(query->queries_to_server), query); 120 ares__init_list_node(&(query->all_queries), query); 121 122 /* Chain the query into the list of all queries. */ 123 ares__insert_in_list(&(query->all_queries), &(channel->all_queries)); 124 /* Keep track of queries bucketed by qid, so we can process DNS 125 * responses quickly. 126 */ 127 ares__insert_in_list( 128 &(query->queries_by_qid), 129 &(channel->queries_by_qid[query->qid % ARES_QID_TABLE_SIZE])); 130 131 /* Perform the first query action. */ 132 now = ares__tvnow(); 133 ares__send_query(channel, query, &now); 134 } 135