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.15 (Berkeley) 11/18/86"; 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 30 31 #ifndef FD_SET 32 #define NFDBITS 32 33 #define FD_SETSIZE 32 34 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 35 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 36 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 37 #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 38 #endif 39 40 #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) 41 42 res_send(buf, buflen, answer, anslen) 43 char *buf; 44 int buflen; 45 char *answer; 46 int anslen; 47 { 48 register int n; 49 int retry, v_circuit, resplen, ns; 50 int gotsomewhere = 0; 51 u_short id, len; 52 char *cp; 53 fd_set dsmask; 54 struct timeval timeout; 55 HEADER *hp = (HEADER *) buf; 56 HEADER *anhp = (HEADER *) answer; 57 struct iovec iov[2]; 58 int terrno = ETIMEDOUT; 59 60 #ifdef DEBUG 61 if (_res.options & RES_DEBUG) { 62 printf("res_send()\n"); 63 p_query(buf); 64 } 65 #endif DEBUG 66 if (!(_res.options & RES_INIT)) 67 if (res_init() == -1) { 68 return(-1); 69 } 70 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 71 id = hp->id; 72 /* 73 * Send request, RETRY times, or until successful 74 */ 75 for (retry = _res.retry; retry > 0; retry--) { 76 for (ns = 0; ns < _res.nscount; ns++) { 77 #ifdef DEBUG 78 if (_res.options & RES_DEBUG) 79 printf("Querying server (# %d) address = %s\n", ns+1, 80 inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); 81 #endif DEBUG 82 if (v_circuit) { 83 /* 84 * Use virtual circuit. 85 */ 86 if (s < 0) { 87 s = socket(AF_INET, SOCK_STREAM, 0); 88 if (s < 0) { 89 terrno = errno; 90 #ifdef DEBUG 91 if (_res.options & RES_DEBUG) 92 perror("socket failed"); 93 #endif DEBUG 94 continue; 95 } 96 if (connect(s, &(_res.nsaddr_list[ns]), 97 sizeof(struct sockaddr)) < 0) { 98 terrno = errno; 99 #ifdef DEBUG 100 if (_res.options & RES_DEBUG) 101 perror("connect failed"); 102 #endif DEBUG 103 (void) close(s); 104 s = -1; 105 continue; 106 } 107 } 108 /* 109 * Send length & message 110 */ 111 len = htons((u_short)buflen); 112 iov[0].iov_base = (caddr_t)&len; 113 iov[0].iov_len = sizeof(len); 114 iov[1].iov_base = buf; 115 iov[1].iov_len = buflen; 116 if (writev(s, iov, 2) != sizeof(len) + buflen) { 117 terrno = errno; 118 #ifdef DEBUG 119 if (_res.options & RES_DEBUG) 120 perror("write failed"); 121 #endif DEBUG 122 (void) close(s); 123 s = -1; 124 continue; 125 } 126 /* 127 * Receive length & response 128 */ 129 cp = answer; 130 len = sizeof(short); 131 while (len != 0 && 132 (n = read(s, (char *)cp, (int)len)) > 0) { 133 cp += n; 134 len -= n; 135 } 136 if (n <= 0) { 137 terrno = errno; 138 #ifdef DEBUG 139 if (_res.options & RES_DEBUG) 140 perror("read failed"); 141 #endif DEBUG 142 (void) close(s); 143 s = -1; 144 continue; 145 } 146 cp = answer; 147 resplen = len = ntohs(*(u_short *)cp); 148 while (len != 0 && 149 (n = read(s, (char *)cp, (int)len)) > 0) { 150 cp += n; 151 len -= n; 152 } 153 if (n <= 0) { 154 terrno = errno; 155 #ifdef DEBUG 156 if (_res.options & RES_DEBUG) 157 perror("read failed"); 158 #endif DEBUG 159 (void) close(s); 160 s = -1; 161 continue; 162 } 163 } else { 164 /* 165 * Use datagrams. 166 */ 167 if (s < 0) 168 s = socket(AF_INET, SOCK_DGRAM, 0); 169 #if BSD >= 43 170 if (connect(s, &_res.nsaddr_list[ns], 171 sizeof(struct sockaddr)) < 0 || 172 send(s, buf, buflen, 0) != buflen) { 173 #ifdef DEBUG 174 if (_res.options & RES_DEBUG) 175 perror("connect"); 176 #endif DEBUG 177 continue; 178 } 179 #else BSD 180 if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 181 sizeof(struct sockaddr)) != buflen) { 182 #ifdef DEBUG 183 if (_res.options & RES_DEBUG) 184 perror("sendto"); 185 #endif DEBUG 186 continue; 187 } 188 #endif BSD 189 /* 190 * Wait for reply 191 */ 192 timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 193 / _res.nscount; 194 if (timeout.tv_sec <= 0) 195 timeout.tv_sec = 1; 196 timeout.tv_usec = 0; 197 wait: 198 FD_ZERO(&dsmask); 199 FD_SET(s, &dsmask); 200 n = select(s+1, &dsmask, (fd_set *)NULL, 201 (fd_set *)NULL, &timeout); 202 if (n < 0) { 203 #ifdef DEBUG 204 if (_res.options & RES_DEBUG) 205 perror("select"); 206 #endif DEBUG 207 continue; 208 } 209 if (n == 0) { 210 /* 211 * timeout 212 */ 213 #ifdef DEBUG 214 if (_res.options & RES_DEBUG) 215 printf("timeout\n"); 216 #endif DEBUG 217 gotsomewhere = 1; 218 continue; 219 } 220 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 221 #ifdef DEBUG 222 if (_res.options & RES_DEBUG) 223 perror("recvfrom"); 224 #endif DEBUG 225 continue; 226 } 227 gotsomewhere = 1; 228 if (id != anhp->id) { 229 /* 230 * response from old query, ignore it 231 */ 232 #ifdef DEBUG 233 if (_res.options & RES_DEBUG) { 234 printf("old answer:\n"); 235 p_query(answer); 236 } 237 #endif DEBUG 238 goto wait; 239 } 240 if (!(_res.options & RES_IGNTC) && anhp->tc) { 241 /* 242 * get rest of answer 243 */ 244 #ifdef DEBUG 245 if (_res.options & RES_DEBUG) 246 printf("truncated answer\n"); 247 #endif DEBUG 248 (void) close(s); 249 s = -1; 250 /* 251 * retry decremented on continue 252 * to desired starting value 253 */ 254 retry = _res.retry + 1; 255 v_circuit = 1; 256 continue; 257 } 258 } 259 #ifdef DEBUG 260 if (_res.options & RES_DEBUG) { 261 printf("got answer:\n"); 262 p_query(answer); 263 } 264 #endif DEBUG 265 /* 266 * We are going to assume that the first server is preferred 267 * over the rest (i.e. it is on the local machine) and only 268 * keep that one open. 269 */ 270 if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 271 return (resplen); 272 } else { 273 (void) close(s); 274 s = -1; 275 return (resplen); 276 } 277 } 278 } 279 if (s >= 0) { 280 (void) close(s); 281 s = -1; 282 } 283 if (v_circuit == 0) 284 if (gotsomewhere == 0) 285 errno = ECONNREFUSED; 286 else 287 errno = ETIMEDOUT; 288 else 289 errno = terrno; 290 return (-1); 291 } 292 293 /* 294 * This routine is for closing the socket if a virtual circuit is used and 295 * the program wants to close it. This provides support for endhostent() 296 * which expects to close the socket. 297 * 298 * This routine is not expected to be user visible. 299 */ 300 _res_close() 301 { 302 if (s != -1) { 303 (void) close(s); 304 s = -1; 305 } 306 } 307