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