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