xref: /original-bsd/lib/libc/net/res_send.c (revision dd2e2b2b)
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.6 (Berkeley) 03/14/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 <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 	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 	if (v_circuit == 0 && gotsomewhere == 0)
250 		errno = ECONNREFUSED;
251 	else
252 		errno = ETIMEDOUT;
253 	return (-1);
254 }
255