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.16 (Berkeley) 01/15/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 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 (_res.nscount == 1) { 171 /* 172 * Connect/Send is detrimental if you 173 * are going to poll more than one server 174 */ 175 if (connect(s, &_res.nsaddr_list[ns], 176 sizeof(struct sockaddr)) < 0 || 177 send(s, buf, buflen, 0) != buflen) { 178 #ifdef DEBUG 179 if (_res.options & RES_DEBUG) 180 perror("connect"); 181 #endif DEBUG 182 continue; 183 } 184 } else 185 #endif BSD 186 if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 187 sizeof(struct sockaddr)) != buflen) { 188 #ifdef DEBUG 189 if (_res.options & RES_DEBUG) 190 perror("sendto"); 191 #endif DEBUG 192 continue; 193 } 194 195 /* 196 * Wait for reply 197 */ 198 timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 199 / _res.nscount; 200 if (timeout.tv_sec <= 0) 201 timeout.tv_sec = 1; 202 timeout.tv_usec = 0; 203 wait: 204 FD_ZERO(&dsmask); 205 FD_SET(s, &dsmask); 206 n = select(s+1, &dsmask, (fd_set *)NULL, 207 (fd_set *)NULL, &timeout); 208 if (n < 0) { 209 #ifdef DEBUG 210 if (_res.options & RES_DEBUG) 211 perror("select"); 212 #endif DEBUG 213 continue; 214 } 215 if (n == 0) { 216 /* 217 * timeout 218 */ 219 #ifdef DEBUG 220 if (_res.options & RES_DEBUG) 221 printf("timeout\n"); 222 #endif DEBUG 223 gotsomewhere = 1; 224 continue; 225 } 226 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 227 #ifdef DEBUG 228 if (_res.options & RES_DEBUG) 229 perror("recvfrom"); 230 #endif DEBUG 231 continue; 232 } 233 gotsomewhere = 1; 234 if (id != anhp->id) { 235 /* 236 * response from old query, ignore it 237 */ 238 #ifdef DEBUG 239 if (_res.options & RES_DEBUG) { 240 printf("old answer:\n"); 241 p_query(answer); 242 } 243 #endif DEBUG 244 goto wait; 245 } 246 if (!(_res.options & RES_IGNTC) && anhp->tc) { 247 /* 248 * get rest of answer 249 */ 250 #ifdef DEBUG 251 if (_res.options & RES_DEBUG) 252 printf("truncated answer\n"); 253 #endif DEBUG 254 (void) close(s); 255 s = -1; 256 /* 257 * retry decremented on continue 258 * to desired starting value 259 */ 260 retry = _res.retry + 1; 261 v_circuit = 1; 262 continue; 263 } 264 } 265 #ifdef DEBUG 266 if (_res.options & RES_DEBUG) { 267 printf("got answer:\n"); 268 p_query(answer); 269 } 270 #endif DEBUG 271 /* 272 * We are going to assume that the first server is preferred 273 * over the rest (i.e. it is on the local machine) and only 274 * keep that one open. 275 */ 276 if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 277 return (resplen); 278 } else { 279 (void) close(s); 280 s = -1; 281 return (resplen); 282 } 283 } 284 } 285 if (s >= 0) { 286 (void) close(s); 287 s = -1; 288 } 289 if (v_circuit == 0) 290 if (gotsomewhere == 0) 291 errno = ECONNREFUSED; 292 else 293 errno = ETIMEDOUT; 294 else 295 errno = terrno; 296 return (-1); 297 } 298 299 /* 300 * This routine is for closing the socket if a virtual circuit is used and 301 * the program wants to close it. This provides support for endhostent() 302 * which expects to close the socket. 303 * 304 * This routine is not expected to be user visible. 305 */ 306 _res_close() 307 { 308 if (s != -1) { 309 (void) close(s); 310 s = -1; 311 } 312 } 313