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