From 568ece9c2758f67e4d2ef206ceb3ab4956f92bd9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 11 Jan 2016 20:59:08 -0500 Subject: [PATCH] rsrv: multicast name lookup --- src/ioc/rsrv/caservertask.c | 82 ++++++++++++++++++++++++++++++++----- src/ioc/rsrv/server.h | 2 +- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/ioc/rsrv/caservertask.c b/src/ioc/rsrv/caservertask.c index c901f47fd..2371fcd09 100644 --- a/src/ioc/rsrv/caservertask.c +++ b/src/ioc/rsrv/caservertask.c @@ -268,7 +268,7 @@ SOCKET* rsrv_grap_tcp(unsigned short *port) } if(ellCount(&casIntfAddrList)==0) - cantProceed("RSRV has empty interface list"); + cantProceed("RSRV has empty interface list\n"); return socks; } @@ -290,6 +290,7 @@ void rsrv_build_addr_lists(void) ellInit ( &casIntfAddrList ); ellInit ( &beaconAddrList ); + ellInit ( &casMCastAddrList ); { ELLLIST temp = ELLLIST_INIT; @@ -301,16 +302,7 @@ void rsrv_build_addr_lists(void) removeDuplicateAddresses(&casIntfAddrList, &temp, 0); } - if (ellCount(&casIntfAddrList) == 0) { - /* default to wildcard 0.0.0.0 */ - osiSockAddrNode *pNode = (osiSockAddrNode *) callocMustSucceed( 1, sizeof(*pNode), "rsrv_init" ); - pNode->addr.ia.sin_family = AF_INET; - pNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); - pNode->addr.ia.sin_port = 0; - ellAdd ( &casIntfAddrList, &pNode->node ); - expandbcast = 1; - - } else { + { /* check user provided list */ osiSockAddrNode *pNode, *pNext; for(pNode = (osiSockAddrNode*)ellFirst(&casIntfAddrList), @@ -319,6 +311,8 @@ void rsrv_build_addr_lists(void) pNode = pNext, pNext = pNext ? (osiSockAddrNode*)ellNext(&pNext->node) : NULL) { + epicsUInt32 top = ntohl(pNode->addr.ia.sin_addr.s_addr)>>24; + if(pNode->addr.ia.sin_family==AF_INET && pNode->addr.ia.sin_addr.s_addr==htonl(INADDR_ANY)) { if (ellCount(&casIntfAddrList) != 1) { @@ -328,10 +322,25 @@ void rsrv_build_addr_lists(void) } else { expandbcast = 1; } + + } else if(pNode->addr.ia.sin_family==AF_INET && top>=224 && top<=239) { + /* This is a multi-cast address */ + ellDelete(&casIntfAddrList, &pNode->node); + ellAdd(&casMCastAddrList, &pNode->node); } } } + if (ellCount(&casIntfAddrList) == 0) { + /* default to wildcard 0.0.0.0 */ + osiSockAddrNode *pNode = (osiSockAddrNode *) callocMustSucceed( 1, sizeof(*pNode), "rsrv_init" ); + pNode->addr.ia.sin_family = AF_INET; + pNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); + pNode->addr.ia.sin_port = 0; + ellAdd ( &casIntfAddrList, &pNode->node ); + expandbcast = 1; + } + addAddrToChannelAccessAddressList ( &beaconAddrList, &EPICS_CAS_BEACON_ADDR_LIST, ca_beacon_port, 0 ); @@ -518,6 +527,7 @@ int rsrv_init (void) /* start servers (TCP and UDP(s) for each interface. */ { + int havesometcp = 0; ELLNODE *cur; int i; @@ -551,6 +561,43 @@ int rsrv_init (void) if(tryBind(conf->udp, &conf->udpAddr, "UDP unicast socket")) goto cleanup; +#ifdef IP_ADD_MEMBERSHIP + /* join UDP socket to any multicast groups */ + { + osiSockAddrNode *pNode; + + for(pNode = (osiSockAddrNode*)ellFirst(&casMCastAddrList); + pNode; + pNode = (osiSockAddrNode*)ellNext(&pNode->node)) + { + struct ip_mreq mreq; + + memset(&mreq, 0, sizeof(mreq)); + mreq.imr_multiaddr = pNode->addr.ia.sin_addr; + mreq.imr_interface.s_addr = conf->udpAddr.ia.sin_addr.s_addr; + + if(setsockopt(conf->udp, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))!=0) + { + struct sockaddr_in temp; + char name[40]; + char sockErrBuf[64]; + temp.sin_family = AF_INET; + temp.sin_addr = mreq.imr_multiaddr; + temp.sin_port = conf->udpAddr.ia.sin_port; + epicsSocketConvertErrnoToString ( + sockErrBuf, sizeof ( sockErrBuf ) ); + ipAddrToDottedIP (&temp, name, sizeof(name)); + fprintf(stderr, "CAS: Socket mcast join %s to %s failed with \"%s\"\n", + ifaceName, name, sockErrBuf ); + } + } + } +#else + if(ellCount(&casMCastAddrList)){ + fprintf(stderr, "IPv4 Multicast name lookup not supported by this target\n"); + } +#endif + #if !defined(_WIN32) /* An oddness of BSD sockets (not winsock) is that binding to * INADDR_ANY will receive unicast and broadcast, but binding to @@ -623,6 +670,7 @@ int rsrv_init (void) } #endif /* !defined(_WIN32) */ + havesometcp = 1; continue; cleanup: epicsSocketDestroy(conf->tcp); @@ -630,6 +678,9 @@ int rsrv_init (void) if(conf->udpbcast!=INVALID_SOCKET) epicsSocketDestroy(conf->udpbcast); free(conf); } + + if(!havesometcp) + cantProceed("CAS: No TCP server started\n"); } /* servers list is considered read-only from this point */ @@ -830,6 +881,15 @@ void casr (unsigned level) UNLOCK_CLIENTQ if (level>=2) { osiSockAddrNode * pAddr; + for(pAddr = (osiSockAddrNode*)ellFirst(&casMCastAddrList); + pAddr; + pAddr = (osiSockAddrNode*)ellNext(&pAddr->node)) + { + char buf[40]; + + ipAddrToDottedIP (&pAddr->addr.ia, buf, sizeof(buf)); + printf("MCast destination %s\n", buf); + } for(pAddr = (osiSockAddrNode*)ellFirst(&beaconAddrList); pAddr; pAddr = (osiSockAddrNode*)ellNext(&pAddr->node)) diff --git a/src/ioc/rsrv/server.h b/src/ioc/rsrv/server.h index 5162cc103..239edac95 100644 --- a/src/ioc/rsrv/server.h +++ b/src/ioc/rsrv/server.h @@ -176,7 +176,7 @@ GLBLTYPE ELLLIST clientQudp; /* locked by clientQlock */ GLBLTYPE ELLLIST servers; /* rsrv_iface_config::node, read-only after rsrv_init() */ GLBLTYPE ELLLIST beaconAddrList; GLBLTYPE SOCKET beaconSocket; -GLBLTYPE ELLLIST casIntfAddrList; +GLBLTYPE ELLLIST casIntfAddrList, casMCastAddrList; GLBLTYPE epicsMutexId clientQlock; GLBLTYPE BUCKET *pCaBucket; /* locked by clientQlock */ GLBLTYPE void *rsrvClientFreeList;