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