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 #if defined(LIBC_SCCS) && !defined(lint) 9 static char sccsid[] = "@(#)res_send.c 6.18 (Berkeley) 11/07/87"; 10 #endif LIBC_SCCS and not lint 11 12 /* 13 * Send query to name server and wait for reply. 14 */ 15 16 #include <sys/param.h> 17 #include <sys/time.h> 18 #include <sys/socket.h> 19 #include <sys/uio.h> 20 #include <netinet/in.h> 21 #include <stdio.h> 22 #include <errno.h> 23 #include <arpa/nameser.h> 24 #include <resolv.h> 25 26 extern int errno; 27 28 static int s = -1; /* socket used for communications */ 29 static struct sockaddr no_addr; 30 31 32 #ifndef FD_SET 33 #define NFDBITS 32 34 #define FD_SETSIZE 32 35 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 36 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 37 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 38 #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 39 #endif 40 41 #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) 42 43 res_send(buf, buflen, answer, anslen) 44 char *buf; 45 int buflen; 46 char *answer; 47 int anslen; 48 { 49 register int n; 50 int retry, v_circuit, resplen, ns; 51 int gotsomewhere = 0, connected = 0; 52 u_short id, len; 53 char *cp; 54 fd_set dsmask; 55 struct timeval timeout; 56 HEADER *hp = (HEADER *) buf; 57 HEADER *anhp = (HEADER *) answer; 58 struct iovec iov[2]; 59 int terrno = ETIMEDOUT; 60 char junk[512]; 61 62 #ifdef DEBUG 63 if (_res.options & RES_DEBUG) { 64 printf("res_send()\n"); 65 p_query(buf); 66 } 67 #endif DEBUG 68 if (!(_res.options & RES_INIT)) 69 if (res_init() == -1) { 70 return(-1); 71 } 72 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 73 id = hp->id; 74 /* 75 * Send request, RETRY times, or until successful 76 */ 77 for (retry = _res.retry; retry > 0; retry--) { 78 for (ns = 0; ns < _res.nscount; ns++) { 79 #ifdef DEBUG 80 if (_res.options & RES_DEBUG) 81 printf("Querying server (# %d) address = %s\n", ns+1, 82 inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 83 #endif DEBUG 84 if (v_circuit) { 85 int truncated = 0; 86 87 /* 88 * Use virtual circuit. 89 */ 90 if (s < 0) { 91 s = socket(AF_INET, SOCK_STREAM, 0); 92 if (s < 0) { 93 terrno = errno; 94 #ifdef DEBUG 95 if (_res.options & RES_DEBUG) 96 perror("socket failed"); 97 #endif DEBUG 98 continue; 99 } 100 if (connect(s, &(_res.nsaddr_list[ns]), 101 sizeof(struct sockaddr)) < 0) { 102 terrno = errno; 103 #ifdef DEBUG 104 if (_res.options & RES_DEBUG) 105 perror("connect failed"); 106 #endif DEBUG 107 (void) close(s); 108 s = -1; 109 continue; 110 } 111 } 112 /* 113 * Send length & message 114 */ 115 len = htons((u_short)buflen); 116 iov[0].iov_base = (caddr_t)&len; 117 iov[0].iov_len = sizeof(len); 118 iov[1].iov_base = buf; 119 iov[1].iov_len = buflen; 120 if (writev(s, iov, 2) != sizeof(len) + buflen) { 121 terrno = errno; 122 #ifdef DEBUG 123 if (_res.options & RES_DEBUG) 124 perror("write failed"); 125 #endif DEBUG 126 (void) close(s); 127 s = -1; 128 continue; 129 } 130 /* 131 * Receive length & response 132 */ 133 cp = answer; 134 len = sizeof(short); 135 while (len != 0 && 136 (n = read(s, (char *)cp, (int)len)) > 0) { 137 cp += n; 138 len -= n; 139 } 140 if (n <= 0) { 141 terrno = errno; 142 #ifdef DEBUG 143 if (_res.options & RES_DEBUG) 144 perror("read failed"); 145 #endif DEBUG 146 (void) close(s); 147 s = -1; 148 continue; 149 } 150 cp = answer; 151 if ((resplen = ntohs(*(u_short *)cp)) > anslen) { 152 #ifdef DEBUG 153 if (_res.options & RES_DEBUG) 154 fprintf(stderr, "response truncated\n"); 155 #endif DEBUG 156 len = anslen; 157 truncated = 1; 158 } else 159 len = resplen; 160 while (len != 0 && 161 (n = read(s, (char *)cp, (int)len)) > 0) { 162 cp += n; 163 len -= n; 164 } 165 if (n <= 0) { 166 terrno = errno; 167 #ifdef DEBUG 168 if (_res.options & RES_DEBUG) 169 perror("read failed"); 170 #endif DEBUG 171 (void) close(s); 172 s = -1; 173 continue; 174 } 175 if (truncated) { 176 /* 177 * Flush rest of answer 178 * so connection stays in synch. 179 */ 180 anhp->tc = 1; 181 len = resplen - anslen; 182 while (len != 0) { 183 n = (len > sizeof(junk) ? 184 sizeof(junk) : len); 185 if ((n = read(s, junk, n)) > 0) 186 len -= n; 187 else 188 break; 189 } 190 } 191 } else { 192 /* 193 * Use datagrams. 194 */ 195 if (s < 0) 196 s = socket(AF_INET, SOCK_DGRAM, 0); 197 #if BSD >= 43 198 if (_res.nscount == 1 || retry == _res.retry) { 199 /* 200 * Don't use connect if we might 201 * still receive a response 202 * from another server. 203 */ 204 if (connected == 0) { 205 if (connect(s, &_res.nsaddr_list[ns], 206 sizeof(struct sockaddr)) < 0) { 207 #ifdef DEBUG 208 if (_res.options & RES_DEBUG) 209 perror("connect"); 210 #endif DEBUG 211 continue; 212 } 213 connected = 1; 214 } 215 if (send(s, buf, buflen, 0) != buflen) { 216 #ifdef DEBUG 217 if (_res.options & RES_DEBUG) 218 perror("send"); 219 #endif DEBUG 220 continue; 221 } 222 } else 223 #endif BSD 224 if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 225 sizeof(struct sockaddr)) != buflen) { 226 #ifdef DEBUG 227 if (_res.options & RES_DEBUG) 228 perror("sendto"); 229 #endif DEBUG 230 continue; 231 } 232 233 /* 234 * Wait for reply 235 */ 236 timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 237 / _res.nscount; 238 if (timeout.tv_sec <= 0) 239 timeout.tv_sec = 1; 240 timeout.tv_usec = 0; 241 wait: 242 FD_ZERO(&dsmask); 243 FD_SET(s, &dsmask); 244 n = select(s+1, &dsmask, (fd_set *)NULL, 245 (fd_set *)NULL, &timeout); 246 if (n < 0) { 247 #ifdef DEBUG 248 if (_res.options & RES_DEBUG) 249 perror("select"); 250 #endif DEBUG 251 continue; 252 } 253 if (n == 0) { 254 /* 255 * timeout 256 */ 257 #ifdef DEBUG 258 if (_res.options & RES_DEBUG) 259 printf("timeout\n"); 260 #endif DEBUG 261 /* 262 * Disconnect if we want to listen 263 * for responses from more than one server. 264 */ 265 if (_res.nscount > 1 && connected) { 266 (void) connect(s, &no_addr, 267 sizeof(no_addr)); 268 connected = 0; 269 } 270 gotsomewhere = 1; 271 continue; 272 } 273 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 274 #ifdef DEBUG 275 if (_res.options & RES_DEBUG) 276 perror("recvfrom"); 277 #endif DEBUG 278 continue; 279 } 280 gotsomewhere = 1; 281 if (id != anhp->id) { 282 /* 283 * response from old query, ignore it 284 */ 285 #ifdef DEBUG 286 if (_res.options & RES_DEBUG) { 287 printf("old answer:\n"); 288 p_query(answer); 289 } 290 #endif DEBUG 291 goto wait; 292 } 293 if (!(_res.options & RES_IGNTC) && anhp->tc) { 294 /* 295 * get rest of answer 296 */ 297 #ifdef DEBUG 298 if (_res.options & RES_DEBUG) 299 printf("truncated answer\n"); 300 #endif DEBUG 301 (void) close(s); 302 s = -1; 303 /* 304 * retry decremented on continue 305 * to desired starting value 306 */ 307 retry = _res.retry + 1; 308 v_circuit = 1; 309 continue; 310 } 311 } 312 #ifdef DEBUG 313 if (_res.options & RES_DEBUG) { 314 printf("got answer:\n"); 315 p_query(answer); 316 } 317 #endif DEBUG 318 /* 319 * We are going to assume that the first server is preferred 320 * over the rest (i.e. it is on the local machine) and only 321 * keep that one open. 322 */ 323 if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 324 return (resplen); 325 } else { 326 (void) close(s); 327 s = -1; 328 return (resplen); 329 } 330 } 331 } 332 if (s >= 0) { 333 (void) close(s); 334 s = -1; 335 } 336 if (v_circuit == 0) 337 if (gotsomewhere == 0) 338 errno = ECONNREFUSED; 339 else 340 errno = ETIMEDOUT; 341 else 342 errno = terrno; 343 return (-1); 344 } 345 346 /* 347 * This routine is for closing the socket if a virtual circuit is used and 348 * the program wants to close it. This provides support for endhostent() 349 * which expects to close the socket. 350 * 351 * This routine is not expected to be user visible. 352 */ 353 _res_close() 354 { 355 if (s != -1) { 356 (void) close(s); 357 s = -1; 358 } 359 } 360