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