updated to support new BSD network interface query API
This commit is contained in:
@@ -34,7 +34,6 @@
|
||||
* (and not N-1 interfaces)
|
||||
*/
|
||||
|
||||
|
||||
static char *sccsId = "@(#) $Id$";
|
||||
|
||||
#include "iocinf.h"
|
||||
@@ -45,263 +44,261 @@ static char *sccsId = "@(#) $Id$";
|
||||
* a higher level.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
# define ifDepenDebugPrintf(argsInParen) printf argsInParen
|
||||
#else
|
||||
# define ifDepenDebugPrintf(argsInParen)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* local_addr()
|
||||
*
|
||||
* A valid non-loopback local address is required in the
|
||||
* beacon message in certain situations where
|
||||
* there are beacon repeaters and there are addresses
|
||||
* in the EPICS_CA_ADDRESS_LIST for which we dont have
|
||||
* a strictly correct local server address on a multi-interface
|
||||
* system. In this situation we use the first valid non-loopback local
|
||||
* address found in the beacon message.
|
||||
* Move to the next ifreq structure
|
||||
* Made difficult by the fact that addresses larger than the structure
|
||||
* size may be returned from the kernel.
|
||||
*/
|
||||
int local_addr(int s, struct sockaddr_in *plcladdr)
|
||||
static struct ifreq * ifreqNext (struct ifreq *pifreq)
|
||||
{
|
||||
int status;
|
||||
struct ifconf ifconf;
|
||||
struct ifreq ifreq[25];
|
||||
struct ifreq *pifreq;
|
||||
static struct sockaddr_in addr;
|
||||
static char init = FALSE;
|
||||
struct sockaddr_in *tmpaddr;
|
||||
unsigned int size;
|
||||
|
||||
if (init){
|
||||
*plcladdr = addr;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* get the addr of the first interface found
|
||||
* (report inconsistent interfaces however)
|
||||
*/
|
||||
ifconf.ifc_len = sizeof ifreq;
|
||||
ifconf.ifc_req = ifreq;
|
||||
status = socket_ioctl(s, SIOCGIFCONF, &ifconf);
|
||||
if (status < 0 || ifconf.ifc_len == 0) {
|
||||
ca_printf(
|
||||
"CAC: SIOCGIFCONF ioctl failed because \"%s\"\n",
|
||||
SOCKERRSTR);
|
||||
ifconf.ifc_len = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
ca_printf("CAC: %d net intf found\n", ifconf.ifc_len/sizeof(*pifreq));
|
||||
#if ( defined (BSD) && ( BSD >= 44 ) ) || defined ( SOCKADDR_HAS_LEN )
|
||||
size = pifreq->ifr_addr.sa_len + sizeof(pifreq->ifr_name);
|
||||
if (size < sizeof(*pifreq))
|
||||
size = sizeof(*pifreq);
|
||||
#else
|
||||
size = sizeof(*pifreq);
|
||||
#endif
|
||||
|
||||
for ( pifreq = ifconf.ifc_req;
|
||||
((size_t)ifconf.ifc_len) >= sizeof(*pifreq);
|
||||
pifreq++, ifconf.ifc_len -= sizeof(*pifreq)) {
|
||||
|
||||
status = socket_ioctl(s, SIOCGIFFLAGS, pifreq);
|
||||
if (status == ERROR){
|
||||
ca_printf("CAC: net intf flags fetch for %s failed\n", pifreq->ifr_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(pifreq->ifr_flags & IFF_UP)) {
|
||||
#ifdef DEBUG
|
||||
ca_printf("CAC: net intf %s was down\n", pifreq->ifr_name);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
ca_printf("CAC: net intf %s found\n", pifreq->ifr_name);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* dont use the loop back interface
|
||||
*/
|
||||
if (pifreq->ifr_flags & IFF_LOOPBACK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
status = socket_ioctl(s, SIOCGIFADDR, pifreq);
|
||||
if (status == ERROR){
|
||||
#ifdef DEBUG
|
||||
ca_printf("CAC: could not obtain addr for %s\n", pifreq->ifr_name);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pifreq->ifr_addr.sa_family != AF_INET){
|
||||
#ifdef DEBUG
|
||||
ca_printf("CAC: interface %s was not AF_INET\n", pifreq->ifr_name);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
tmpaddr = (struct sockaddr_in *) &pifreq->ifr_addr;
|
||||
|
||||
init = TRUE;
|
||||
addr = *tmpaddr;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!init){
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
*plcladdr = addr;
|
||||
return OK;
|
||||
return (struct ifreq *)(size + (char *)pifreq);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* caDiscoverInterfaces()
|
||||
*
|
||||
* This routine is provided with the address of an ELLLIST, a socket
|
||||
* a destination port number, and a match address. When the
|
||||
* routine returns there will be one additional inet address
|
||||
* (a caAddrNode) in the list for each inet interface found that
|
||||
* is up and isnt a loop back interface (match addr is INADDR_ANY)
|
||||
* or it matches the specified interface (match addr isnt INADDR_ANY).
|
||||
* If the interface supports broadcast then I add its broadcast
|
||||
* address to the list. If the interface is a point to
|
||||
* point link then I add the destination address of the point to
|
||||
* point link to the list. In either case I set the port number
|
||||
* in the address node to the port supplied in the argument
|
||||
* list.
|
||||
*
|
||||
* LOCK should be applied here for (pList)
|
||||
* (this is also called from the server)
|
||||
* caDiscoverInterfaces ()
|
||||
*/
|
||||
void epicsShareAPI caDiscoverInterfaces
|
||||
(ELLLIST *pList, int socket, unsigned short port, struct in_addr matchAddr)
|
||||
epicsShareFunc void epicsShareAPI caDiscoverInterfaces
|
||||
(ELLLIST *pList, SOCKET socket, unsigned short port, struct in_addr matchAddr)
|
||||
{
|
||||
struct sockaddr_in localAddr;
|
||||
struct sockaddr_in *pInetAddr;
|
||||
caAddrNode *pNode;
|
||||
int status;
|
||||
struct ifconf ifconf;
|
||||
struct ifreq *pIfreqList;
|
||||
struct ifreq *pifreq;
|
||||
unsigned nelem;
|
||||
static const unsigned nelem = 100;
|
||||
int status;
|
||||
struct ifconf ifconf;
|
||||
struct ifreq *pIfreqList;
|
||||
struct ifreq *pIfreqListEnd;
|
||||
struct ifreq *pifreq;
|
||||
struct ifreq *pnextifreq;
|
||||
caAddrNode *pNewNode;
|
||||
|
||||
/*
|
||||
* use pool so that we avoid using too much stack space
|
||||
*
|
||||
* nelem is set to the maximum interfaces
|
||||
* on one machine here
|
||||
*/
|
||||
pIfreqList = (struct ifreq *) calloc ( nelem, sizeof(*pifreq) );
|
||||
if (!pIfreqList) {
|
||||
errlogPrintf ("osiSockDiscoverInterfaces(): no memory to complete request\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ifconf.ifc_len = nelem * sizeof(*pifreq);
|
||||
ifconf.ifc_req = pIfreqList;
|
||||
status = socket_ioctl (socket, SIOCGIFCONF, &ifconf);
|
||||
if (status < 0 || ifconf.ifc_len == 0) {
|
||||
errlogPrintf ("osiSockDiscoverInterfaces(): unable to fetch network interface configuration\n");
|
||||
free (pIfreqList);
|
||||
return;
|
||||
}
|
||||
|
||||
pIfreqListEnd = (struct ifreq *) (ifconf.ifc_len + (char *) pIfreqList);
|
||||
pIfreqListEnd--;
|
||||
|
||||
/*
|
||||
* use pool so that we avoid using to much stack space
|
||||
* under vxWorks
|
||||
*
|
||||
* nelem is set to the maximum interfaces
|
||||
* on one machine here
|
||||
*/
|
||||
nelem = 100;
|
||||
pIfreqList = (struct ifreq *)calloc(nelem, sizeof(*pifreq));
|
||||
if(!pIfreqList){
|
||||
return;
|
||||
}
|
||||
for ( pifreq = pIfreqList; pifreq <= pIfreqListEnd; pifreq = pnextifreq ) {
|
||||
|
||||
ifconf.ifc_len = nelem*sizeof(*pifreq);
|
||||
ifconf.ifc_req = pIfreqList;
|
||||
status = socket_ioctl(socket, SIOCGIFCONF, &ifconf);
|
||||
if (status < 0 || ifconf.ifc_len == 0) {
|
||||
free(pIfreqList);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* find the next if req
|
||||
*/
|
||||
pnextifreq = ifreqNext (pifreq);
|
||||
|
||||
nelem = ifconf.ifc_len/sizeof(struct ifreq);
|
||||
for (pifreq = pIfreqList; pifreq<(pIfreqList+nelem); pifreq++){
|
||||
status = socket_ioctl(socket, SIOCGIFFLAGS, pifreq);
|
||||
if (status){
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* If its not an internet interface then dont use it
|
||||
*/
|
||||
if ( pifreq->ifr_addr.sa_family != AF_INET ) {
|
||||
ifDepenDebugPrintf ( ("osiSockDiscoverInterfaces(): interface \"%s\" was not AF_INET\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* dont bother with interfaces that have been disabled
|
||||
*/
|
||||
if (!(pifreq->ifr_flags & IFF_UP)) {
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* if it isnt a wildcarded interface then look for
|
||||
* an exact match
|
||||
*/
|
||||
if ( matchAddr.s_addr != htonl (INADDR_ANY) ) {
|
||||
struct sockaddr_in *pInetAddr = (struct sockaddr_in *) &pifreq->ifr_addr;
|
||||
if ( pInetAddr->sin_addr.s_addr != matchAddr.s_addr ) {
|
||||
ifDepenDebugPrintf ( ("osiSockDiscoverInterfaces(): net intf \"%s\" didnt match\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dont use the loop back interface
|
||||
*/
|
||||
if (pifreq->ifr_flags & IFF_LOOPBACK) {
|
||||
continue;
|
||||
}
|
||||
status = socket_ioctl ( socket, SIOCGIFFLAGS, pifreq );
|
||||
if ( status ) {
|
||||
errlogPrintf ("osiSockDiscoverInterfaces(): net intf flags fetch for \"%s\" failed\n", pifreq->ifr_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* dont bother with interfaces that have been disabled
|
||||
*/
|
||||
if ( ! ( pifreq->ifr_flags & IFF_UP ) ) {
|
||||
ifDepenDebugPrintf ( ("osiSockDiscoverInterfaces(): net intf \"%s\" was down\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch the local address for this interface
|
||||
*/
|
||||
status = socket_ioctl(socket, SIOCGIFADDR, pifreq);
|
||||
if (status){
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* dont use the loop back interface
|
||||
*/
|
||||
if ( pifreq->ifr_flags & IFF_LOOPBACK ) {
|
||||
ifDepenDebugPrintf ( ("osiSockDiscoverInterfaces(): ignoring loopback interface: \"%s\"\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If its not an internet inteface
|
||||
* then dont use it.
|
||||
*/
|
||||
if (pifreq->ifr_addr.sa_family != AF_INET) {
|
||||
continue;
|
||||
}
|
||||
pNewNode = (caAddrNode *) calloc (1, sizeof (*pNewNode) );
|
||||
if ( pNewNode == NULL ) {
|
||||
errlogPrintf ( "osiSockDiscoverInterfaces(): no memory available for configuration\n" );
|
||||
free ( pIfreqList );
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* save the interface's IP address
|
||||
*/
|
||||
pInetAddr = (struct sockaddr_in *)&pifreq->ifr_addr;
|
||||
localAddr = *pInetAddr;
|
||||
/*
|
||||
* If this is an interface that supports
|
||||
* broadcast fetch the broadcast address.
|
||||
*
|
||||
* Otherwise if this is a point to point
|
||||
* interface then use the destination address.
|
||||
*
|
||||
* Otherwise CA will not query through the
|
||||
* interface.
|
||||
*/
|
||||
if ( pifreq->ifr_flags & IFF_BROADCAST ) {
|
||||
status = socket_ioctl (socket, SIOCGIFBRDADDR, pifreq);
|
||||
if ( status ) {
|
||||
errlogPrintf ("osiSockDiscoverInterfaces(): net intf \"%s\": bcast addr fetch fail\n", pifreq->ifr_name);
|
||||
free ( pNewNode );
|
||||
continue;
|
||||
}
|
||||
pNewNode->destAddr.sa = pifreq->ifr_broadaddr;
|
||||
}
|
||||
else if ( pifreq->ifr_flags & IFF_POINTOPOINT ) {
|
||||
status = socket_ioctl ( socket, SIOCGIFDSTADDR, pifreq);
|
||||
if ( status ) {
|
||||
ifDepenDebugPrintf ( ("osiSockDiscoverInterfaces(): net intf \"%s\": pt to pt addr fetch fail\n", pifreq->ifr_name) );
|
||||
free ( pNewNode );
|
||||
continue;
|
||||
}
|
||||
pNewNode->destAddr.sa = pifreq->ifr_dstaddr;
|
||||
}
|
||||
else {
|
||||
errlogPrintf ( "osiSockDiscoverInterfaces(): net intf \"%s\": not pt to pt or bcast?\n", pifreq->ifr_name );
|
||||
free ( pNewNode );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* if it isnt a wildcarded interface then look for
|
||||
* an exact match
|
||||
*/
|
||||
if (matchAddr.s_addr != htonl(INADDR_ANY)) {
|
||||
if (pInetAddr->sin_addr.s_addr != matchAddr.s_addr) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ( pNewNode->destAddr.sa.sa_family == AF_INET ) {
|
||||
pNewNode->destAddr.in.sin_port = htons ( port );
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is an interface that supports
|
||||
* broadcast fetch the broadcast address.
|
||||
*
|
||||
* Otherwise if this is a point to point
|
||||
* interface then use the destination address.
|
||||
*
|
||||
* Otherwise CA will not query through the
|
||||
* interface.
|
||||
*/
|
||||
if (pifreq->ifr_flags & IFF_BROADCAST) {
|
||||
status = socket_ioctl(
|
||||
socket,
|
||||
SIOCGIFBRDADDR,
|
||||
pifreq);
|
||||
if (status){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if(pifreq->ifr_flags & IFF_POINTOPOINT){
|
||||
status = socket_ioctl(
|
||||
socket,
|
||||
SIOCGIFDSTADDR,
|
||||
pifreq);
|
||||
if (status){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else{
|
||||
continue;
|
||||
}
|
||||
|
||||
pNode = (caAddrNode *) calloc(1,sizeof(*pNode));
|
||||
if(!pNode){
|
||||
continue;
|
||||
}
|
||||
|
||||
pNode->destAddr.in = *pInetAddr;
|
||||
pNode->destAddr.in.sin_port = htons(port);
|
||||
pNode->srcAddr.in = localAddr;
|
||||
ifDepenDebugPrintf ( ("osiSockDiscoverInterfaces(): net intf \"%s\" found\n", pifreq->ifr_name) );
|
||||
|
||||
/*
|
||||
* LOCK applied externally
|
||||
*/
|
||||
ellAdd(pList, &pNode->node);
|
||||
}
|
||||
ellAdd ( pList, &pNewNode->node );
|
||||
}
|
||||
|
||||
free(pIfreqList);
|
||||
free ( pIfreqList );
|
||||
}
|
||||
|
||||
/*
|
||||
* osiLocalAddr ()
|
||||
*/
|
||||
int local_addr (SOCKET socket, struct sockaddr_in *plcladdr)
|
||||
{
|
||||
static const unsigned nelem = 100;
|
||||
static char init = 0;
|
||||
static caAddr addr;
|
||||
int status;
|
||||
struct ifconf ifconf;
|
||||
struct ifreq *pIfreqList;
|
||||
struct ifreq *pifreq;
|
||||
struct ifreq *pIfreqListEnd;
|
||||
struct ifreq *pnextifreq;
|
||||
|
||||
if ( init ) {
|
||||
*plcladdr = addr.in;
|
||||
return OK;
|
||||
}
|
||||
|
||||
memset ( (void *) &addr, '\0', sizeof ( addr ) );
|
||||
addr.in.sin_family = AF_UNSPEC;
|
||||
|
||||
pIfreqList = (struct ifreq *) calloc ( nelem, sizeof(*pIfreqList) );
|
||||
if ( ! pIfreqList ) {
|
||||
errlogPrintf ( "osiLocalAddr(): no memory to complete request\n" );
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ifconf.ifc_len = nelem * sizeof ( *pIfreqList );
|
||||
ifconf.ifc_req = pIfreqList;
|
||||
status = socket_ioctl ( socket, SIOCGIFCONF, &ifconf );
|
||||
if ( status < 0 || ifconf.ifc_len == 0 ) {
|
||||
errlogPrintf (
|
||||
"CAC: SIOCGIFCONF ioctl failed because %d\n",
|
||||
SOCKERRNO );
|
||||
free ( pIfreqList );
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
pIfreqListEnd = (struct ifreq *) ( ifconf.ifc_len + (char *) ifconf.ifc_req );
|
||||
pIfreqListEnd--;
|
||||
|
||||
for ( pifreq = ifconf.ifc_req; pifreq <= pIfreqListEnd; pifreq = pnextifreq ) {
|
||||
caAddr addrCpy;
|
||||
|
||||
/*
|
||||
* find the next if req
|
||||
*/
|
||||
pnextifreq = ifreqNext ( pifreq );
|
||||
|
||||
if ( pifreq->ifr_addr.sa_family != AF_INET ) {
|
||||
ifDepenDebugPrintf ( ("local_addr: interface %s was not AF_INET\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
addrCpy.sa = pifreq->ifr_addr;
|
||||
|
||||
status = socket_ioctl ( socket, SIOCGIFFLAGS, pifreq );
|
||||
if ( status < 0 ) {
|
||||
errlogPrintf ( "local_addr: net intf flags fetch for %s failed\n", pifreq->ifr_name );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! ( pifreq->ifr_flags & IFF_UP ) ) {
|
||||
ifDepenDebugPrintf ( ("local_addr: net intf %s was down\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* dont use the loop back interface
|
||||
*/
|
||||
if ( pifreq->ifr_flags & IFF_LOOPBACK ) {
|
||||
ifDepenDebugPrintf ( ("local_addr: ignoring loopback interface: %s\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
ifDepenDebugPrintf ( ("local_addr: net intf %s found\n", pifreq->ifr_name) );
|
||||
|
||||
init = 1;
|
||||
addr = addrCpy;
|
||||
break;
|
||||
}
|
||||
|
||||
free ( pIfreqList );
|
||||
|
||||
*plcladdr = addr.in;
|
||||
return OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user