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