- use dig before gethostbyname to resolve host names
This commit is contained in:
119
ascon.c
119
ascon.c
@ -17,75 +17,62 @@
|
|||||||
static double lastClose = 0; /* time of last close operation */
|
static double lastClose = 0; /* time of last close operation */
|
||||||
static AsconProtocol *protocols = NULL;
|
static AsconProtocol *protocols = NULL;
|
||||||
|
|
||||||
long parse_dotted_adr(const char *dottedadr) {
|
static int MakeSocketAdr(
|
||||||
int ip[4];
|
struct sockaddr *sockaddrPtr, /* socket address */
|
||||||
int i;
|
char *hostname, /* name or ip of host. NULL implies INADDR_ANY */
|
||||||
|
int port, /* port number */
|
||||||
|
char dotted_ip[16]) { /* resolved ip adr */
|
||||||
|
/*
|
||||||
|
Workaround for the following case:
|
||||||
|
switching off and on a LakeShore 336 does acquire a new address,
|
||||||
|
but the value in the cache (for gethostbyname) is not updated.
|
||||||
|
node: dig seems to be recommended over nslookup
|
||||||
|
*/
|
||||||
|
|
||||||
if (sscanf(dottedadr, "%d.%d.%d.%d", ip, ip+1, ip+2, ip+3) != 4) return 0;
|
struct hostent *hostent; /* Host database entry */
|
||||||
for (i=0; i<3; i++) {
|
struct sockaddr_in *sadr = (struct sockaddr_in *)sockaddrPtr;
|
||||||
if (ip[i] < 0 || ip[i] > 255) return 0;
|
|
||||||
}
|
|
||||||
return ip[0] + (ip[1] << 8) + (ip[2] << 16) + (ip[3] << 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
long ns_lookup(char *hostname) {
|
|
||||||
FILE *fil;
|
FILE *fil;
|
||||||
char line[256];
|
char line[256];
|
||||||
long ipadr;
|
int l;
|
||||||
|
|
||||||
ipadr = parse_dotted_adr(hostname);
|
(void) memset(sadr, 0, sizeof(*sadr));
|
||||||
if (ipadr) return ipadr;
|
if (dotted_ip) { /* default value: failure */
|
||||||
snprintf(line, sizeof line, "timeout 1 nslookup %s", hostname);
|
dotted_ip[0] = 0;
|
||||||
|
}
|
||||||
|
sadr->sin_family = AF_INET;
|
||||||
|
sadr->sin_port = htons((unsigned short)port);
|
||||||
|
if (hostname == NULL) {
|
||||||
|
/* do not need to copy, as INADDR_ANY is all zero bytes */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (inet_pton(AF_INET, hostname, &sadr->sin_addr) == 1) {
|
||||||
|
/* resolved as dotted numbers notation */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
hostent = gethostbyname(hostname);
|
||||||
|
if (hostent == 0) {
|
||||||
|
/* we assume that when gethostname gets no entry, dig will also fail.
|
||||||
|
That way, dig will not be called repeatedly for no reason */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* copy the address: in case dig fails, we use the cached value */
|
||||||
|
memcpy(&sadr->sin_addr, hostent->h_addr_list[0], 4);
|
||||||
|
/* we use hostent->h_name instead of hostname here, as this has already
|
||||||
|
the proper domain added */
|
||||||
|
snprintf(line, sizeof line, "timeout 1 dig +short %s", hostent->h_name);
|
||||||
fil = popen(line, "r");
|
fil = popen(line, "r");
|
||||||
if (fil == NULL) {
|
if (fil != NULL) {
|
||||||
return 0;
|
if (fgets(line, sizeof(line), fil) != NULL) {
|
||||||
}
|
l = strlen(line);
|
||||||
while (fgets(line, sizeof(line), fil) != NULL) {
|
if (line[l-1] <= ' ') line[l-1] = 0; /* strip off newline */
|
||||||
if (strncmp(line, "Address: ", 9) == 0) {
|
/* silently ignore return value, if it fails, we take the cached value */
|
||||||
ipadr = parse_dotted_adr(line+9);
|
inet_pton(AF_INET, line, &sadr->sin_addr);
|
||||||
if (ipadr) {
|
|
||||||
fclose(fil);
|
|
||||||
return ipadr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fclose(fil);
|
fclose(fil);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Based on CreateSocketAdress from John Ousterhout
|
|
||||||
Use ns_lookup instead of gethostbyname, as the latter uses a cache, which
|
|
||||||
is not sufficient in some cases (switching off and on a LakeShore 336 does
|
|
||||||
acquire a new address, but the value in the cache is not updates)
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int MakeSocketAdress(struct sockaddr_in *sockaddrPtr, /* Socket address */
|
|
||||||
char *host, /* Host. NULL implies INADDR_ANY */
|
|
||||||
int port)
|
|
||||||
{ /* Port number */
|
|
||||||
struct hostent *hostent; /* Host database entry */
|
|
||||||
struct in_addr addr; /* For 64/32 bit madness */
|
|
||||||
|
|
||||||
(void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));
|
|
||||||
sockaddrPtr->sin_family = AF_INET;
|
|
||||||
sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF));
|
|
||||||
if (host == NULL) {
|
|
||||||
addr.s_addr = INADDR_ANY;
|
|
||||||
} else {
|
|
||||||
addr.s_addr = ns_lookup(host);
|
|
||||||
if (addr.s_addr == 0) { /* try gethostbyname only if ns_lookup failed */
|
|
||||||
hostent = gethostbyname(host);
|
|
||||||
if (hostent == NULL) return 0; /* error */
|
|
||||||
memcpy((char *) &addr,
|
|
||||||
(char *) hostent->h_addr_list[0], (size_t) hostent->h_length);
|
|
||||||
}
|
}
|
||||||
|
if (dotted_ip) {
|
||||||
|
inet_ntop(AF_INET, &sadr->sin_addr, dotted_ip, 16);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* There is a rumor that this assignment may require care on
|
|
||||||
* some 64 bit machines, we do not believe it.
|
|
||||||
*/
|
|
||||||
sockaddrPtr->sin_addr.s_addr = addr.s_addr;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +127,7 @@ static void AsconConnect(Ascon * a)
|
|||||||
/* input state: AsconConnectStart
|
/* input state: AsconConnectStart
|
||||||
output state: AsconFailed or AsconConnecting */
|
output state: AsconFailed or AsconConnecting */
|
||||||
int ret;
|
int ret;
|
||||||
struct sockaddr_in adr;
|
struct sockaddr adr;
|
||||||
char *colon;
|
char *colon;
|
||||||
int port;
|
int port;
|
||||||
int oldopts;
|
int oldopts;
|
||||||
@ -184,17 +171,15 @@ static void AsconConnect(Ascon * a)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*colon = '\0';
|
*colon = '\0';
|
||||||
ret = MakeSocketAdress(&adr, a->hostport, port);
|
ret = MakeSocketAdr(&adr, a->hostport, port, a->ip);
|
||||||
*colon = ':';
|
*colon = ':';
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
a->ip = 0;
|
|
||||||
AsconError(a, "bad host specification", 0);
|
AsconError(a, "bad host specification", 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
a->ip = adr.sin_addr.s_addr;
|
|
||||||
oldopts = fcntl(a->fd, F_GETFL, 0);
|
oldopts = fcntl(a->fd, F_GETFL, 0);
|
||||||
fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK);
|
fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK);
|
||||||
ret = connect(a->fd, (struct sockaddr *) &adr, sizeof(struct sockaddr_in));
|
ret = connect(a->fd, &adr, sizeof(struct sockaddr_in));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case EINPROGRESS:
|
case EINPROGRESS:
|
||||||
@ -891,10 +876,10 @@ char *AsconHostport(Ascon *a)
|
|||||||
return a->hostport;
|
return a->hostport;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long AsconIP(Ascon *a)
|
char *AsconIP(Ascon *a)
|
||||||
{
|
{
|
||||||
if (a==NULL) {
|
if (a==NULL) {
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
return a->ip;
|
return a->ip;
|
||||||
}
|
}
|
||||||
|
4
ascon.h
4
ascon.h
@ -112,9 +112,9 @@ char *AsconHostport(Ascon *a);
|
|||||||
/**
|
/**
|
||||||
* \brief return IP address
|
* \brief return IP address
|
||||||
* \param a The Ascon to query
|
* \param a The Ascon to query
|
||||||
* \return the IP address
|
* \return the IP address (dotted numbers)
|
||||||
*/
|
*/
|
||||||
unsigned long AsconIP(Ascon *a);
|
char *AsconIP(Ascon *a);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief set or get timeout
|
* \brief set or get timeout
|
||||||
|
2
ascon.i
2
ascon.i
@ -65,7 +65,7 @@ struct Ascon {
|
|||||||
char *sendTerminator; /**< terminator for sending messages */
|
char *sendTerminator; /**< terminator for sending messages */
|
||||||
char *replyTerminator; /**< (std) terminator list for reply. NULL is the special case CR, LF or CR/LF */
|
char *replyTerminator; /**< (std) terminator list for reply. NULL is the special case CR, LF or CR/LF */
|
||||||
char *hostport; /**< host:port to connect */
|
char *hostport; /**< host:port to connect */
|
||||||
in_addr_t ip; /**< the ip address */
|
char ip[16]; /**< the ip address (dotted numbers) */
|
||||||
pDynString errmsg; /**< error message */
|
pDynString errmsg; /**< error message */
|
||||||
double start; /**< unix time when read was started */
|
double start; /**< unix time when read was started */
|
||||||
int noResponse; /**< no response expected */
|
int noResponse; /**< no response expected */
|
||||||
|
2
devser.c
2
devser.c
@ -580,7 +580,7 @@ char *DevHostport(DevSer *devser) {
|
|||||||
return AsconHostport(devser->ascon);
|
return AsconHostport(devser->ascon);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long DevIP(DevSer *devser) {
|
char *DevIP(DevSer *devser) {
|
||||||
return AsconIP(devser->ascon);
|
return AsconIP(devser->ascon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
devser.h
4
devser.h
@ -206,9 +206,9 @@ char *DevHostport(DevSer *devser);
|
|||||||
/**
|
/**
|
||||||
* \brief return IP address
|
* \brief return IP address
|
||||||
* \param a The device serializer to query
|
* \param a The device serializer to query
|
||||||
* \return the IP address
|
* \return the IP address (dotted numbers)
|
||||||
*/
|
*/
|
||||||
unsigned long DevIP(DevSer *devser);
|
char *DevIP(DevSer *devser);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief return status of device server ("offline", "unconnected", "")
|
* \brief return status of device server ("offline", "unconnected", "")
|
||||||
|
@ -1742,15 +1742,9 @@ static int SctIpAddress(pSICSOBJ ccmd, SConnection * con,
|
|||||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||||
{
|
{
|
||||||
SctController *c;
|
SctController *c;
|
||||||
uint32_t ip;
|
|
||||||
|
|
||||||
c = (SctController *) ccmd->pPrivate;
|
c = (SctController *) ccmd->pPrivate;
|
||||||
ip = DevIP(c->devser);
|
SCPrintf(con, eValue, "%s", DevIP(c->devser));
|
||||||
SCPrintf(con, eValue, "%d.%d.%d.%d",
|
|
||||||
(int)(ip & 0xff),
|
|
||||||
(int)((ip >> 8) & 0xff),
|
|
||||||
(int)((ip >> 16) & 0xff),
|
|
||||||
(int)((ip >> 24) & 0xff));
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user