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