From 87c11d83d22744bb79ec757ddd53fe258f1b6e28 Mon Sep 17 00:00:00 2001 From: Matej Sekoranja Date: Sun, 6 Mar 2016 21:21:26 +0100 Subject: [PATCH] win32 port --- pvtoolsSrc/eget.cpp | 2 +- src/remote/blockingUDPTransport.cpp | 48 ++++++++--- src/remote/pv/remote.h | 2 +- src/utils/configuration.cpp | 2 +- src/utils/inetAddressUtil.cpp | 128 +++++++++++++++++++++++++++- src/utils/logger.cpp | 1 + src/utils/pv/configuration.h | 2 +- src/utils/pv/fairQueue.h | 17 +++- 8 files changed, 179 insertions(+), 23 deletions(-) diff --git a/pvtoolsSrc/eget.cpp b/pvtoolsSrc/eget.cpp index 511c5a3..e8b933d 100644 --- a/pvtoolsSrc/eget.cpp +++ b/pvtoolsSrc/eget.cpp @@ -1946,6 +1946,7 @@ int main (int argc, char *argv[]) epicsThreadSleep(timeOut); } + epics::pvAccess::ca::CAClientFactory::stop(); ClientFactory::stop(); } // service RPC mode @@ -2137,7 +2138,6 @@ int main (int argc, char *argv[]) channel->destroy(); - epics::pvAccess::ca::CAClientFactory::stop(); ClientFactory::stop(); } diff --git a/src/remote/blockingUDPTransport.cpp b/src/remote/blockingUDPTransport.cpp index 7a9cf2e..7ada705 100644 --- a/src/remote/blockingUDPTransport.cpp +++ b/src/remote/blockingUDPTransport.cpp @@ -619,6 +619,8 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so nullTransportClient, responseHandler, listenLocalAddress, PVA_PROTOCOL_REVISION, PVA_DEFAULT_PRIORITY)); + if (!transport) + continue; listenLocalAddress = *transport->getRemoteAddress(); // to allow automatic assignment of listen port (for testing) if (listenPort == 0) @@ -660,17 +662,20 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so 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); - */ - // NOTE: search responses all always send from sendTransport + if (transport2) + { + /* The other wrinkle is that nothing should be sent from this second + * socket. So replies are made through the unicast socket. + * + transport2->setReplyTransport(transport); + */ + // NOTE: search responses all always send from sendTransport - if (ignoreAddressVector.get() && ignoreAddressVector->size()) - transport2->setIgnoredAddresses(ignoreAddressVector.get()); + if (ignoreAddressVector.get() && ignoreAddressVector->size()) + transport2->setIgnoredAddresses(ignoreAddressVector.get()); - tappedNIF.push_back(bcastAddress); + tappedNIF.push_back(bcastAddress); + } } #endif @@ -710,7 +715,11 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so nullTransportClient, responseHandler, anyAddress, PVA_PROTOCOL_REVISION, PVA_DEFAULT_PRIORITY)); - + if (!sendTransport) + { + THROW_BASE_EXCEPTION("Failed to initialize UDP transport."); + } + // TODO current implementation shares the port (aka beacon and search port) int32 sendPort = listenPort; @@ -778,14 +787,27 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so // Setup local multicasting // + // WIN32 do not allow binding to multicast address, use any address w/ port + #if defined(_WIN32) + anyAddress.ia.sin_port = htons(listenPort); + #endif + BlockingUDPTransport::shared_pointer localMulticastTransport; try { // NOTE: multicast receiver socket must be "bound" to INADDR_ANY or multicast address localMulticastTransport = static_pointer_cast(connector->connect( nullTransportClient, responseHandler, - group, PVA_PROTOCOL_REVISION, - PVA_DEFAULT_PRIORITY)); + #if !defined(_WIN32) + group, + #else + anyAddress, + #endif + PVA_PROTOCOL_REVISION, + PVA_DEFAULT_PRIORITY)); + if (!localMulticastTransport) + throw std::runtime_error("Failed to bind UDP socket."); + localMulticastTransport->setTappedNIF(&tappedNIF); localMulticastTransport->join(group, loAddr); localMulticastTransport->start(); @@ -797,7 +819,7 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so } catch (std::exception& ex) { - LOG(logLevelDebug, "Failed to initialize local multicast, funcionality disabled. Reason: %s.", ex.what()); + LOG(logLevelDebug, "Failed to initialize local multicast, functionality disabled. Reason: %s.", ex.what()); } } diff --git a/src/remote/pv/remote.h b/src/remote/pv/remote.h index a865ad7..5c172e9 100644 --- a/src/remote/pv/remote.h +++ b/src/remote/pv/remote.h @@ -24,7 +24,6 @@ #include #include #include -#include #ifdef remoteEpicsExportSharedSymbols # define epicsExportSharedSymbols @@ -33,6 +32,7 @@ #include #include +#include /// TODO only here because of the Lockable #include diff --git a/src/utils/configuration.cpp b/src/utils/configuration.cpp index 713af0b..3b9fbf0 100644 --- a/src/utils/configuration.cpp +++ b/src/utils/configuration.cpp @@ -50,7 +50,7 @@ const std::string &Properties::getProperty(const string &key, const string &defa } } -void Properties::Properties::load() +void Properties::load() { load(_fileName); } diff --git a/src/utils/inetAddressUtil.cpp b/src/utils/inetAddressUtil.cpp index 819ca21..7b29669 100644 --- a/src/utils/inetAddressUtil.cpp +++ b/src/utils/inetAddressUtil.cpp @@ -214,13 +214,12 @@ int getLoopbackNIF(osiSockAddr &loAddr, string const & localNIF, unsigned short -// copy of base-3.14.12.4/src/libCom/osi/os/default/osdNetIntf.c -// TODO support windows (see osi/os/WIN32/osdNetIntf.c) - #include //#include #include +#if !defined(_WIN32) + /* * Determine the size of an ifreq structure * Made difficult by the fact that addresses larger than the structure @@ -387,6 +386,7 @@ int discoverInterfaces(IfaceNodeVector &list, SOCKET socket, const osiSockAddr * } #endif else { + // if it is a match, accept the interface even if it does not support broadcast (i.e. 127.0.0.1) if (match) node.ifaceBCast.sa.sa_family = AF_UNSPEC; else @@ -406,5 +406,127 @@ int discoverInterfaces(IfaceNodeVector &list, SOCKET socket, const osiSockAddr * } +#else + +#define VC_EXTRALEAN +#include +#include + +int discoverInterfaces(IfaceNodeVector &list, SOCKET socket, const osiSockAddr *pMatchAddr) +{ + int status; + INTERFACE_INFO *pIfinfo; + INTERFACE_INFO *pIfinfoList; + unsigned nelem; + int numifs; + DWORD cbBytesReturned; + int match; + + /* only valid for winsock 2 and above + TODO resolve dllimport compilation problem and uncomment this check + if (wsaMajorVersion() < 2 ) { + fprintf(stderr, "Need to set EPICS_CA_AUTO_ADDR_LIST=NO for winsock 1\n"); + return -1; + } + */ + + nelem = 100; + pIfinfoList = (INTERFACE_INFO *) calloc(nelem, sizeof(INTERFACE_INFO)); + if(!pIfinfoList){ + return -1; + } + + status = WSAIoctl (socket, SIO_GET_INTERFACE_LIST, + NULL, 0, + (LPVOID)pIfinfoList, nelem*sizeof(INTERFACE_INFO), + &cbBytesReturned, NULL, NULL); + + if (status != 0 || cbBytesReturned == 0) { + fprintf(stderr, "WSAIoctl SIO_GET_INTERFACE_LIST failed %d\n",WSAGetLastError()); + free(pIfinfoList); + return -1; + } + + numifs = cbBytesReturned/sizeof(INTERFACE_INFO); + for (pIfinfo = pIfinfoList; pIfinfo < (pIfinfoList+numifs); pIfinfo++){ + + /* + * dont bother with interfaces that have been disabled + */ + if (!(pIfinfo->iiFlags & IFF_UP)) { + continue; + } + + /* + * If its not an internet interface then dont use it + * + work around WS2 bug + */ + if (pIfinfo->iiAddress.Address.sa_family != AF_INET) { + if (pIfinfo->iiAddress.Address.sa_family == 0) { + pIfinfo->iiAddress.Address.sa_family = AF_INET; + } + else + continue; + } + + /* + * if it isnt a wildcarded interface then look for + * an exact match + */ + match = 0; + if (pMatchAddr && pMatchAddr->sa.sa_family != AF_UNSPEC) { + if (pIfinfo->iiAddress.Address.sa_family != pMatchAddr->sa.sa_family) { + continue; + } + if (pIfinfo->iiAddress.Address.sa_family != AF_INET) { + continue; + } + if (pMatchAddr->sa.sa_family != AF_INET) { + continue; + } + if (pMatchAddr->ia.sin_addr.s_addr != htonl(INADDR_ANY)) { + if (pIfinfo->iiAddress.AddressIn.sin_addr.s_addr != pMatchAddr->ia.sin_addr.s_addr) { + continue; + } + else + match = 1; + } + } + + /* + * dont use the loop back interface, unless it maches pMatchAddr + */ + if (!match) { + if (pIfinfo->iiFlags & IFF_LOOPBACK) { + continue; + } + } + + ifaceNode node; + node.ifaceAddr.ia = pIfinfo->iiAddress.AddressIn; + + if (pIfinfo->iiFlags & IFF_BROADCAST) { + const unsigned mask = pIfinfo->iiNetmask.AddressIn.sin_addr.s_addr; + const unsigned bcast = pIfinfo->iiBroadcastAddress.AddressIn.sin_addr.s_addr; + const unsigned addr = pIfinfo->iiAddress.AddressIn.sin_addr.s_addr; + unsigned result = (addr & mask) | (bcast &~mask); + node.ifaceBCast.ia.sin_family = AF_INET; + node.ifaceBCast.ia.sin_addr.s_addr = result; + node.ifaceBCast.ia.sin_port = htons ( 0 ); + } + else { + node.ifaceBCast.ia = pIfinfo->iiBroadcastAddress.AddressIn; + } + + + list.push_back(node); + } + + free (pIfinfoList); + return 0; +} + +#endif + } } diff --git a/src/utils/logger.cpp b/src/utils/logger.cpp index b7701f6..2443fba 100644 --- a/src/utils/logger.cpp +++ b/src/utils/logger.cpp @@ -53,6 +53,7 @@ namespace epics { va_end(arg); printf("\n"); + fflush(stdout); // needed for WIN32 } } diff --git a/src/utils/pv/configuration.h b/src/utils/pv/configuration.h index 81a6ef9..ff8b431 100644 --- a/src/utils/pv/configuration.h +++ b/src/utils/pv/configuration.h @@ -191,7 +191,7 @@ public: inline size_t size() const {return confs.size();} }; -struct ConfigurationBuilder +struct epicsShareClass ConfigurationBuilder { ConfigurationBuilder(); ConfigurationBuilder& push_env(); diff --git a/src/utils/pv/fairQueue.h b/src/utils/pv/fairQueue.h index 014f455..568ecc2 100644 --- a/src/utils/pv/fairQueue.h +++ b/src/utils/pv/fairQueue.h @@ -7,7 +7,11 @@ #ifndef FAIRQUEUE_H #define FAIRQUEUE_H -#include +#ifdef epicsExportSharedSymbols +# define fairQueueExportSharedSymbols +# undef epicsExportSharedSymbols +#endif + #include #include #include @@ -16,6 +20,13 @@ #include +#ifdef fairQueueExportSharedSymbols +# define epicsExportSharedSymbols +# undef fairQueueExportSharedSymbols +#endif + +#include + namespace epics {namespace pvAccess { @@ -42,13 +53,13 @@ namespace epics {namespace pvAccess { * as push_back() does not broadcast (only wakes up one waiter) */ template -class epicsShareClass fair_queue +class fair_queue { typedef epicsGuard guard_t; public: typedef std::tr1::shared_ptr value_type; - class epicsShareClass entry { + class entry { /* In c++, use of ellLib (which implies offsetof()) should be restricted * to POD structs. So enode_t exists as a POD struct for which offsetof() * is safe and well defined. enode_t::self is used in place of