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