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