xref: /csrg-svn/lib/libc/net/res_send.c (revision 24032)
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.3 (Berkeley) 07/25/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 <nameser.h>
22 #include <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 	if (_res.options & RES_DEBUG) {
42 		printf("res_send()\n");
43 		p_query(buf);
44 	}
45 	if (!(_res.options & RES_INIT))
46 		res_init();
47 	s = -1;
48 	v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
49 	id = hp->id;
50 	/*
51 	 * Send request, RETRY times, or until successful
52 	 */
53 	for (retry = _res.retry; --retry >= 0; ) {
54 		if (v_circuit) {
55 			/*
56 			 * Use virtual circuit.
57 			 */
58 			if (s < 0)
59 				s = socket(AF_INET, SOCK_STREAM, 0);
60 			if (connect(s, &_res.nsaddr, sizeof(_res.nsaddr)) < 0) {
61 				if (_res.options & RES_DEBUG)
62 					printf("connect failed %d\n", errno);
63 				(void) close(s);
64 				s = -1;
65 				continue;
66 			}
67 			/*
68 			 * Send length & message
69 			 */
70 			len = htons(buflen);
71 			if (write(s, &len, sizeof(len)) != sizeof(len) ||
72 			    write(s, buf, buflen) != buflen) {
73 				if (_res.options & RES_DEBUG)
74 					printf("write failed %d\n", errno);
75 				(void) close(s);
76 				s = -1;
77 				continue;
78 			}
79 			/*
80 			 * Receive length & response
81 			 */
82 			cp = answer;
83 			len = sizeof(short);
84 			while (len > 0 && (n = read(s, cp, len)) > 0) {
85 				cp += n;
86 				len -= n;
87 			}
88 			if (n <= 0) {
89 				if (_res.options & RES_DEBUG)
90 					printf("read failed %d\n", errno);
91 				(void) close(s);
92 				s = -1;
93 				continue;
94 			}
95 			cp = answer;
96 			resplen = len = ntohs(*(short *)cp);
97 			while (len > 0 && (n = read(s, cp, len)) > 0) {
98 				cp += n;
99 				len -= n;
100 			}
101 			if (n <= 0) {
102 				if (_res.options & RES_DEBUG)
103 					printf("read failed %d\n", errno);
104 				(void) close(s);
105 				s = -1;
106 				continue;
107 			}
108 		} else {
109 			/*
110 			 * Use datagrams.
111 			 */
112 			if (s < 0)
113 				s = socket(AF_INET, SOCK_DGRAM, 0);
114 			if (sendto(s, buf, buflen, 0, &_res.nsaddr,
115 			    sizeof(_res.nsaddr)) != buflen) {
116 				if (_res.options & RES_DEBUG)
117 					printf("sendto errno = %d\n", errno);
118 			}
119 			/*
120 			 * Wait for reply
121 			 */
122 			timeout.tv_sec = _res.retrans;
123 			timeout.tv_usec = 0;
124 			dsmask = 1 << s;
125 			n = select(s+1, &dsmask, 0, 0, &timeout);
126 			if (n < 0) {
127 				if (_res.options & RES_DEBUG)
128 					printf("select errno = %d\n", errno);
129 				continue;
130 			}
131 			if (n == 0) {
132 				/*
133 				 * timeout
134 				 */
135 				if (_res.options & RES_DEBUG)
136 					printf("timeout\n");
137 				continue;
138 			}
139 			if ((resplen = recvfrom(s, answer, anslen,
140 			    0, 0, 0)) <= 0) {
141 				if (_res.options & RES_DEBUG)
142 					printf("recvfrom, errno=%d\n", errno);
143 				continue;
144 			}
145 			if (id != anhp->id) {
146 				/*
147 				 * response from old query, ignore it
148 				 */
149 				if (_res.options & RES_DEBUG) {
150 					printf("old answer:\n");
151 					p_query(answer);
152 				}
153 				continue;
154 			}
155 			if (!(_res.options & RES_IGNTC) && anhp->tc) {
156 				/*
157 				 * get rest of answer
158 				 */
159 				if (_res.options & RES_DEBUG)
160 					printf("truncated answer\n");
161 				(void) close(s);
162 				s = -1;
163 				retry = _res.retry;
164 				v_circuit = 1;
165 				continue;
166 			}
167 		}
168 		if (_res.options & RES_DEBUG) {
169 			printf("got answer:\n");
170 			p_query(answer);
171 		}
172 		(void) close(s);
173 		return (resplen);
174 	}
175 	(void) close(s);
176 	errno = ETIMEDOUT;
177 	return (-1);
178 }
179