diff --git a/pvAccessApp/client/Makefile b/pvAccessApp/client/Makefile index e4e4ca9..81c3798 100644 --- a/pvAccessApp/client/Makefile +++ b/pvAccessApp/client/Makefile @@ -8,8 +8,8 @@ LIBSRCS += ChannelAccessFactory.cpp LIBRARY=pvAccessClient -pvAccessClient_LIBS += pvMisc -pvMisc_DIR = $(PVDATA_HOME)/lib/$(EPICS_HOST_ARCH) +pvAccessClient_LIBS += pvData +pvData_DIR = $(PVDATA_HOME)/lib/$(EPICS_HOST_ARCH) include $(TOP)/configure/RULES #---------------------------------------- diff --git a/pvAccessApp/testUtils/Makefile b/pvAccessApp/testUtils/Makefile index 0a5f1d9..70a80db 100644 --- a/pvAccessApp/testUtils/Makefile +++ b/pvAccessApp/testUtils/Makefile @@ -4,19 +4,24 @@ include $(TOP)/configure/CONFIG PROD_HOST += hexDumpTest hexDumpTest_SRCS += hexDumpTest.cpp -hexDumpTest_LIBS += pvAccUtils +hexDumpTest_LIBS += pvAccessUtils PROD_HOST += wildcharMatcherTest wildcharMatcherTest_SRCS += wildcharMatcherTest.cpp -wildcharMatcherTest_LIBS += pvAccUtils Com +wildcharMatcherTest_LIBS += pvAccessUtils Com PROD_HOST += arrayFIFOTest arrayFIFOTest_SRCS += arrayFIFOTest.cpp -arrayFIFOTest_LIBS += pvAccUtils Com +arrayFIFOTest_LIBS += pvAccessUtils Com PROD_HOST += growingCircularBufferTest growingCircularBufferTest_SRCS += growingCircularBufferTest.cpp -growingCircularBufferTest_LIBS += pvAccUtils Com +growingCircularBufferTest_LIBS += pvAccessUtils Com + + +PROD_HOST += inetAddressUtilsTest +inetAddressUtilsTest_SRCS += inetAddressUtilsTest.cpp +inetAddressUtilsTest_LIBS += pvAccessUtils Com include $(TOP)/configure/RULES #---------------------------------------- diff --git a/pvAccessApp/testUtils/inetAddressUtilsTest.cpp b/pvAccessApp/testUtils/inetAddressUtilsTest.cpp new file mode 100644 index 0000000..c2e84ee --- /dev/null +++ b/pvAccessApp/testUtils/inetAddressUtilsTest.cpp @@ -0,0 +1,138 @@ +/* + * inetAddressUtilsTest.cpp + * + * Created on: Dec 8, 2010 + * Author: user + */ + +#include "inetAddressUtil.h" + +#include +#include +#include +#include +#include +#include + +using namespace epics::pvAccess; +using std::cout; +using std::endl; +using std::stringstream; +using std::hex; + +String inetAddressToString(osiSockAddr *addr) { + stringstream saddr; + + saddr<<(int)((addr->ia.sin_addr.s_addr)>>24)<<'.'; + saddr<<((int)((addr->ia.sin_addr.s_addr)>>16)&0xFF)<<'.'; + saddr<<((int)((addr->ia.sin_addr.s_addr)>>8)&0xFF)<<'.'; + saddr<<((int)(addr->ia.sin_addr.s_addr)&0xFF); + if(addr->ia.sin_port>0) saddr<<":"<ia.sin_port; + saddr<<" ("<ia.sin_addr.s_addr))<<")"; + + return saddr.str(); +} + +int main(int argc, char *argv[]) { + + InetAddrVector *vec; + InetAddrVector *vec1; + + cout<<"Testing \"getSocketAddressList\""<size()==3); + + osiSockAddr* addr; + addr = vec->at(0); + assert(addr->ia.sin_family==AF_INET); + assert(addr->ia.sin_port==555); + assert(addr->ia.sin_addr.s_addr==(uint32_t)0x7F000001); + cout<<'\t'<at(1); + assert(addr->ia.sin_family==AF_INET); + assert(addr->ia.sin_port==1234); + assert(addr->ia.sin_addr.s_addr==(uint32_t)0x0A0A0C0B); + cout<<'\t'<at(2); + assert(addr->ia.sin_family==AF_INET); + assert(addr->ia.sin_port==555); + assert(addr->ia.sin_addr.s_addr==(uint32_t)0xC0A80304); + cout<<'\t'<size()==4); + + addr = vec1->at(0); + assert(addr->ia.sin_family==AF_INET); + assert(addr->ia.sin_port==6789); + assert(addr->ia.sin_addr.s_addr==(uint32_t)0xAC1037A0); + cout<<'\t'<at(1); + assert(addr->ia.sin_family==AF_INET); + assert(addr->ia.sin_port==555); + assert(addr->ia.sin_addr.s_addr==(uint32_t)0x7F000001); + cout<<'\t'<at(2); + assert(addr->ia.sin_family==AF_INET); + assert(addr->ia.sin_port==1234); + assert(addr->ia.sin_addr.s_addr==(uint32_t)0x0A0A0C0B); + cout<<'\t'<at(3); + assert(addr->ia.sin_family==AF_INET); + assert(addr->ia.sin_port==555); + assert(addr->ia.sin_addr.s_addr==(uint32_t)0xC0A80304); + cout<<'\t'<at(0)))==(int32)0x7F000001); + assert(ipv4AddressToInt(*(vec->at(1)))==(int32)0x0A0A0C0B); + assert(ipv4AddressToInt(*(vec->at(2)))==(int32)0xC0A80304); + cout<<"\nPASSED!\n"; + + delete vec; + delete vec1; + + cout<<"Testing \"intToIPv4Address\""<ia.sin_family==AF_INET); + cout<<'\t'<ia.sin_family==AF_INET); + cout<<'\t'<getArray(),src,16)==0); + cout<<"\nPASSED!\n"; + + // TODO add test for 'getBroadcastAddresses' + + delete addr; + + return 0; +} + diff --git a/pvAccessApp/utils/Makefile b/pvAccessApp/utils/Makefile index 21dbeef..e5ed21c 100644 --- a/pvAccessApp/utils/Makefile +++ b/pvAccessApp/utils/Makefile @@ -6,13 +6,17 @@ INC += hexDump.h INC += wildcharMatcher.h INC += arrayFIFO.h INC += growingCircularBuffer.h +INC += inetAddressUtil.h LIBSRCS += hexDump.cpp LIBSRCS += wildcharMatcher.cpp +LIBSRCS += inetAddressUtil.cpp -LIBRARY = pvAccUtils +LIBRARY = pvAccessUtils +pvAccessUtils_LIBS += Com +pvAccessUtils_LIBS += pvData -#pvAccUtils_LIBS += Com +pvData_DIR = $(PVDATA_HOME)/lib/$(EPICS_HOST_ARCH) include $(TOP)/configure/RULES #---------------------------------------- diff --git a/pvAccessApp/utils/inetAddressUtil.cpp b/pvAccessApp/utils/inetAddressUtil.cpp new file mode 100644 index 0000000..c100d56 --- /dev/null +++ b/pvAccessApp/utils/inetAddressUtil.cpp @@ -0,0 +1,208 @@ +/* + * inetAddressUtil.cpp + * + * Created on: Nov 12, 2010 + * Author: Miha Vitorovic + */ + +#include "inetAddressUtil.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace epics::pvData; + +namespace epics { + namespace pvAccess { + + /* copied from EPICS v3 ca/iocinf.cpp + * removeDuplicateAddresses () + */ + void removeDuplicateAddresses(ELLLIST *pDestList, ELLLIST *pSrcList, + int silent) { + ELLNODE *pRawNode; + + while((pRawNode = ellGet(pSrcList))) { + STATIC_ASSERT(offsetof(osiSockAddrNode, node)==0); + osiSockAddrNode *pNode = + reinterpret_cast (pRawNode); + osiSockAddrNode *pTmpNode; + + if(pNode->addr.sa.sa_family==AF_INET) { + + pTmpNode = (osiSockAddrNode *)ellFirst (pDestList); // X aCC 749 + while(pTmpNode) { + if(pTmpNode->addr.sa.sa_family==AF_INET) { + if(pNode->addr.ia.sin_addr.s_addr + ==pTmpNode->addr.ia.sin_addr.s_addr + &&pNode->addr.ia.sin_port + ==pTmpNode->addr.ia.sin_port) { + if(!silent) { + char buf[64]; + ipAddrToDottedIP(&pNode->addr.ia, buf, + sizeof(buf)); + fprintf( + stderr, + "Warning: Duplicate EPICS CA Address list entry \"%s\" discarded\n", + buf); + } + free(pNode); + pNode = NULL; + break; + } + } + pTmpNode = (osiSockAddrNode *)ellNext (&pTmpNode->node); // X aCC 749 + } + if(pNode) { + ellAdd(pDestList, &pNode->node); + } + } + else { + ellAdd(pDestList, &pNode->node); + } + } + } + + InetAddrVector* getBroadcastAddresses(SOCKET sock) { + ELLLIST bcastList; + ELLLIST tmpList; + osiSockAddr addr; + + ellInit ( &bcastList ); // X aCC 392 + ellInit ( &tmpList ); // X aCC 392 + + addr.ia.sin_family = AF_UNSPEC; + osiSockDiscoverBroadcastAddresses(&bcastList, sock, &addr); + removeDuplicateAddresses(&tmpList, &bcastList, 1); + // forcePort ( &bcastList, port ); // if needed copy from ca/iocinf.cpp + + int size = ellCount(&bcastList ); + InetAddrVector* retVector = new InetAddrVector(size); + + ELLNODE *pRawNode; + + while((pRawNode = ellGet(&tmpList))) { + osiSockAddrNode *pNode = + reinterpret_cast (pRawNode); + osiSockAddr* posa = new osiSockAddr; + memcpy(posa, &(pNode->addr), sizeof(osiSockAddr)); + retVector->push_back(posa); + free(pNode); // using free because it is allocated by calloc + } + + return retVector; + } + + void encodeAsIPv6Address(ByteBuffer* buffer, const osiSockAddr* address) { + // IPv4 compatible IPv6 address + // first 80-bit are 0 + buffer->putLong(0); + buffer->putShort(0); + // next 16-bits are 1 + buffer->putShort(0xFFFF); + // following IPv4 address in big-endian (network) byte order + in_addr_t ipv4Addr = address->ia.sin_addr.s_addr; + buffer->putByte((int8)((ipv4Addr>>24)&0xFF)); + buffer->putByte((int8)((ipv4Addr>>16)&0xFF)); + buffer->putByte((int8)((ipv4Addr>>8)&0xFF)); + buffer->putByte((int8)(ipv4Addr&0xFF)); + } + + osiSockAddr* intToIPv4Address(int32 addr) { + osiSockAddr* ret = new osiSockAddr; + ret->ia.sin_family = AF_INET; + ret->ia.sin_addr.s_addr = (in_addr_t)addr; + ret->ia.sin_port = 0; + + return ret; + } + + int32 ipv4AddressToInt(const osiSockAddr& addr) { + return (int32)(addr.ia.sin_addr.s_addr); + } + + int32 parseInetAddress(const String addr) { + int32 retAddr; + + size_t dot = addr.find('.'); + if(dot==String::npos) THROW_BASE_EXCEPTION("Not an IPv4 address."); + int byte = atoi(addr.substr(0, dot).c_str()); + if(byte<0||byte>255) THROW_BASE_EXCEPTION("Not an IPv4 address."); + retAddr = byte; + + int num = dot+1; + dot = addr.find('.', num); + if(dot==String::npos) THROW_BASE_EXCEPTION("Not an IPv4 address."); + byte = atoi(addr.substr(num, dot-num).c_str()); + if(byte<0||byte>255) THROW_BASE_EXCEPTION("Not an IPv4 address."); + retAddr <<= 8; + retAddr |= byte; + + num = dot+1; + dot = addr.find('.', num); + if(dot==String::npos) THROW_BASE_EXCEPTION("Not an IPv4 address."); + byte = atoi(addr.substr(num, dot-num).c_str()); + if(byte<0||byte>255) THROW_BASE_EXCEPTION("Not an IPv4 address."); + retAddr <<= 8; + retAddr |= byte; + + num = dot+1; + byte = atoi(addr.substr(num).c_str()); + if(byte<0||byte>255) THROW_BASE_EXCEPTION("Not an IPv4 address."); + retAddr <<= 8; + retAddr |= byte; + + return retAddr; + } + + osiSockAddr* processAddressForList(String address, int defaultPort) { + // check port + int port = defaultPort; + size_t pos = address.find(':'); + if(pos!=String::npos) { + port = atoi(address.substr(pos+1).c_str()); + address = address.substr(0, pos); + } + + // add parsed address + osiSockAddr* addr = new osiSockAddr; + addr->ia.sin_family = AF_INET; + addr->ia.sin_port = port; + addr->ia.sin_addr.s_addr = parseInetAddress(address); + + return addr; + } + + InetAddrVector* getSocketAddressList(String list, int defaultPort, + const InetAddrVector* appendList) { + InetAddrVector* iav = new InetAddrVector(); + + // parse string + size_t subStart = 0; + size_t subEnd; + while((subEnd = list.find(' ', subStart))!=String::npos) { + String address = list.substr(subStart, (subEnd-subStart)); + + iav->push_back(processAddressForList(address, defaultPort)); + subStart = list.find_first_not_of(" \t\r\n\v", subEnd); + } + + if(subStart!=String::npos&&list.length()>0) iav->push_back( + processAddressForList(list.substr(subStart), defaultPort)); + + if(appendList!=NULL) { + for(size_t i = 0; isize(); i++) + iav->push_back(appendList->at(i)); + } + return iav; + } + + } +} diff --git a/pvAccessApp/utils/inetAddressUtil.h b/pvAccessApp/utils/inetAddressUtil.h new file mode 100644 index 0000000..5b8c687 --- /dev/null +++ b/pvAccessApp/utils/inetAddressUtil.h @@ -0,0 +1,87 @@ +/* + * inetAddressUtil.h + * + * Created on: Nov 12, 2010 + * Author: Miha Vitorovic + */ + +#ifndef INETADDRESSUTIL_H_ +#define INETADDRESSUTIL_H_ + +/* uporabim lahko: + * EPICSv3 osiSock.h kjer je definiran osiSockDiscoverBroadcastAddresses + * + * Kako se ga uporablja je v + * epics/base/src/ca/iocinf.cpp funkcija configureChannelAccessAddressList + * + * razišči kako se to priredi za IPv6 + * + */ + +#include +#include +#include +#include + +using namespace epics::pvData; + +namespace epics { + namespace pvAccess { + + typedef std::vector InetAddrVector; + + /** + * returns a vector containing all the IPv4 broadcast addresses + * on this machine. IPv6 doesn't have a local broadcast address. + * + * TODO Check implementation/rewrite this + */ + InetAddrVector* getBroadcastAddresses(SOCKET sock); + + /** + * Encode IPv4 address as IPv6 address. + * @param buffer byte-buffer where to put encoded data. + * @param address address to encode. + */ + void + encodeAsIPv6Address(ByteBuffer* buffer, + const osiSockAddr* address); + + /** + * Convert an integer into an IPv4 INET address. + * @param addr integer representation of a given address. + * @return IPv4 INET address. + */ + osiSockAddr* intToIPv4Address(int32 addr); + + /** + * Convert an IPv4 INET address to an integer. + * @param addr IPv4 INET address. + * @return integer representation of a given address. + */ + int32 ipv4AddressToInt(const osiSockAddr& addr); + + /** + * Parse space delimited addresss[:port] string and return array of InetSocketAddress. + * @param list space delimited addresss[:port] string. + * @param defaultPort port take if not specified. + * @param appendList list to be appended. + * @return array of InetSocketAddress. + */ + InetAddrVector* getSocketAddressList(String list, int defaultPort, + const InetAddrVector* appendList); + + /** + * Parse space delimited addresss[:port] string and return array of InetSocketAddress. + * @param list space delimited addresss[:port] string. + * @param defaultPort port take if not specified. + * @return array of InetSocketAddress. + */ + InetAddrVector* getSocketAddressList(String list, int defaultPort) { + return getSocketAddressList(list, defaultPort, NULL); + } + + } +} + +#endif /* INETADDRESSUTIL_H_ */