|
|
1.1 root 1: /*
2: * Copyright (c) 1985, 1989 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)send.c 5.17 (Berkeley) 6/29/90";
22: #endif /* not lint */
23:
24: /*
25: *******************************************************************************
26: *
27: * send.c --
28: *
29: * Routine to send request packets to a name server.
30: *
31: * Based on "@(#)res_send.c 6.25 (Berkeley) 6/1/90".
32: *
33: *******************************************************************************
34: */
35:
36:
37: /*
38: * Send query to name server and wait for reply.
39: */
40:
41: #include <sys/param.h>
42: #include <sys/time.h>
43: #include <sys/socket.h>
44: #include <sys/uio.h>
45: #include <netinet/in.h>
46: #include <stdio.h>
47: #include <errno.h>
48: #include <arpa/nameser.h>
49: #include <arpa/inet.h>
50: #include <resolv.h>
51: #include "res.h"
52:
53: extern int errno;
54:
55: static int s = -1; /* socket used for communications */
56:
57:
58: #ifndef FD_SET
59: #define NFDBITS 32
60: #define FD_SETSIZE 32
61: #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
62: #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
63: #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
64: #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
65: #endif
66:
67: #define SR 1 /* SendRequest style */
68:
69: #ifndef DEBUG
70: #define DEBUG
71: #endif
72:
73: unsigned short nsport = NAMESERVER_PORT;
74:
75:
76:
77: /*
78: *******************************************************************************
79: *
80: * SendRequest --
81: *
82: * Sends a request packet to a name server whose address
83: * is specified by the first argument and returns with
84: * the answer packet.
85: *
86: * Results:
87: * SUCCESS - the request was sent and an answer
88: * was received.
89: * TIME_OUT - the virtual circuit connection timed-out
90: * or a reply to a datagram wasn't received.
91: *
92: *
93: *******************************************************************************
94: */
95:
96: int
97: SendRequest(nsAddrPtr, buf, buflen, answer, anslen, trueLenPtr)
98: struct in_addr *nsAddrPtr;
99: char *buf;
100: int buflen;
101: char *answer;
102: u_int anslen;
103: int *trueLenPtr;
104: {
105: register int n;
106: int try, v_circuit, resplen, ns;
107: int gotsomewhere = 0, connected = 0;
108: int connreset = 0;
109: u_short id, len;
110: char *cp;
111: fd_set dsmask;
112: struct timeval timeout;
113: HEADER *hp = (HEADER *) buf;
114: HEADER *anhp = (HEADER *) answer;
115: struct iovec iov[2];
116: int terrno = ETIMEDOUT;
117: char junk[512];
118:
119: #if SR
120: struct sockaddr_in sin;
121:
122: if (_res.options & RES_DEBUG2) {
123: printf("------------\nSendRequest(), len %d\n", buflen);
124: Print_query(buf, buf+buflen, 1);
125: }
126: sin.sin_family = AF_INET;
127: sin.sin_port = htons(nsport);
128: sin.sin_addr = *nsAddrPtr;
129: #else
130: #ifdef DEBUG
131: if (_res.options & RES_DEBUG) {
132: printf("res_send()\n");
133: p_query(buf);
134: }
135: #endif DEBUG
136: if (!(_res.options & RES_INIT))
137: if (res_init() == -1) {
138: return(-1);
139: }
140: #endif /* SR */
141: v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
142: id = hp->id;
143: /*
144: * Send request, RETRY times, or until successful
145: */
146: for (try = 0; try < _res.retry; try++) {
147: #if !SR
148: for (ns = 0; ns < _res.nscount; ns++) {
149: #ifdef DEBUG
150: if (_res.options & RES_DEBUG)
151: printf("Querying server (# %d) address = %s\n", ns+1,
152: inet_ntoa(_res.nsaddr_list[ns].sin_addr));
153: #endif DEBUG
154: #endif /* !SR */
155: usevc:
156: if (v_circuit) {
157: int truncated = 0;
158:
159: /*
160: * Use virtual circuit;
161: * at most one attempt per server.
162: */
163: try = _res.retry;
164: if (s < 0) {
165: s = socket(AF_INET, SOCK_STREAM, 0);
166: if (s < 0) {
167: terrno = errno;
168: #ifdef DEBUG
169: if (_res.options & RES_DEBUG)
170: perror("socket (vc) failed");
171: #endif DEBUG
172: continue;
173: }
174: #if SR
175: if (connect(s, &sin,
176: #else
177: if (connect(s, &(_res.nsaddr_list[ns]),
178: #endif
179: sizeof(struct sockaddr)) < 0) {
180: terrno = errno;
181: #ifdef DEBUG
182: if (_res.options & RES_DEBUG)
183: perror("connect failed");
184: #endif DEBUG
185: (void) close(s);
186: s = -1;
187: continue;
188: }
189: }
190: /*
191: * Send length & message
192: */
193: len = htons((u_short)buflen);
194: iov[0].iov_base = (caddr_t)&len;
195: iov[0].iov_len = sizeof(len);
196: iov[1].iov_base = buf;
197: iov[1].iov_len = buflen;
198: if (writev(s, iov, 2) != sizeof(len) + buflen) {
199: terrno = errno;
200: #ifdef DEBUG
201: if (_res.options & RES_DEBUG)
202: perror("write failed");
203: #endif DEBUG
204: (void) close(s);
205: s = -1;
206: continue;
207: }
208: /*
209: * Receive length & response
210: */
211: cp = answer;
212: len = sizeof(short);
213: while (len != 0 &&
214: (n = read(s, (char *)cp, (int)len)) > 0) {
215: cp += n;
216: len -= n;
217: }
218: if (n <= 0) {
219: terrno = errno;
220: #ifdef DEBUG
221: if (_res.options & RES_DEBUG)
222: perror("read failed");
223: #endif DEBUG
224: (void) close(s);
225: s = -1;
226: /*
227: * A long running process might get its TCP
228: * connection reset if the remote server was
229: * restarted. Requery the server instead of
230: * trying a new one. When there is only one
231: * server, this means that a query might work
232: * instead of failing. We only allow one reset
233: * per query to prevent looping.
234: */
235: if (terrno == ECONNRESET && !connreset) {
236: connreset = 1;
237: ns--;
238: }
239: continue;
240: }
241: cp = answer;
242: if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
243: #ifdef DEBUG
244: if (_res.options & RES_DEBUG)
245: fprintf(stderr, "response truncated\n");
246: #endif DEBUG
247: len = anslen;
248: truncated = 1;
249: } else
250: len = resplen;
251: while (len != 0 &&
252: (n = read(s, (char *)cp, (int)len)) > 0) {
253: cp += n;
254: len -= n;
255: }
256: if (n <= 0) {
257: terrno = errno;
258: #ifdef DEBUG
259: if (_res.options & RES_DEBUG)
260: perror("read failed");
261: #endif DEBUG
262: (void) close(s);
263: s = -1;
264: continue;
265: }
266: if (truncated) {
267: /*
268: * Flush rest of answer
269: * so connection stays in synch.
270: */
271: anhp->tc = 1;
272: len = resplen - anslen;
273: while (len != 0) {
274: n = (len > sizeof(junk) ?
275: sizeof(junk) : len);
276: if ((n = read(s, junk, n)) > 0)
277: len -= n;
278: else
279: break;
280: }
281: }
282: } else {
283: /*
284: * Use datagrams.
285: */
286: if (s < 0) {
287: s = socket(AF_INET, SOCK_DGRAM, 0);
288: if (s < 0) {
289: terrno = errno;
290: #ifdef DEBUG
291: if (_res.options & RES_DEBUG)
292: perror("socket (dg) failed");
293: #endif DEBUG
294: continue;
295: }
296: }
297: #if SR
298: /*
299: * Special case the send code below
300: * since we have just 1 server.
301: */
302: #if BSD >= 43
303: if (connected == 0) {
304: if (connect(s, &sin,
305: sizeof(struct sockaddr)) < 0) {
306: if (_res.options & RES_DEBUG)
307: perror("connect");
308: continue;
309: }
310: connected = 1;
311: }
312: if (send(s, buf, buflen, 0) != buflen) {
313: if (_res.options & RES_DEBUG)
314: perror("send");
315: continue;
316: }
317: #else /* BSD */
318: if (sendto(s, buf, buflen, 0, &sin,
319: sizeof(struct sockaddr)) != buflen) {
320: if (_res.options & RES_DEBUG)
321: perror("sendto");
322: continue;
323: }
324: #endif
325: #else /* SR */
326: #if BSD >= 43
327: /*
328: * I'm tired of answering this question, so:
329: * On a 4.3BSD+ machine (client and server,
330: * actually), sending to a nameserver datagram
331: * port with no nameserver will cause an
332: * ICMP port unreachable message to be returned.
333: * If our datagram socket is "connected" to the
334: * server, we get an ECONNREFUSED error on the next
335: * socket operation, and select returns if the
336: * error message is received. We can thus detect
337: * the absence of a nameserver without timing out.
338: * If we have sent queries to at least two servers,
339: * however, we don't want to remain connected,
340: * as we wish to receive answers from the first
341: * server to respond.
342: */
343: if (_res.nscount == 1 || (try == 0 && ns == 0)) {
344: /*
345: * Don't use connect if we might
346: * still receive a response
347: * from another server.
348: */
349: if (connected == 0) {
350: if (connect(s, &_res.nsaddr_list[ns],
351: sizeof(struct sockaddr)) < 0) {
352: #ifdef DEBUG
353: if (_res.options & RES_DEBUG)
354: perror("connect");
355: #endif DEBUG
356: continue;
357: }
358: connected = 1;
359: }
360: if (send(s, buf, buflen, 0) != buflen) {
361: #ifdef DEBUG
362: if (_res.options & RES_DEBUG)
363: perror("send");
364: #endif DEBUG
365: continue;
366: }
367: } else {
368: /*
369: * Disconnect if we want to listen
370: * for responses from more than one server.
371: */
372: if (connected) {
373: (void) connect(s, &no_addr,
374: sizeof(no_addr));
375: connected = 0;
376: }
377: #endif BSD
378: if (sendto(s, buf, buflen, 0,
379: &_res.nsaddr_list[ns],
380: sizeof(struct sockaddr)) != buflen) {
381: #ifdef DEBUG
382: if (_res.options & RES_DEBUG)
383: perror("sendto");
384: #endif DEBUG
385: continue;
386: }
387: #if BSD >= 43
388: }
389: #endif
390: #endif /* SR */
391:
392: /*
393: * Wait for reply
394: */
395: timeout.tv_sec = (_res.retrans << try);
396: #if !SR
397: if (try > 0)
398: timeout.tv_sec /= _res.nscount;
399: #endif /* SR */
400: if (timeout.tv_sec <= 0)
401: timeout.tv_sec = 1;
402: timeout.tv_usec = 0;
403: wait:
404: FD_ZERO(&dsmask);
405: FD_SET(s, &dsmask);
406: n = select(s+1, &dsmask, (fd_set *)NULL,
407: (fd_set *)NULL, &timeout);
408: if (n < 0) {
409: #ifdef DEBUG
410: if (_res.options & RES_DEBUG)
411: perror("select");
412: #endif DEBUG
413: continue;
414: }
415: if (n == 0) {
416: /*
417: * timeout
418: */
419: #ifdef DEBUG
420: if (_res.options & RES_DEBUG)
421: printf("timeout (%d secs)\n",
422: timeout.tv_sec);
423: #endif DEBUG
424: #if BSD >= 43
425: gotsomewhere = 1;
426: #endif
427: continue;
428: }
429: if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
430: #ifdef DEBUG
431: if (_res.options & RES_DEBUG)
432: perror("recvfrom");
433: #endif DEBUG
434: continue;
435: }
436: gotsomewhere = 1;
437: if (id != anhp->id) {
438: /*
439: * response from old query, ignore it
440: */
441: #if SR
442: if (_res.options & RES_DEBUG2) {
443: printf("------------\nOld answer:\n");
444: Print_query(answer, answer+resplen, 1);
445: }
446: #else
447: #ifdef DEBUG
448: if (_res.options & RES_DEBUG) {
449: printf("old answer:\n");
450: p_query(answer);
451: }
452: #endif DEBUG
453: #endif
454: goto wait;
455: }
456: if (!(_res.options & RES_IGNTC) && anhp->tc) {
457: /*
458: * get rest of answer;
459: * use TCP with same server.
460: */
461: #ifdef DEBUG
462: if (_res.options & RES_DEBUG)
463: printf("truncated answer\n");
464: #endif DEBUG
465: (void) close(s);
466: s = -1;
467: v_circuit = 1;
468: goto usevc;
469: }
470: }
471: #if SR
472: if (_res.options & RES_DEBUG) {
473: if (_res.options & RES_DEBUG2)
474: printf("------------\nGot answer (%d bytes):\n",
475: resplen);
476: else
477: printf("------------\nGot answer:\n");
478: Print_query(answer, answer+resplen, 1);
479: }
480: (void) close(s);
481: s = -1;
482: *trueLenPtr = resplen;
483: return (SUCCESS);
484: #else
485: #ifdef DEBUG
486: if (_res.options & RES_DEBUG) {
487: printf("got answer:\n");
488: p_query(answer);
489: }
490: #endif DEBUG
491: /*
492: * If using virtual circuits, we assume that the first server
493: * is preferred * over the rest (i.e. it is on the local
494: * machine) and only keep that one open.
495: * If we have temporarily opened a virtual circuit,
496: * or if we haven't been asked to keep a socket open,
497: * close the socket.
498: */
499: if ((v_circuit &&
500: ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
501: (_res.options & RES_STAYOPEN) == 0) {
502: (void) close(s);
503: s = -1;
504: }
505: return (resplen);
506: }
507: #endif /* SR */
508: }
509: if (s >= 0) {
510: (void) close(s);
511: s = -1;
512: }
513: #if SR
514: if (v_circuit == 0)
515: if (gotsomewhere == 0)
516: return NO_RESPONSE; /* no nameservers found */
517: else
518: return TIME_OUT; /* no answer obtained */
519: else
520: if (errno == ECONNREFUSED)
521: return NO_RESPONSE;
522: else
523: return ERROR;
524: #else
525: if (v_circuit == 0)
526: if (gotsomewhere == 0)
527: errno = ECONNREFUSED; /* no nameservers found */
528: else
529: errno = ETIMEDOUT; /* no answer obtained */
530: else
531: errno = terrno;
532: return (-1);
533: #endif
534: }
535:
536: /*
537: * This routine is for closing the socket if a virtual circuit is used and
538: * the program wants to close it.
539: *
540: * Called from the interrupt handler.
541: */
542: SendRequest_close()
543: {
544: if (s != -1) {
545: (void) close(s);
546: s = -1;
547: }
548: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.