udp transport initialization refactoring (deduplication)
This commit is contained in:
@@ -491,6 +491,20 @@ namespace epics {
|
||||
|
||||
};
|
||||
|
||||
typedef std::vector<BlockingUDPTransport::shared_pointer> BlockingUDPTransportVector;
|
||||
|
||||
epicsShareExtern void initializeUDPTransports(
|
||||
bool serverFlag,
|
||||
BlockingUDPTransportVector& udpTransports,
|
||||
const IfaceNodeVector& ifaceList,
|
||||
const ResponseHandler::shared_pointer& responseHandler,
|
||||
BlockingUDPTransport::shared_pointer& sendTransport,
|
||||
epics::pvData::int32& listenPort,
|
||||
bool autoAddressList,
|
||||
const std::string& addressList,
|
||||
const std::string& ignoreAddressList);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -357,36 +357,40 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so
|
||||
|
||||
// CMD_ORIGIN_TAG filtering
|
||||
// NOTE: from design point of view this is not a right place to process application message here
|
||||
if (unlikely((command == CMD_ORIGIN_TAG) && _tappedNIF))
|
||||
if (unlikely(command == CMD_ORIGIN_TAG))
|
||||
{
|
||||
// 128-bit IPv6 address
|
||||
osiSockAddr originNIFAddress;
|
||||
if (decodeAsIPv6Address(receiveBuffer, &originNIFAddress))
|
||||
// enabled?
|
||||
if (_tappedNIF)
|
||||
{
|
||||
originNIFAddress.ia.sin_family = AF_INET;
|
||||
|
||||
/*
|
||||
LOG(logLevelDebug, "Got CMD_ORIGIN_TAG message form %s tagged as %s.",
|
||||
inetAddressToString(fromAddress, true).c_str(),
|
||||
inetAddressToString(originNIFAddress, false).c_str());
|
||||
*/
|
||||
|
||||
// filter
|
||||
if (originNIFAddress.ia.sin_addr.s_addr != htonl(INADDR_ANY))
|
||||
// 128-bit IPv6 address
|
||||
osiSockAddr originNIFAddress;
|
||||
if (decodeAsIPv6Address(receiveBuffer, &originNIFAddress))
|
||||
{
|
||||
bool accept = false;
|
||||
for(size_t i = 0; i < _tappedNIF->size(); i++)
|
||||
{
|
||||
if((*_tappedNIF)[i].ia.sin_addr.s_addr == originNIFAddress.ia.sin_addr.s_addr)
|
||||
{
|
||||
accept = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
originNIFAddress.ia.sin_family = AF_INET;
|
||||
|
||||
// ignore messages from non-tapped NIFs
|
||||
if (!accept)
|
||||
return false;
|
||||
/*
|
||||
LOG(logLevelDebug, "Got CMD_ORIGIN_TAG message form %s tagged as %s.",
|
||||
inetAddressToString(fromAddress, true).c_str(),
|
||||
inetAddressToString(originNIFAddress, false).c_str());
|
||||
*/
|
||||
|
||||
// filter
|
||||
if (originNIFAddress.ia.sin_addr.s_addr != htonl(INADDR_ANY))
|
||||
{
|
||||
bool accept = false;
|
||||
for(size_t i = 0; i < _tappedNIF->size(); i++)
|
||||
{
|
||||
if((*_tappedNIF)[i].ia.sin_addr.s_addr == originNIFAddress.ia.sin_addr.s_addr)
|
||||
{
|
||||
accept = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ignore messages from non-tapped NIFs
|
||||
if (!accept)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -408,6 +412,12 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so
|
||||
|
||||
bool BlockingUDPTransport::send(const char* buffer, size_t length, const osiSockAddr& address)
|
||||
{
|
||||
if (IS_LOGGABLE(logLevelDebug))
|
||||
{
|
||||
LOG(logLevelDebug, "Sending %d bytes to %s.",
|
||||
length, inetAddressToString(address).c_str());
|
||||
}
|
||||
|
||||
int retval = sendto(_channel, buffer,
|
||||
length, 0, &(address.sa), sizeof(sockaddr));
|
||||
if(unlikely(retval<0))
|
||||
@@ -425,6 +435,13 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so
|
||||
bool BlockingUDPTransport::send(ByteBuffer* buffer, const osiSockAddr& address) {
|
||||
|
||||
buffer->flip();
|
||||
|
||||
if (IS_LOGGABLE(logLevelDebug))
|
||||
{
|
||||
LOG(logLevelDebug, "Sending %d bytes to %s.",
|
||||
buffer->getRemaining(), inetAddressToString(address).c_str());
|
||||
}
|
||||
|
||||
int retval = sendto(_channel, buffer->getArray(),
|
||||
buffer->getLimit(), 0, &(address.sa), sizeof(sockaddr));
|
||||
if(unlikely(retval<0))
|
||||
@@ -552,6 +569,241 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so
|
||||
|
||||
}
|
||||
|
||||
void initializeUDPTransports(bool serverFlag,
|
||||
BlockingUDPTransportVector& udpTransports,
|
||||
const IfaceNodeVector& ifaceList,
|
||||
const ResponseHandler::shared_pointer& responseHandler,
|
||||
BlockingUDPTransport::shared_pointer& sendTransport,
|
||||
int32& listenPort,
|
||||
bool autoAddressList,
|
||||
const std::string& addressList,
|
||||
const std::string& ignoreAddressList)
|
||||
{
|
||||
TransportClient::shared_pointer nullTransportClient;
|
||||
auto_ptr<BlockingUDPConnector> connector(new BlockingUDPConnector(serverFlag, true, true));
|
||||
|
||||
// TODO configurable local NIF, address
|
||||
osiSockAddr loAddr;
|
||||
getLoopbackNIF(loAddr, "", 0);
|
||||
|
||||
// TODO configurable local multicast address
|
||||
std::string mcastAddress("224.0.0.128");
|
||||
|
||||
osiSockAddr group;
|
||||
aToIPAddr(mcastAddress.c_str(), listenPort, &group.ia);
|
||||
|
||||
//
|
||||
// set ignore address list
|
||||
//
|
||||
auto_ptr<InetAddrVector> ignoreAddressVector;
|
||||
if (!ignoreAddressList.empty())
|
||||
ignoreAddressVector.reset(getSocketAddressList(ignoreAddressList, 0, 0));
|
||||
|
||||
//
|
||||
// Setup UDP trasport(s) (per interface)
|
||||
//
|
||||
|
||||
InetAddrVector tappedNIF;
|
||||
|
||||
for (IfaceNodeVector::const_iterator iter = ifaceList.begin(); iter != ifaceList.end(); iter++)
|
||||
{
|
||||
ifaceNode node = *iter;
|
||||
|
||||
LOG(logLevelDebug, "Setting up UDP for interface %s, broadcast %s.",
|
||||
inetAddressToString(node.ifaceAddr, false).c_str(),
|
||||
inetAddressToString(node.ifaceBCast, false).c_str());
|
||||
try
|
||||
{
|
||||
// where to bind (listen) address
|
||||
osiSockAddr listenLocalAddress;
|
||||
listenLocalAddress.ia.sin_family = AF_INET;
|
||||
listenLocalAddress.ia.sin_port = htons(listenPort);
|
||||
listenLocalAddress.ia.sin_addr.s_addr = node.ifaceAddr.ia.sin_addr.s_addr;
|
||||
|
||||
BlockingUDPTransport::shared_pointer transport = static_pointer_cast<BlockingUDPTransport>(connector->connect(
|
||||
nullTransportClient, responseHandler,
|
||||
listenLocalAddress, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
listenLocalAddress = *transport->getRemoteAddress();
|
||||
// to allow automatic assignment of listen port (for testing)
|
||||
if (listenPort == 0)
|
||||
{
|
||||
listenPort = ntohs(listenLocalAddress.ia.sin_port);
|
||||
aToIPAddr(mcastAddress.c_str(), listenPort, &group.ia);
|
||||
|
||||
LOG(logLevelDebug, "Dynamic listen UDP port set to %d.", listenPort);
|
||||
}
|
||||
|
||||
if (ignoreAddressVector.get() && ignoreAddressVector->size())
|
||||
transport->setIgnoredAddresses(ignoreAddressVector.get());
|
||||
|
||||
tappedNIF.push_back(listenLocalAddress);
|
||||
|
||||
|
||||
BlockingUDPTransport::shared_pointer transport2;
|
||||
|
||||
if(node.ifaceBCast.ia.sin_family == AF_UNSPEC ||
|
||||
node.ifaceBCast.ia.sin_addr.s_addr == listenLocalAddress.ia.sin_addr.s_addr) {
|
||||
LOG(logLevelWarn, "Unable to find broadcast address of interface %s.", inetAddressToString(node.ifaceAddr, false).c_str());
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
else
|
||||
{
|
||||
/* An oddness of BSD sockets (not winsock) is that binding to
|
||||
* INADDR_ANY will receive unicast and broadcast, but binding to
|
||||
* a specific interface address receives only unicast. The trick
|
||||
* is to bind a second socket to the interface broadcast address,
|
||||
* which will then receive only broadcasts.
|
||||
*/
|
||||
|
||||
osiSockAddr bcastAddress;
|
||||
bcastAddress.ia.sin_family = AF_INET;
|
||||
bcastAddress.ia.sin_port = htons(listenPort);
|
||||
bcastAddress.ia.sin_addr.s_addr = node.ifaceBCast.ia.sin_addr.s_addr;
|
||||
|
||||
transport2 = static_pointer_cast<BlockingUDPTransport>(connector->connect(
|
||||
nullTransportClient, responseHandler,
|
||||
bcastAddress, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
/* The other wrinkle is that nothing should be sent from this second
|
||||
* socket. So replies are made through the unicast socket.
|
||||
*/
|
||||
transport2->setReplyTransport(transport);
|
||||
|
||||
if (ignoreAddressVector.get() && ignoreAddressVector->size())
|
||||
transport2->setIgnoredAddresses(ignoreAddressVector.get());
|
||||
|
||||
tappedNIF.push_back(bcastAddress);
|
||||
}
|
||||
#endif
|
||||
|
||||
transport->setMutlicastNIF(loAddr, true);
|
||||
transport->setLocalMulticastAddress(group);
|
||||
|
||||
transport->start();
|
||||
udpTransports.push_back(transport);
|
||||
|
||||
if (transport2)
|
||||
{
|
||||
transport2->start();
|
||||
udpTransports.push_back(transport2);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
THROW_BASE_EXCEPTION_CAUSE("Failed to initialize UDP transport.", e);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
THROW_BASE_EXCEPTION("Failed to initialize UDP transport.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Create UDP transport for sending (to all network interfaces)
|
||||
//
|
||||
|
||||
osiSockAddr anyAddress;
|
||||
anyAddress.ia.sin_family = AF_INET;
|
||||
anyAddress.ia.sin_port = htons(0);
|
||||
anyAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
sendTransport = static_pointer_cast<BlockingUDPTransport>(connector->connect(
|
||||
nullTransportClient, responseHandler,
|
||||
anyAddress, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
|
||||
// TODO current implementation shares the port (aka beacon and search port)
|
||||
int32 sendPort = listenPort;
|
||||
|
||||
//
|
||||
// compile auto address list - where to send packets
|
||||
//
|
||||
|
||||
InetAddrVector autoBCastAddr;
|
||||
for (IfaceNodeVector::const_iterator iter = ifaceList.begin(); iter != ifaceList.end(); iter++)
|
||||
{
|
||||
ifaceNode node = *iter;
|
||||
|
||||
if (node.ifaceBCast.ia.sin_family != AF_UNSPEC)
|
||||
{
|
||||
node.ifaceBCast.ia.sin_port = htons(sendPort);
|
||||
autoBCastAddr.push_back(node.ifaceBCast);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// set send address list
|
||||
//
|
||||
|
||||
if (!addressList.empty())
|
||||
{
|
||||
// if auto is true, add it to specified list
|
||||
if (!autoAddressList)
|
||||
autoBCastAddr.clear();
|
||||
|
||||
auto_ptr<InetAddrVector> list(getSocketAddressList(addressList, sendPort, &autoBCastAddr));
|
||||
if (list.get() && list->size())
|
||||
{
|
||||
sendTransport->setSendAddresses(list.get());
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
// fallback
|
||||
// set default (auto) address list
|
||||
sendTransport->setSendAddresses(&autoBCastAddr);
|
||||
}
|
||||
*/
|
||||
}
|
||||
else if (autoAddressList)
|
||||
{
|
||||
// set default (auto) address list
|
||||
sendTransport->setSendAddresses(&autoBCastAddr);
|
||||
}
|
||||
|
||||
|
||||
sendTransport->start();
|
||||
udpTransports.push_back(sendTransport);
|
||||
|
||||
// debug output of broadcast addresses
|
||||
InetAddrVector* blist = sendTransport->getSendAddresses();
|
||||
if (!blist || !blist->size())
|
||||
LOG(logLevelError,
|
||||
"No broadcast addresses found or specified - empty address list!");
|
||||
else
|
||||
for (size_t i = 0; i < blist->size(); i++)
|
||||
LOG(logLevelDebug,
|
||||
"Broadcast address #%d: %s.", i, inetAddressToString((*blist)[i]).c_str());
|
||||
|
||||
//
|
||||
// Setup local multicasting
|
||||
//
|
||||
|
||||
BlockingUDPTransport::shared_pointer localMulticastTransport;
|
||||
try
|
||||
{
|
||||
// NOTE: multicast receiver socket must be "bound" to INADDR_ANY or multicast address
|
||||
localMulticastTransport = static_pointer_cast<BlockingUDPTransport>(connector->connect(
|
||||
nullTransportClient, responseHandler,
|
||||
group, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
localMulticastTransport->setTappedNIF(&tappedNIF);
|
||||
localMulticastTransport->join(group, loAddr);
|
||||
localMulticastTransport->start();
|
||||
udpTransports.push_back(localMulticastTransport);
|
||||
|
||||
LOG(logLevelDebug, "Local multicast enabled on %s/%s.",
|
||||
inetAddressToString(loAddr, false).c_str(),
|
||||
inetAddressToString(group).c_str());
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LOG(logLevelDebug, "Failed to initialize local multicast, funcionality disabled. Reason: %s.", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4478,222 +4478,20 @@ namespace epics {
|
||||
SOCKET socket = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
|
||||
if (socket == INVALID_SOCKET)
|
||||
{
|
||||
LOG(logLevelError, "Failed to initialize broadcast UDP transport.");
|
||||
LOG(logLevelError, "Failed to create a socket to introspect network interfaces.");
|
||||
return false;
|
||||
}
|
||||
|
||||
IfaceNodeVector ifaceList;
|
||||
if (discoverInterfaces(ifaceList, socket, 0) || ifaceList.size() == 0)
|
||||
{
|
||||
LOG(logLevelError, "Failed to initialize broadcast UDP transport, no interfaces available.");
|
||||
LOG(logLevelError, "Failed to introspect interfaces or no network interfaces available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
epicsSocketDestroy (socket);
|
||||
|
||||
|
||||
|
||||
//ClientContextImpl::shared_pointer thisPointer = shared_from_this();
|
||||
TransportClient::shared_pointer nullTransportClient;
|
||||
auto_ptr<BlockingUDPConnector> broadcastConnector(new BlockingUDPConnector(false, true, true));
|
||||
|
||||
osiSockAddr anyAddress;
|
||||
anyAddress.ia.sin_family = AF_INET;
|
||||
anyAddress.ia.sin_port = htons(0);
|
||||
anyAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
m_searchTransport = static_pointer_cast<BlockingUDPTransport>(broadcastConnector->connect(
|
||||
nullTransportClient, m_responseHandler,
|
||||
anyAddress, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
if (!m_searchTransport.get())
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
|
||||
InetAddrVector autoBCastAddr;
|
||||
for (IfaceNodeVector::const_iterator iter = ifaceList.begin(); iter != ifaceList.end(); iter++)
|
||||
{
|
||||
ifaceNode node = *iter;
|
||||
|
||||
if (node.ifaceBCast.ia.sin_family != AF_UNSPEC)
|
||||
{
|
||||
node.ifaceBCast.ia.sin_port = htons(m_broadcastPort);
|
||||
autoBCastAddr.push_back(node.ifaceBCast);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// set beacon (broadcast) address list
|
||||
//
|
||||
|
||||
|
||||
if (!m_addressList.empty())
|
||||
{
|
||||
// if auto is true, add it to specified list
|
||||
if (!m_autoAddressList)
|
||||
autoBCastAddr.clear();
|
||||
|
||||
auto_ptr<InetAddrVector> list(getSocketAddressList(m_addressList, m_broadcastPort, &autoBCastAddr));
|
||||
if (list.get() && list->size())
|
||||
{
|
||||
m_searchTransport->setSendAddresses(list.get());
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
// fallback
|
||||
// set default (auto) address list
|
||||
m_searchTransport->setSendAddresses(&autoBCastAddr);
|
||||
}
|
||||
*/
|
||||
}
|
||||
else if (m_autoAddressList)
|
||||
{
|
||||
// set default (auto) address list
|
||||
m_searchTransport->setSendAddresses(&autoBCastAddr);
|
||||
}
|
||||
|
||||
m_searchTransport->start();
|
||||
|
||||
// debug output for broadcast addresses
|
||||
InetAddrVector* blist = m_searchTransport->getSendAddresses();
|
||||
if (!blist || !blist->size())
|
||||
LOG(logLevelError,
|
||||
"No broadcast addresses found or specified - empty PV search address list!");
|
||||
else
|
||||
for (size_t i = 0; i < blist->size(); i++)
|
||||
LOG(logLevelDebug,
|
||||
"Broadcast address #%d: %s.", i, inetAddressToString((*blist)[i]).c_str());
|
||||
|
||||
|
||||
// TODO configurable local NIF, address
|
||||
osiSockAddr loAddr;
|
||||
getLoopbackNIF(loAddr, "", 0);
|
||||
|
||||
//
|
||||
// Setup local multicasting
|
||||
//
|
||||
|
||||
osiSockAddr group;
|
||||
// TODO configurable local multicast address
|
||||
aToIPAddr("224.0.0.128", m_broadcastPort, &group.ia);
|
||||
|
||||
BlockingUDPTransport::shared_pointer localMulticastTransport;
|
||||
|
||||
if (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
// NOTE: multicast receiver socket must be "bound" to INADDR_ANY or multicast address
|
||||
localMulticastTransport = static_pointer_cast<BlockingUDPTransport>(broadcastConnector->connect(
|
||||
nullTransportClient, m_responseHandler,
|
||||
group, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
localMulticastTransport->join(group, loAddr);
|
||||
|
||||
if (localMulticastTransport)
|
||||
{
|
||||
localMulticastTransport->start();
|
||||
m_udpTransports.push_back(localMulticastTransport);
|
||||
}
|
||||
|
||||
LOG(logLevelDebug, "Local multicast enabled on %s/%s.",
|
||||
inetAddressToString(loAddr, false).c_str(),
|
||||
inetAddressToString(group).c_str());
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LOG(logLevelDebug, "Failed to initialize local multicast, funcionality disabled. Reason: %s.", ex.what());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(logLevelDebug, "Failed to detect a loopback network interface, local multicast disabled.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for (IfaceNodeVector::const_iterator iter = ifaceList.begin(); iter != ifaceList.end(); iter++)
|
||||
{
|
||||
ifaceNode node = *iter;
|
||||
|
||||
LOG(logLevelDebug, "Setting up UDP for interface %s, broadcast %s.",
|
||||
inetAddressToString(node.ifaceAddr, false).c_str(),
|
||||
inetAddressToString(node.ifaceBCast, false).c_str());
|
||||
try
|
||||
{
|
||||
// where to bind (listen) address
|
||||
// TODO opt copy
|
||||
osiSockAddr listenLocalAddress;
|
||||
listenLocalAddress.ia.sin_family = AF_INET;
|
||||
listenLocalAddress.ia.sin_port = htons(m_broadcastPort);
|
||||
listenLocalAddress.ia.sin_addr.s_addr = node.ifaceAddr.ia.sin_addr.s_addr;
|
||||
|
||||
BlockingUDPTransport::shared_pointer transport = static_pointer_cast<BlockingUDPTransport>(broadcastConnector->connect(
|
||||
nullTransportClient, m_responseHandler,
|
||||
listenLocalAddress, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
listenLocalAddress = *transport->getRemoteAddress();
|
||||
|
||||
BlockingUDPTransport::shared_pointer transport2;
|
||||
|
||||
if(node.ifaceBCast.ia.sin_family == AF_UNSPEC ||
|
||||
node.ifaceBCast.ia.sin_addr.s_addr == listenLocalAddress.ia.sin_addr.s_addr) {
|
||||
LOG(logLevelWarn, "Unable to find broadcast address of interface %s.", inetAddressToString(node.ifaceBCast, false).c_str());
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
else
|
||||
{
|
||||
/* An oddness of BSD sockets (not winsock) is that binding to
|
||||
* INADDR_ANY will receive unicast and broadcast, but binding to
|
||||
* a specific interface address receives only unicast. The trick
|
||||
* is to bind a second socket to the interface broadcast address,
|
||||
* which will then receive only broadcasts.
|
||||
*/
|
||||
|
||||
// TODO opt copy
|
||||
osiSockAddr bcastAddress;
|
||||
bcastAddress.ia.sin_family = AF_INET;
|
||||
bcastAddress.ia.sin_port = htons(m_broadcastPort);
|
||||
bcastAddress.ia.sin_addr.s_addr = node.ifaceBCast.ia.sin_addr.s_addr;
|
||||
|
||||
transport2 = static_pointer_cast<BlockingUDPTransport>(broadcastConnector->connect(
|
||||
nullTransportClient, m_responseHandler,
|
||||
bcastAddress, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
/* The other wrinkle is that nothing should be sent from this second
|
||||
* socket. So replies are made through the unicast socket.
|
||||
*/
|
||||
transport2->setReplyTransport(transport);
|
||||
}
|
||||
#endif
|
||||
|
||||
transport->setMutlicastNIF(loAddr, true);
|
||||
transport->setLocalMulticastAddress(group);
|
||||
|
||||
transport->start();
|
||||
m_udpTransports.push_back(transport);
|
||||
|
||||
if (transport2)
|
||||
{
|
||||
transport2->start();
|
||||
m_udpTransports.push_back(transport2);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
THROW_BASE_EXCEPTION_CAUSE("Failed to initialize broadcast UDP transport", e);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
THROW_BASE_EXCEPTION("Failed to initialize broadcast UDP transport");
|
||||
}
|
||||
}
|
||||
initializeUDPTransports(false, m_udpTransports, ifaceList, m_responseHandler, m_searchTransport,
|
||||
m_broadcastPort, m_autoAddressList, m_addressList, std::string());
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -5112,7 +4910,6 @@ namespace epics {
|
||||
/**
|
||||
* UDP transports needed to receive channel searches.
|
||||
*/
|
||||
typedef std::vector<BlockingUDPTransport::shared_pointer> BlockingUDPTransportVector;
|
||||
BlockingUDPTransportVector m_udpTransports;
|
||||
|
||||
/**
|
||||
|
||||
@@ -172,13 +172,15 @@ void ServerContextImpl::loadConfiguration()
|
||||
SOCKET sock = epicsSocketCreate(AF_INET, SOCK_STREAM, 0);
|
||||
if (!sock) {
|
||||
THROW_BASE_EXCEPTION("Failed to create a socket needed to introspect network interfaces.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (discoverInterfaces(_ifaceList, sock, &_ifaceAddr) || _ifaceList.size() == 0)
|
||||
if (discoverInterfaces(_ifaceList, sock, &_ifaceAddr))
|
||||
{
|
||||
THROW_BASE_EXCEPTION("Failed to introspect network interfaces or no network interfaces available.");
|
||||
return;
|
||||
THROW_BASE_EXCEPTION("Failed to introspect network interfaces.");
|
||||
}
|
||||
else if (_ifaceList.size() == 0)
|
||||
{
|
||||
THROW_BASE_EXCEPTION("No (specified) network interface(s) available.");
|
||||
}
|
||||
epicsSocketDestroy(sock);
|
||||
}
|
||||
@@ -276,222 +278,8 @@ void ServerContextImpl::internalInitialize()
|
||||
|
||||
void ServerContextImpl::initializeBroadcastTransport()
|
||||
{
|
||||
TransportClient::shared_pointer nullTransportClient;
|
||||
auto_ptr<BlockingUDPConnector> broadcastConnector(new BlockingUDPConnector(true, true, true));
|
||||
|
||||
// TODO configurable local NIF, address
|
||||
osiSockAddr loAddr;
|
||||
getLoopbackNIF(loAddr, "", 0);
|
||||
|
||||
// TODO configurable local multicast address
|
||||
osiSockAddr group;
|
||||
aToIPAddr("224.0.0.128", _broadcastPort, &group.ia);
|
||||
|
||||
//
|
||||
// set ignore address list
|
||||
//
|
||||
auto_ptr<InetAddrVector> ignoreAddressList;
|
||||
if (!_ignoreAddressList.empty())
|
||||
ignoreAddressList.reset(getSocketAddressList(_ignoreAddressList, 0, 0));
|
||||
|
||||
//
|
||||
// Setup UDP trasport(s) (per interface)
|
||||
//
|
||||
|
||||
InetAddrVector tappedNIF;
|
||||
|
||||
for (IfaceNodeVector::const_iterator iter = _ifaceList.begin(); iter != _ifaceList.end(); iter++)
|
||||
{
|
||||
ifaceNode node = *iter;
|
||||
|
||||
LOG(logLevelDebug, "Setting up UDP for interface %s, broadcast %s.",
|
||||
inetAddressToString(node.ifaceAddr, false).c_str(),
|
||||
inetAddressToString(node.ifaceBCast, false).c_str());
|
||||
try
|
||||
{
|
||||
// where to bind (listen) address
|
||||
osiSockAddr listenLocalAddress;
|
||||
listenLocalAddress.ia.sin_family = AF_INET;
|
||||
listenLocalAddress.ia.sin_port = htons(_broadcastPort);
|
||||
listenLocalAddress.ia.sin_addr.s_addr = node.ifaceAddr.ia.sin_addr.s_addr;
|
||||
|
||||
BlockingUDPTransport::shared_pointer transport = static_pointer_cast<BlockingUDPTransport>(broadcastConnector->connect(
|
||||
nullTransportClient, _responseHandler,
|
||||
listenLocalAddress, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
listenLocalAddress = *transport->getRemoteAddress();
|
||||
// to allow automatic assignment of broadcast port (for testing)
|
||||
if (_broadcastPort == 0)
|
||||
{
|
||||
_broadcastPort = ntohs(listenLocalAddress.ia.sin_port);
|
||||
aToIPAddr("224.0.0.128", _broadcastPort, &group.ia);
|
||||
|
||||
LOG(logLevelDebug, "Dynamic broadcast UDP port set to %d.", _broadcastPort);
|
||||
}
|
||||
|
||||
if (ignoreAddressList.get() && ignoreAddressList->size())
|
||||
transport->setIgnoredAddresses(ignoreAddressList.get());
|
||||
|
||||
tappedNIF.push_back(listenLocalAddress);
|
||||
|
||||
|
||||
BlockingUDPTransport::shared_pointer transport2;
|
||||
|
||||
if(node.ifaceBCast.ia.sin_family == AF_UNSPEC ||
|
||||
node.ifaceBCast.ia.sin_addr.s_addr == listenLocalAddress.ia.sin_addr.s_addr) {
|
||||
LOG(logLevelWarn, "Unable to find broadcast address of interface %s.", inetAddressToString(node.ifaceBCast, false).c_str());
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
else
|
||||
{
|
||||
/* An oddness of BSD sockets (not winsock) is that binding to
|
||||
* INADDR_ANY will receive unicast and broadcast, but binding to
|
||||
* a specific interface address receives only unicast. The trick
|
||||
* is to bind a second socket to the interface broadcast address,
|
||||
* which will then receive only broadcasts.
|
||||
*/
|
||||
|
||||
osiSockAddr bcastAddress;
|
||||
bcastAddress.ia.sin_family = AF_INET;
|
||||
bcastAddress.ia.sin_port = htons(_broadcastPort);
|
||||
bcastAddress.ia.sin_addr.s_addr = node.ifaceBCast.ia.sin_addr.s_addr;
|
||||
|
||||
transport2 = static_pointer_cast<BlockingUDPTransport>(broadcastConnector->connect(
|
||||
nullTransportClient, _responseHandler,
|
||||
bcastAddress, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
/* The other wrinkle is that nothing should be sent from this second
|
||||
* socket. So replies are made through the unicast socket.
|
||||
*/
|
||||
transport2->setReplyTransport(transport);
|
||||
|
||||
if (ignoreAddressList.get() && ignoreAddressList->size())
|
||||
transport2->setIgnoredAddresses(ignoreAddressList.get());
|
||||
|
||||
tappedNIF.push_back(bcastAddress);
|
||||
}
|
||||
#endif
|
||||
|
||||
transport->setMutlicastNIF(loAddr, true);
|
||||
transport->setLocalMulticastAddress(group);
|
||||
|
||||
transport->start();
|
||||
_udpTransports.push_back(transport);
|
||||
|
||||
if (transport2)
|
||||
{
|
||||
transport2->start();
|
||||
_udpTransports.push_back(transport2);
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
THROW_BASE_EXCEPTION_CAUSE("Failed to initialize broadcast UDP transport", e);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
THROW_BASE_EXCEPTION("Failed to initialize broadcast UDP transport");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Create UDP transport for sending (to all network interfaces)
|
||||
//
|
||||
|
||||
osiSockAddr anyAddress;
|
||||
anyAddress.ia.sin_family = AF_INET;
|
||||
anyAddress.ia.sin_port = htons(0);
|
||||
anyAddress.ia.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
_broadcastTransport = static_pointer_cast<BlockingUDPTransport>(broadcastConnector->connect(
|
||||
nullTransportClient, _responseHandler,
|
||||
anyAddress, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
|
||||
//
|
||||
// compile auto address list - where to send beacons
|
||||
//
|
||||
|
||||
InetAddrVector autoBCastAddr;
|
||||
for (IfaceNodeVector::const_iterator iter = _ifaceList.begin(); iter != _ifaceList.end(); iter++)
|
||||
{
|
||||
ifaceNode node = *iter;
|
||||
|
||||
if (node.ifaceBCast.ia.sin_family != AF_UNSPEC)
|
||||
{
|
||||
node.ifaceBCast.ia.sin_port = htons(_broadcastPort);
|
||||
autoBCastAddr.push_back(node.ifaceBCast);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// set beacon (broadcast) address list
|
||||
//
|
||||
|
||||
if (!_beaconAddressList.empty())
|
||||
{
|
||||
// if auto is true, add it to specified list
|
||||
if (!_autoBeaconAddressList)
|
||||
autoBCastAddr.clear();
|
||||
|
||||
auto_ptr<InetAddrVector> list(getSocketAddressList(_beaconAddressList, _broadcastPort, &autoBCastAddr));
|
||||
if (list.get() && list->size())
|
||||
{
|
||||
_broadcastTransport->setSendAddresses(list.get());
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
// fallback
|
||||
// set default (auto) address list
|
||||
_broadcastTransport->setSendAddresses(&autoBCastAddr);
|
||||
}
|
||||
*/
|
||||
}
|
||||
else if (_autoBeaconAddressList)
|
||||
{
|
||||
// set default (auto) address list
|
||||
_broadcastTransport->setSendAddresses(&autoBCastAddr);
|
||||
}
|
||||
|
||||
|
||||
// debug output of broadcast addresses
|
||||
InetAddrVector* blist = _broadcastTransport->getSendAddresses();
|
||||
if (!blist || !blist->size())
|
||||
LOG(logLevelError,
|
||||
"No broadcast addresses found or specified - empty beacon address list!");
|
||||
else
|
||||
for (size_t i = 0; i < blist->size(); i++)
|
||||
LOG(logLevelDebug,
|
||||
"Beacon broadcast address #%d: %s.", i, inetAddressToString((*blist)[i]).c_str());
|
||||
|
||||
//
|
||||
// Setup local multicasting
|
||||
//
|
||||
|
||||
BlockingUDPTransport::shared_pointer localMulticastTransport;
|
||||
try
|
||||
{
|
||||
// NOTE: multicast receiver socket must be "bound" to INADDR_ANY or multicast address
|
||||
localMulticastTransport = static_pointer_cast<BlockingUDPTransport>(broadcastConnector->connect(
|
||||
nullTransportClient, _responseHandler,
|
||||
group, PVA_PROTOCOL_REVISION,
|
||||
PVA_DEFAULT_PRIORITY));
|
||||
localMulticastTransport->setTappedNIF(&tappedNIF);
|
||||
localMulticastTransport->join(group, loAddr);
|
||||
localMulticastTransport->start();
|
||||
_udpTransports.push_back(localMulticastTransport);
|
||||
|
||||
LOG(logLevelDebug, "Local multicast enabled on %s/%s.",
|
||||
inetAddressToString(loAddr, false).c_str(),
|
||||
inetAddressToString(group).c_str());
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LOG(logLevelDebug, "Failed to initialize local multicast, funcionality disabled. Reason: %s.", ex.what());
|
||||
}
|
||||
|
||||
initializeUDPTransports(true, _udpTransports, _ifaceList, _responseHandler, _broadcastTransport,
|
||||
_broadcastPort, _autoBeaconAddressList, _beaconAddressList, _ignoreAddressList);
|
||||
}
|
||||
|
||||
void ServerContextImpl::run(int32 seconds)
|
||||
|
||||
@@ -354,7 +354,6 @@ private:
|
||||
/**
|
||||
* UDP transports needed to receive channel searches.
|
||||
*/
|
||||
typedef std::vector<BlockingUDPTransport::shared_pointer> BlockingUDPTransportVector;
|
||||
BlockingUDPTransportVector _udpTransports;
|
||||
|
||||
/**
|
||||
|
||||
@@ -59,6 +59,7 @@ int ChannelAccessIFTest::runAllTest() {
|
||||
testPlan(153+EXTRA_STRESS_TESTS);
|
||||
|
||||
Configuration::shared_pointer base_config(ConfigurationBuilder()
|
||||
//.add("EPICS_PVA_DEBUG", "3")
|
||||
.add("EPICS_PVAS_INTF_ADDR_LIST", "127.0.0.1")
|
||||
.add("EPICS_PVA_ADDR_LIST", "127.0.0.1")
|
||||
.add("EPICS_PVA_AUTO_ADDR_LIST","0")
|
||||
|
||||
Reference in New Issue
Block a user