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.10 (Berkeley) 04/10/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 extern u_short htons(), ntohs(); 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; ) { 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 if (write(s, (char *)&len, sizeof(len)) != sizeof(len)|| 100 write(s, buf, buflen) != buflen) { 101 #ifdef DEBUG 102 if (_res.options & RES_DEBUG) 103 perror("write failed"); 104 #endif DEBUG 105 (void) close(s); 106 s = -1; 107 continue; 108 } 109 /* 110 * Receive length & response 111 */ 112 cp = answer; 113 len = sizeof(short); 114 while (len > 0 && 115 (n = read(s, (char *)cp, (int)len)) > 0) { 116 cp += n; 117 len -= n; 118 } 119 if (n <= 0) { 120 #ifdef DEBUG 121 if (_res.options & RES_DEBUG) 122 perror("read failed"); 123 #endif DEBUG 124 (void) close(s); 125 s = -1; 126 continue; 127 } 128 cp = answer; 129 resplen = len = ntohs(*(u_short *)cp); 130 while (len > 0 && 131 (n = read(s, (char *)cp, (int)len)) > 0) { 132 cp += n; 133 len -= n; 134 } 135 if (n <= 0) { 136 #ifdef DEBUG 137 if (_res.options & RES_DEBUG) 138 perror("read failed"); 139 #endif DEBUG 140 (void) close(s); 141 s = -1; 142 continue; 143 } 144 } else { 145 /* 146 * Use datagrams. 147 */ 148 if (s < 0) 149 s = socket(AF_INET, SOCK_DGRAM, 0); 150 #if BSD >= 43 151 if (connect(s, &_res.nsaddr_list[ns], 152 sizeof(struct sockaddr)) < 0 || 153 send(s, buf, buflen, 0) != buflen) { 154 #ifdef DEBUG 155 if (_res.options & RES_DEBUG) 156 perror("connect"); 157 #endif DEBUG 158 continue; 159 } 160 #else BSD 161 if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], 162 sizeof(struct sockaddr)) != buflen) { 163 #ifdef DEBUG 164 if (_res.options & RES_DEBUG) 165 perror("sendto"); 166 #endif DEBUG 167 continue; 168 } 169 #endif BSD 170 /* 171 * Wait for reply 172 */ 173 timeout.tv_sec = (_res.retrans << (_res.retry - retry)) 174 / _res.nscount; 175 if (timeout.tv_sec <= 0) 176 timeout.tv_sec = 1; 177 timeout.tv_usec = 0; 178 wait: 179 dsmask = 1 << s; 180 n = select(s+1, &dsmask, 0, 0, &timeout); 181 if (n < 0) { 182 #ifdef DEBUG 183 if (_res.options & RES_DEBUG) 184 perror("select"); 185 #endif DEBUG 186 continue; 187 } 188 if (n == 0) { 189 /* 190 * timeout 191 */ 192 #ifdef DEBUG 193 if (_res.options & RES_DEBUG) 194 printf("timeout\n"); 195 #endif DEBUG 196 gotsomewhere = 1; 197 continue; 198 } 199 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 200 #ifdef DEBUG 201 if (_res.options & RES_DEBUG) 202 perror("recvfrom"); 203 #endif DEBUG 204 continue; 205 } 206 gotsomewhere = 1; 207 if (id != anhp->id) { 208 /* 209 * response from old query, ignore it 210 */ 211 #ifdef DEBUG 212 if (_res.options & RES_DEBUG) { 213 printf("old answer:\n"); 214 p_query(answer); 215 } 216 #endif DEBUG 217 goto wait; 218 } 219 if (!(_res.options & RES_IGNTC) && anhp->tc) { 220 /* 221 * get rest of answer 222 */ 223 #ifdef DEBUG 224 if (_res.options & RES_DEBUG) 225 printf("truncated answer\n"); 226 #endif DEBUG 227 (void) close(s); 228 s = -1; 229 retry = _res.retry; 230 v_circuit = 1; 231 continue; 232 } 233 } 234 #ifdef DEBUG 235 if (_res.options & RES_DEBUG) { 236 printf("got answer:\n"); 237 p_query(answer); 238 } 239 #endif DEBUG 240 /* 241 * We are going to assume that the first server is preferred 242 * over the rest (i.e. it is on the local machine) and only 243 * keep that one open. 244 */ 245 if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { 246 return (resplen); 247 } else { 248 (void) close(s); 249 s = -1; 250 return (resplen); 251 } 252 } 253 } 254 (void) close(s); 255 s = -1; 256 if (v_circuit == 0 && gotsomewhere == 0) 257 errno = ECONNREFUSED; 258 else 259 errno = ETIMEDOUT; 260 return (-1); 261 } 262 263 /* 264 * This routine is for closing the socket if a virtual circuit is used and 265 * the program wants to close it. This provides support for endhostent() 266 * which expects to close the socket. 267 * 268 * This routine is not expected to be user visible. 269 */ 270 _res_close() 271 { 272 if (s != -1) { 273 (void) close(s); 274 s = -1; 275 } 276 } 277