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