res_send.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:9k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 1985, 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *   notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *   notice, this list of conditions and the following disclaimer in the
  12.  *   documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *   must display the following acknowledgement:
  15.  * This product includes software developed by the University of
  16.  * California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *   may be used to endorse or promote products derived from this software
  19.  *   without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33. #if defined(LIBC_SCCS) && !defined(lint)
  34. /*static char *sccsid = "from: @(#)res_send.c 6.45 (Berkeley) 2/24/91";*/
  35. static char *rcsid = "$Id$";
  36. #endif /* LIBC_SCCS and not lint */
  37. #include <pthread.h>
  38. #include <stdio.h>
  39. #include <errno.h>
  40. #include <resolv.h>
  41. #include <netdb.h>
  42. #include <time.h>
  43. #include <sys/timers.h>
  44. #include <sys/socket.h>
  45. #include <sys/uio.h>
  46. #include <netinet/in.h>
  47. #include "res_internal.h"
  48. enum { SEND_GIVE_UP = -1, SEND_TRY_NEXT = -2, SEND_TRY_SAME = -3,
  49.    SEND_TIMEOUT = -4, SEND_TRUNCATED = -5 };
  50. static int send_datagram(int server, int sock, const char *buf, int buflen,
  51.  char *answer, int anslen, int try,
  52.  struct res_data *data);
  53. static int send_circuit(int server, const char *buf, int buflen, char *answer,
  54. int anslen, struct res_data *data);
  55. static int close_save_errno(int sock);
  56. int res_send(const char *buf, int buflen, char *answer, int anslen)
  57. {
  58. struct res_data *data;
  59. struct sockaddr_in local;
  60. int use_virtual_circuit, result, udp_sock, have_seen_same, terrno = 0;
  61. int try, server;
  62. data = _res_init();
  63. if (!data)
  64. return -1;
  65. try = 0;
  66. server = 0;
  67. /* Try doing connectionless queries if appropriate. */
  68. if (!(data->state.options & RES_USEVC) && buflen <= PACKETSZ) {
  69. /* Create and bind a local UDP socket. */
  70. udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
  71. if (udp_sock < 0)
  72. return -1;
  73. local.sin_family = AF_INET;
  74. local.sin_addr.s_addr = htonl(INADDR_ANY);
  75. local.sin_port = htons(0);
  76. if (bind(udp_sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
  77. close(udp_sock);
  78. return -1;
  79. }
  80. /* Cycle through the retries and servers, sending off queries and
  81.  * waiting for responses. */
  82. for (; try < data->state.retry; try++) {
  83. for (; server < data->state.nscount; server++) {
  84. result = send_datagram(server, udp_sock, buf, buflen, answer,
  85.    anslen, try, data);
  86. if (result == SEND_TIMEOUT)
  87. terrno = ETIMEDOUT;
  88. else if (result != SEND_TRY_NEXT)
  89. break;
  90. }
  91. if (server < data->state.nscount)
  92. break;
  93. }
  94. close(udp_sock);
  95. if (result < 0)
  96. errno = (terrno == ETIMEDOUT) ? ETIMEDOUT : ECONNREFUSED;
  97. else
  98. errno = 0;
  99. if (result != SEND_TRUNCATED)
  100. return (result >= 0) ? result : -1;
  101. }
  102. /* Either we have to use the virtual circuit, or the server couldn't
  103.  * fit its response in a UDP packet.  Cycle through the retries and
  104.  * servers, sending off queries and waiting for responses. Allow a
  105.  * response of SEND_TRY_SAME to cause an extra retry once. */
  106. for (; try < data->state.retry; try++) {
  107. for (; server < data->state.nscount; server++) {
  108. result = send_circuit(server, buf, buflen, answer, anslen, data);
  109. terrno = errno;
  110. if (result == SEND_TRY_SAME) {
  111. if (!have_seen_same)
  112. server--;
  113. have_seen_same = 1;
  114. } else if (result != SEND_TRY_NEXT) {
  115. break;
  116. }
  117. }
  118. }
  119. errno = terrno;
  120. return (result >= 0) ? result : -1;
  121. }
  122. static int send_datagram(int server, int sock, const char *buf, int buflen,
  123.  char *answer, int anslen, int try,
  124.  struct res_data *data)
  125. {
  126. int count, interval;
  127. struct sockaddr_in local_addr;
  128. HEADER *request = (HEADER *) buf, *response = (HEADER *) answer;
  129. struct timespec timeout;
  130. struct timeval current;
  131. struct timezone zone;
  132. #ifdef DEBUG_RESOLVER
  133. if (_res.options & RES_DEBUG) {
  134.   printf("res_send: request:n");
  135.   __p_query(buf);
  136. }
  137. #endif /* DEBUG_RESOLVER */
  138. /* Send a packet to the server. */
  139. count = sendto(sock, buf, buflen, 0,
  140.    (struct sockaddr *) &data->state.nsaddr_list[server],
  141.    sizeof(struct sockaddr_in));
  142. if (count != buflen) {
  143. #ifdef DEBUG_RESOLVER
  144.     if (count < 0){
  145.     if (_res.options & RES_DEBUG)
  146.     perror("send_datagram:sendto");
  147. }
  148. #endif /* DEBUG_RESOLVER */
  149. return SEND_TRY_NEXT;
  150. }
  151. /* Await a reply with the correct ID. */
  152. while (1) {
  153. struct sockaddr_in from;
  154. int from_len;
  155. from_len = sizeof(from);
  156. interval = data->state.retrans << try;
  157. if (try > 0)
  158. interval /= data->state.nscount;
  159. gettimeofday(&current, &zone);
  160. current.tv_sec += interval;
  161. TIMEVAL_TO_TIMESPEC(&current, &timeout);
  162. count = recvfrom_timedwait(sock, answer, anslen, 0,
  163.    &from, &from_len, &timeout);
  164. if (count < 0)
  165. return SEND_TRY_NEXT;
  166. /* If the ID is wrong, it's from an old query; ignore it. */
  167. if (response->id == request->id)
  168. break;
  169. #ifdef DEBUG_RESOLVER
  170.     if (_res.options & RES_DEBUG) {
  171.   printf("res_sendto: count=%d, response:n", count);
  172.   __p_query(answer);
  173. }
  174. #endif /* DEBUG_RESOLVER */
  175. }
  176. /* Report a truncated response unless RES_IGNTC is set.  This will
  177.  * cause the res_send() loop to fall back to TCP. */
  178. if (response->tc && !(data->state.options & RES_IGNTC))
  179. return SEND_TRUNCATED;
  180. return count;
  181. }
  182. static int send_circuit(int server, const char *buf, int buflen, char *answer,
  183. int anslen, struct res_data *data)
  184. {
  185. HEADER *response = (HEADER *) answer;
  186. int sock = -1, result, n, response_len, count;
  187. unsigned short len;
  188. struct iovec iov[2];
  189. char *p, junk[512];
  190. /* If data->sock is valid, then it's an open connection to the
  191.  * first server.  Grab it if it's appropriate; close it if not. */
  192. if (data->sock) {
  193. if (server == 0)
  194. sock = data->sock;
  195. else
  196. close(data->sock);
  197. data->sock = -1;
  198. }
  199. /* Initialize our socket if we didn't grab it from data. */
  200. if (sock == -1) {
  201. sock = socket(AF_INET, SOCK_STREAM, 0);
  202. if (sock < 0)
  203. return SEND_GIVE_UP;
  204. result = connect(sock,
  205.  (struct sockaddr *) &data->state.nsaddr_list[server],
  206.  sizeof(struct sockaddr_in));
  207. if (result < 0) {
  208. close_save_errno(sock);
  209. return SEND_TRY_NEXT;
  210. }
  211. }
  212. /* Send length and message. */
  213. len = htons((unsigned short) buflen);
  214. iov[0].iov_base = (caddr_t) &len;
  215. iov[0].iov_len = sizeof(len);
  216. iov[1].iov_base = (char *) buf;
  217. iov[1].iov_len = buflen;
  218. if (writev(sock, iov, 2) != sizeof(len) + buflen) {
  219. close_save_errno(sock);
  220. return SEND_TRY_NEXT;
  221. }
  222. /* Receive length. */
  223. p = (char *) &len;
  224. n = sizeof(len);
  225. while (n) {
  226. count = read(sock, p, n);
  227. if (count <= 0) {
  228. /* If we got ECONNRESET, the remote server may have restarted,
  229.  * and we report SEND_TRY_SAME.  (The main loop will only
  230.  * allow one of these, so we don't have to worry about looping
  231.  * indefinitely.) */
  232. close_save_errno(sock);
  233. return (errno == ECONNRESET) ? SEND_TRY_SAME : SEND_TRY_NEXT;
  234. }
  235. p += count;
  236. n -= count;
  237. }
  238. len = ntohs(len);
  239. response_len = (len > anslen) ? anslen : len;
  240. len -= response_len;
  241. /* Receive message. */
  242. p = answer;
  243. n = response_len;
  244. while (n) {
  245. count = read(sock, p, n);
  246. if (count <= 0) {
  247. close_save_errno(sock);
  248. return SEND_TRY_NEXT;
  249. }
  250. p += count;
  251. n -= count;
  252. }
  253. /* If the reply is longer than our answer buffer, set the truncated
  254.  * bit and flush the rest of the reply, to keep the connection in
  255.  * sync. */
  256. if (len) {
  257. response->tc = 1;
  258. while (len) {
  259. n = (len > sizeof(junk)) ? sizeof(junk) : len;
  260. count = read(sock, junk, n);
  261. if (count <= 0) {
  262. close_save_errno(sock);
  263. return response_len;
  264. }
  265. len -= count;
  266. }
  267. }
  268. /* If this is the first server, and RES_USEVC and RES_STAYOPEN are
  269.  * both set, save the connection.  Otherwise, close it. */
  270. if (server == 0 && (data->state.options & RES_USEVC &&
  271. data->state.options & RES_STAYOPEN))
  272. data->sock = sock;
  273. else
  274. close_save_errno(sock);
  275. return response_len;
  276. }
  277. static int close_save_errno(int sock)
  278. {
  279. int terrno;
  280. terrno = errno;
  281. close(sock);
  282. errno = terrno;
  283. }