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.19 (Berkeley) 03/07/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 #endif BSD 229 if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 230 sizeof(struct sockaddr)) != buflen) { 231 #ifdef DEBUG 232 if (_res.options & RES_DEBUG) 233 perror("sendto"); 234 #endif DEBUG 235 continue; 236 } 237 238 /* 239 * Wait for reply 240 */ 241 timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 242 / _res.nscount; 243 if (timeout.tv_sec <= 0) 244 timeout.tv_sec = 1; 245 timeout.tv_usec = 0; 246 wait: 247 FD_ZERO(&dsmask); 248 FD_SET(s, &dsmask); 249 n = select(s+1, &dsmask, (fd_set *)NULL, 250 (fd_set *)NULL, &timeout); 251 if (n < 0) { 252 #ifdef DEBUG 253 if (_res.options & RES_DEBUG) 254 perror("select"); 255 #endif DEBUG 256 continue; 257 } 258 if (n == 0) { 259 /* 260 * timeout 261 */ 262 #ifdef DEBUG 263 if (_res.options & RES_DEBUG) 264 printf("timeout\n"); 265 #endif DEBUG 266 /* 267 * Disconnect if we want to listen 268 * for responses from more than one server. 269 */ 270 if (_res.nscount > 1 && connected) { 271 (void) connect(s, &no_addr, 272 sizeof(no_addr)); 273 connected = 0; 274 } 275 gotsomewhere = 1; 276 continue; 277 } 278 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 279 #ifdef DEBUG 280 if (_res.options & RES_DEBUG) 281 perror("recvfrom"); 282 #endif DEBUG 283 continue; 284 } 285 gotsomewhere = 1; 286 if (id != anhp->id) { 287 /* 288 * response from old query, ignore it 289 */ 290 #ifdef DEBUG 291 if (_res.options & RES_DEBUG) { 292 printf("old answer:\n"); 293 p_query(answer); 294 } 295 #endif DEBUG 296 goto wait; 297 } 298 if (!(_res.options & RES_IGNTC) && anhp->tc) { 299 /* 300 * get rest of answer 301 */ 302 #ifdef DEBUG 303 if (_res.options & RES_DEBUG) 304 printf("truncated answer\n"); 305 #endif DEBUG 306 (void) close(s); 307 s = -1; 308 /* 309 * retry decremented on continue 310 * to desired starting value 311 */ 312 retry = _res.retry + 1; 313 v_circuit = 1; 314 continue; 315 } 316 } 317 #ifdef DEBUG 318 if (_res.options & RES_DEBUG) { 319 printf("got answer:\n"); 320 p_query(answer); 321 } 322 #endif DEBUG 323 /* 324 * We are going to assume that the first server is preferred 325 * over the rest (i.e. it is on the local machine) and only 326 * keep that one open. 327 */ 328 if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 329 return (resplen); 330 } else { 331 (void) close(s); 332 s = -1; 333 return (resplen); 334 } 335 } 336 } 337 if (s >= 0) { 338 (void) close(s); 339 s = -1; 340 } 341 if (v_circuit == 0) 342 if (gotsomewhere == 0) 343 errno = ECONNREFUSED; 344 else 345 errno = ETIMEDOUT; 346 else 347 errno = terrno; 348 return (-1); 349 } 350 351 /* 352 * This routine is for closing the socket if a virtual circuit is used and 353 * the program wants to close it. This provides support for endhostent() 354 * which expects to close the socket. 355 * 356 * This routine is not expected to be user visible. 357 */ 358 _res_close() 359 { 360 if (s != -1) { 361 (void) close(s); 362 s = -1; 363 } 364 } 365