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.13 (Berkeley) 05/07/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 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 FD_ZERO(&dsmask); 183 FD_SET(s, &dsmask); 184 n = select(s+1, &dsmask, (fd_set *)NULL, 185 (fd_set *)NULL, &timeout); 186 if (n < 0) { 187 #ifdef DEBUG 188 if (_res.options & RES_DEBUG) 189 perror("select"); 190 #endif DEBUG 191 continue; 192 } 193 if (n == 0) { 194 /* 195 * timeout 196 */ 197 #ifdef DEBUG 198 if (_res.options & RES_DEBUG) 199 printf("timeout\n"); 200 #endif DEBUG 201 gotsomewhere = 1; 202 continue; 203 } 204 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 205 #ifdef DEBUG 206 if (_res.options & RES_DEBUG) 207 perror("recvfrom"); 208 #endif DEBUG 209 continue; 210 } 211 gotsomewhere = 1; 212 if (id != anhp->id) { 213 /* 214 * response from old query, ignore it 215 */ 216 #ifdef DEBUG 217 if (_res.options & RES_DEBUG) { 218 printf("old answer:\n"); 219 p_query(answer); 220 } 221 #endif DEBUG 222 goto wait; 223 } 224 if (!(_res.options & RES_IGNTC) && anhp->tc) { 225 /* 226 * get rest of answer 227 */ 228 #ifdef DEBUG 229 if (_res.options & RES_DEBUG) 230 printf("truncated answer\n"); 231 #endif DEBUG 232 (void) close(s); 233 s = -1; 234 /* 235 * retry decremented on continue 236 * to desired starting value 237 */ 238 retry = _res.retry + 1; 239 v_circuit = 1; 240 continue; 241 } 242 } 243 #ifdef DEBUG 244 if (_res.options & RES_DEBUG) { 245 printf("got answer:\n"); 246 p_query(answer); 247 } 248 #endif DEBUG 249 /* 250 * We are going to assume that the first server is preferred 251 * over the rest (i.e. it is on the local machine) and only 252 * keep that one open. 253 */ 254 if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 255 return (resplen); 256 } else { 257 (void) close(s); 258 s = -1; 259 return (resplen); 260 } 261 } 262 } 263 (void) close(s); 264 s = -1; 265 if (v_circuit == 0 && gotsomewhere == 0) 266 errno = ECONNREFUSED; 267 else 268 errno = ETIMEDOUT; 269 return (-1); 270 } 271 272 /* 273 * This routine is for closing the socket if a virtual circuit is used and 274 * the program wants to close it. This provides support for endhostent() 275 * which expects to close the socket. 276 * 277 * This routine is not expected to be user visible. 278 */ 279 _res_close() 280 { 281 if (s != -1) { 282 (void) close(s); 283 s = -1; 284 } 285 } 286