BSD 4_3_Net_1 release
[unix-history] / named / tools / nslookup / send.c
/*
* Copyright (c) 1985 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static char sccsid[] = "@(#)send.c 5.10 (Berkeley) 1/28/89";
#endif /* not lint */
/*
*******************************************************************************
*
* send.c --
*
* Routine to send request packets to a name server.
*
* Modified version of 4.3BSD BIND res_send.c 5.5 (Berkeley) 9/14/85
*
*******************************************************************************
*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include "res.h"
/*
* Initialize the socket address info struct.
*/
static struct sockaddr_in sin;
\f
/*
*******************************************************************************
*
* SendRequest --
*
* Sends a request packet to a name server whose address
* is specified by the first argument and returns with
* the answer packet.
*
* Results:
* SUCCESS - the request was sent and an answer
* was received.
* TIME_OUT - the virtual circuit connection timed-out
* or a reply to a datagram wasn't received.
*
*
*******************************************************************************
*/
int
SendRequest(nsAddrPtr, buf, buflen, answer, anslen, trueLenPtr)
struct in_addr *nsAddrPtr;
char *buf;
int buflen;
char *answer;
int anslen;
int *trueLenPtr;
{
struct timeval timeout;
register int n;
u_short packetId, len;
short length;
char *cp;
int retry, v_circuit, resplen;
int dsmask;
int numTimeOuts = 0;
HEADER *requestPtr = (HEADER *) buf;
HEADER *answerPtr = (HEADER *) answer;
if (_res.options & RES_DEBUG2) {
printf("------------\nSendRequest(), len %d\n", buflen);
Print_query(buf, buf+buflen, 1);
}
sockFD = -1;
/*
* See if a virtual circuit is required or desired.
*/
v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
packetId = requestPtr->id;
sin.sin_family = AF_INET;
sin.sin_port = htons(NAMESERVER_PORT);
sin.sin_addr = *nsAddrPtr;
/*
* Send request, RETRY times, or until successful
*/
for (retry = _res.retry; --retry >= 0; ) {
if (v_circuit) {
/*
* Use virtual circuit.
*/
if (sockFD < 0)
sockFD = socket(AF_INET, SOCK_STREAM, 0);
if (connect(sockFD, &sin, sizeof(sin)) < 0) {
if (_res.options & RES_DEBUG) {
perror("SendRequest");
}
(void) close(sockFD);
sockFD = -1;
continue;
}
/*
* Send length & message
*/
len = htons(buflen);
if (write(sockFD, &len, sizeof(len)) != sizeof(len) ||
write(sockFD, buf, buflen) != buflen) {
if (_res.options & RES_DEBUG) {
perror("SendRequest");
}
(void) close(sockFD);
sockFD = -1;
continue;
}
/*
* Receive length & response
*/
cp = answer;
length = sizeof(short);
while(length > 0 && (n = read(sockFD, cp, length)) > 0){
cp += n;
length -= n;
}
if (n <= 0) {
if (_res.options & RES_DEBUG) {
perror("SendRequest");
}
(void) close(sockFD);
sockFD = -1;
continue;
}
cp = answer;
resplen = length = ntohs(*(short *)cp);
while(length > 0 && (n = read(sockFD, cp, length)) > 0){
cp += n;
length -= n;
}
if (n <= 0) {
if (_res.options & RES_DEBUG) {
perror("SendRequest");
}
(void) close(sockFD);
sockFD = -1;
continue;
}
} else {
/*
* Use datagrams.
*/
if (sockFD < 0)
sockFD = socket(AF_INET, SOCK_DGRAM, 0);
if (sendto(sockFD, buf, buflen, 0, &sin,
sizeof(sin)) != buflen) {
perror("SendRequest: sendto");
continue;
}
/*
* Wait for reply
*/
timeout.tv_sec = _res.retrans;
timeout.tv_usec = 0;
dsmask = 1 << sockFD;
n = select(sockFD+1, &dsmask, 0, 0, &timeout);
if (n < 0) {
if (_res.options & RES_DEBUG) {
perror("SendRequest: select");
}
continue;
}
if (n == 0) {
/*
* timeout
*/
if (_res.options & RES_DEBUG) {
printf("Timeout %d\n", ++numTimeOuts);
}
continue;
}
if ((resplen = recv(sockFD, answer, anslen, 0)) <= 0) {
if (_res.options & RES_DEBUG) {
perror("SendRequest: recv");
}
continue;
}
if (packetId != answerPtr->id) {
/*
* response from old query, ignore it
*/
if (_res.options & RES_DEBUG2) {
printf("------------\nOld answer:\n");
Print_query(answer, answer+resplen, 1);
}
continue;
}
if (!(_res.options & RES_IGNTC) && answerPtr->tc) {
/*
* get rest of answer
*/
if (_res.options & RES_DEBUG) {
printf("truncated answer\n");
}
(void) close(sockFD);
sockFD = -1;
retry = _res.retry;
v_circuit = 1;
continue;
}
}
if (_res.options & RES_DEBUG) {
if (_res.options & RES_DEBUG2)
printf("------------\nGot answer (%d bytes):\n",
resplen);
else
printf("------------\nGot answer:\n");
Print_query(answer, answer+resplen, 1);
}
(void) close(sockFD);
sockFD = -1;
*trueLenPtr = resplen;
return (SUCCESS);
}
(void) close(sockFD);
sockFD = -1;
return (TIME_OUT);
}