xref: /csrg-svn/lib/libc/net/res_send.c (revision 24734)
1 /*
2  * Copyright (c) 1985 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)res_send.c	5.5 (Berkeley) 09/14/85";
9 #endif not lint
10 
11 /*
12  * Send query to name server and wait for reply.
13  */
14 
15 #include <sys/types.h>
16 #include <sys/time.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <stdio.h>
20 #include <errno.h>
21 #include <arpa/nameser.h>
22 #include <arpa/resolv.h>
23 
24 extern int errno;
25 
26 res_send(buf, buflen, answer, anslen)
27 	char *buf;
28 	int buflen;
29 	char *answer;
30 	int anslen;
31 {
32 	register int n;
33 	int s, retry, v_circuit, resplen;
34 	u_short id, len;
35 	char *cp;
36 	int dsmask;
37 	struct timeval timeout;
38 	HEADER *hp = (HEADER *) buf;
39 	HEADER *anhp = (HEADER *) answer;
40 
41 #ifdef DEBUG
42 	if (_res.options & RES_DEBUG) {
43 		printf("res_send()\n");
44 		p_query(buf);
45 	}
46 #endif
47 	if (!(_res.options & RES_INIT))
48 		if (res_init() == -1) {
49 			return(-1);
50 		}
51 	s = -1;
52 	v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
53 	id = hp->id;
54 	/*
55 	 * Send request, RETRY times, or until successful
56 	 */
57 	for (retry = _res.retry; --retry >= 0; ) {
58 		if (v_circuit) {
59 			/*
60 			 * Use virtual circuit.
61 			 */
62 			if (s < 0)
63 				s = socket(AF_INET, SOCK_STREAM, 0);
64 			if (connect(s, &_res.nsaddr, sizeof(_res.nsaddr)) < 0) {
65 #ifdef DEBUG
66 				if (_res.options & RES_DEBUG)
67 					printf("connect failed %d\n", errno);
68 #endif
69 				(void) close(s);
70 				s = -1;
71 				continue;
72 			}
73 			/*
74 			 * Send length & message
75 			 */
76 			len = htons(buflen);
77 			if (write(s, &len, sizeof(len)) != sizeof(len) ||
78 			    write(s, buf, buflen) != buflen) {
79 #ifdef DEBUG
80 				if (_res.options & RES_DEBUG)
81 					printf("write failed %d\n", errno);
82 #endif
83 				(void) close(s);
84 				s = -1;
85 				continue;
86 			}
87 			/*
88 			 * Receive length & response
89 			 */
90 			cp = answer;
91 			len = sizeof(short);
92 			while (len > 0 && (n = read(s, cp, len)) > 0) {
93 				cp += n;
94 				len -= n;
95 			}
96 			if (n <= 0) {
97 #ifdef DEBUG
98 				if (_res.options & RES_DEBUG)
99 					printf("read failed %d\n", errno);
100 #endif
101 				(void) close(s);
102 				s = -1;
103 				continue;
104 			}
105 			cp = answer;
106 			resplen = len = ntohs(*(short *)cp);
107 			while (len > 0 && (n = read(s, cp, len)) > 0) {
108 				cp += n;
109 				len -= n;
110 			}
111 			if (n <= 0) {
112 #ifdef DEBUG
113 				if (_res.options & RES_DEBUG)
114 					printf("read failed %d\n", errno);
115 #endif
116 				(void) close(s);
117 				s = -1;
118 				continue;
119 			}
120 		} else {
121 			/*
122 			 * Use datagrams.
123 			 */
124 			if (s < 0)
125 				s = socket(AF_INET, SOCK_DGRAM, 0);
126 			if (sendto(s, buf, buflen, 0, &_res.nsaddr,
127 			    sizeof(_res.nsaddr)) != buflen) {
128 #ifdef DEBUG
129 				if (_res.options & RES_DEBUG)
130 					printf("sendto errno = %d\n", errno);
131 #endif
132 			}
133 			/*
134 			 * Wait for reply
135 			 */
136 			timeout.tv_sec = _res.retrans;
137 			timeout.tv_usec = 0;
138 			dsmask = 1 << s;
139 			n = select(s+1, &dsmask, 0, 0, &timeout);
140 			if (n < 0) {
141 #ifdef DEBUG
142 				if (_res.options & RES_DEBUG)
143 					printf("select errno = %d\n", errno);
144 #endif
145 				continue;
146 			}
147 			if (n == 0) {
148 				/*
149 				 * timeout
150 				 */
151 #ifdef DEBUG
152 				if (_res.options & RES_DEBUG)
153 					printf("timeout\n");
154 #endif
155 				continue;
156 			}
157 			if ((resplen = recvfrom(s, answer, anslen,
158 			    0, 0, 0)) <= 0) {
159 #ifdef DEBUG
160 				if (_res.options & RES_DEBUG)
161 					printf("recvfrom, errno=%d\n", errno);
162 #endif
163 				continue;
164 			}
165 			if (id != anhp->id) {
166 				/*
167 				 * response from old query, ignore it
168 				 */
169 #ifdef DEBUG
170 				if (_res.options & RES_DEBUG) {
171 					printf("old answer:\n");
172 					p_query(answer);
173 				}
174 #endif
175 				continue;
176 			}
177 			if (!(_res.options & RES_IGNTC) && anhp->tc) {
178 				/*
179 				 * get rest of answer
180 				 */
181 #ifdef DEBUG
182 				if (_res.options & RES_DEBUG)
183 					printf("truncated answer\n");
184 #endif
185 				(void) close(s);
186 				s = -1;
187 				retry = _res.retry;
188 				v_circuit = 1;
189 				continue;
190 			}
191 		}
192 #ifdef DEBUG
193 		if (_res.options & RES_DEBUG) {
194 			printf("got answer:\n");
195 			p_query(answer);
196 		}
197 #endif
198 		(void) close(s);
199 		return (resplen);
200 	}
201 	(void) close(s);
202 	errno = ETIMEDOUT;
203 	return (-1);
204 }
205