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