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