1 2 /* 3 * Copyright (c) 1985 Regents of the University of California. 4 * All rights reserved. The Berkeley software License Agreement 5 * specifies the terms and conditions for redistribution. 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)res_send.c 6.2 (Berkeley) 02/22/86"; 10 #endif not lint 11 12 /* 13 * Send query to name server and wait for reply. 14 */ 15 16 #include <sys/types.h> 17 #include <sys/time.h> 18 #include <sys/socket.h> 19 #include <netinet/in.h> 20 #include <stdio.h> 21 #include <errno.h> 22 #include <arpa/nameser.h> 23 #include <arpa/resolv.h> 24 25 extern int errno; 26 27 #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) 28 29 res_send(buf, buflen, answer, anslen) 30 char *buf; 31 int buflen; 32 char *answer; 33 int anslen; 34 { 35 register int n; 36 int retry, v_circuit, resplen, ns; 37 static int s = -1; 38 u_short id, len; 39 char *cp; 40 int dsmask; 41 struct timeval timeout; 42 HEADER *hp = (HEADER *) buf; 43 HEADER *anhp = (HEADER *) answer; 44 45 #ifdef DEBUG 46 if (_res.options & RES_DEBUG) { 47 printf("res_send()\n"); 48 p_query(buf); 49 } 50 #endif DEBUG 51 if (!(_res.options & RES_INIT)) 52 if (res_init() == -1) { 53 return(-1); 54 } 55 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 56 id = hp->id; 57 /* 58 * Send request, RETRY times, or until successful 59 */ 60 for (retry = _res.retry; --retry >= 0; ) { 61 for (ns = 0; ns < _res.nscount; ns++) { 62 #ifdef DEBUG 63 if (_res.options & RES_DEBUG) 64 printf("Querying server (# %d) address = %s\n", ns+1, 65 inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); 66 #endif DEBUG 67 if (v_circuit) { 68 /* 69 * Use virtual circuit. 70 */ 71 if (s < 0) { 72 s = socket(AF_INET, SOCK_STREAM, 0); 73 if (connect(s, &(_res.nsaddr_list[ns]), 74 sizeof(struct sockaddr)) < 0) { 75 #ifdef DEBUG 76 if (_res.options & RES_DEBUG) 77 printf("connect failed %d\n",errno); 78 #endif DEBUG 79 (void) close(s); 80 s = -1; 81 continue; 82 } 83 } 84 /* 85 * Send length & message 86 */ 87 len = htons(buflen); 88 if (write(s, &len, sizeof(len)) != sizeof(len) || 89 write(s, buf, buflen) != buflen) { 90 #ifdef DEBUG 91 if (_res.options & RES_DEBUG) 92 printf("write failed %d\n", errno); 93 #endif DEBUG 94 (void) close(s); 95 s = -1; 96 continue; 97 } 98 /* 99 * Receive length & response 100 */ 101 cp = answer; 102 len = sizeof(short); 103 while (len > 0 && (n = read(s, cp, len)) > 0) { 104 cp += n; 105 len -= n; 106 } 107 if (n <= 0) { 108 #ifdef DEBUG 109 if (_res.options & RES_DEBUG) 110 printf("read failed %d\n", errno); 111 #endif DEBUG 112 (void) close(s); 113 s = -1; 114 continue; 115 } 116 cp = answer; 117 resplen = len = ntohs(*(short *)cp); 118 while (len > 0 && (n = read(s, cp, len)) > 0) { 119 cp += n; 120 len -= n; 121 } 122 if (n <= 0) { 123 #ifdef DEBUG 124 if (_res.options & RES_DEBUG) 125 printf("read failed %d\n", errno); 126 #endif DEBUG 127 (void) close(s); 128 s = -1; 129 continue; 130 } 131 } else { 132 /* 133 * Use datagrams. 134 */ 135 if (s < 0) 136 s = socket(AF_INET, SOCK_DGRAM, 0); 137 if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 138 sizeof(struct sockaddr)) != buflen) { 139 #ifdef DEBUG 140 if (_res.options & RES_DEBUG) 141 printf("sendto errno = %d\n", errno); 142 #endif DEBUG 143 } 144 /* 145 * Wait for reply 146 */ 147 timeout.tv_sec = 148 ((_res.retrans * _res.retry) / _res.nscount); 149 timeout.tv_usec = 0; 150 dsmask = 1 << s; 151 n = select(s+1, &dsmask, 0, 0, &timeout); 152 if (n < 0) { 153 #ifdef DEBUG 154 if (_res.options & RES_DEBUG) 155 printf("select errno = %d\n", errno); 156 #endif DEBUG 157 continue; 158 } 159 if (n == 0) { 160 /* 161 * timeout 162 */ 163 #ifdef DEBUG 164 if (_res.options & RES_DEBUG) 165 printf("timeout\n"); 166 #endif DEBUG 167 continue; 168 } 169 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 170 #ifdef DEBUG 171 if (_res.options & RES_DEBUG) 172 printf("recvfrom, errno=%d\n", errno); 173 #endif DEBUG 174 continue; 175 } 176 if (id != anhp->id) { 177 /* 178 * response from old query, ignore it 179 */ 180 #ifdef DEBUG 181 if (_res.options & RES_DEBUG) { 182 printf("old answer:\n"); 183 p_query(answer); 184 } 185 #endif DEBUG 186 continue; 187 } 188 if (!(_res.options & RES_IGNTC) && anhp->tc) { 189 /* 190 * get rest of answer 191 */ 192 #ifdef DEBUG 193 if (_res.options & RES_DEBUG) 194 printf("truncated answer\n"); 195 #endif DEBUG 196 (void) close(s); 197 s = -1; 198 retry = _res.retry; 199 v_circuit = 1; 200 continue; 201 } 202 } 203 #ifdef DEBUG 204 if (_res.options & RES_DEBUG) { 205 printf("got answer:\n"); 206 p_query(answer); 207 } 208 #endif DEBUG 209 /* 210 * We are going to assume that the first server is preferred 211 * over the rest (i.e. it is on the local machine) and only 212 * keep that one open. 213 */ 214 if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 215 return (resplen); 216 } else { 217 (void) close(s); 218 s = -1; 219 return (resplen); 220 } 221 } 222 } 223 (void) close(s); 224 errno = ETIMEDOUT; 225 return (-1); 226 } 227