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