udp transport initialization refactoring (deduplication)

This commit is contained in:
Matej Sekoranja
2016-03-02 12:37:58 +01:00
parent 87fa71070d
commit 0db4a9a342
6 changed files with 305 additions and 454 deletions

View File

@@ -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;
/**