From 84ac6ed0919a3ec097d37f37332fd06782b3f18c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 24 Oct 2019 10:38:25 -0700 Subject: [PATCH] move sockaddr wrapper to public API --- src/evhelper.cpp | 130 ++------------------------------------- src/evhelper.h | 55 +++-------------- src/pvxs/util.h | 47 ++++++++++++++ src/udp_collector.cpp | 10 +-- src/udp_collector.h | 6 +- src/util.cpp | 138 ++++++++++++++++++++++++++++++++++++++++++ test/testsock.cpp | 20 +++--- tools/pvxvct.cpp | 10 +-- 8 files changed, 220 insertions(+), 196 deletions(-) diff --git a/src/evhelper.cpp b/src/evhelper.cpp index 9a42bd2..8829de6 100644 --- a/src/evhelper.cpp +++ b/src/evhelper.cpp @@ -223,95 +223,7 @@ void evevent::add(const struct timeval *tv) throw std::runtime_error("event_add() fails"); } -evsockaddr::evsockaddr(int af) -{ - memset(&store, 0, sizeof(store)); - store.sa.sa_family = af; - if(af!=AF_INET && af!=AF_INET6 && af!=AF_UNSPEC) - throw std::invalid_argument("Unsupported address family"); -} - -unsigned short evsockaddr::port() const -{ - switch(store.sa.sa_family) { - case AF_INET: return ntohs(store.in.sin_port); - case AF_INET6:return ntohs(store.in6.sin6_port); - default: return 0; - } -} - -void evsockaddr::setPort(unsigned short port) -{ - switch(store.sa.sa_family) { - case AF_INET: store.in.sin_port = htons(port); break; - case AF_INET6:store.in6.sin6_port = htons(port); break; - default: - throw std::logic_error("evsockaddr: set family before port"); - } -} - -void evsockaddr::setAddress(const char *name) -{ - evsockaddr temp; - int templen = sizeof(temp.store); - if(evutil_parse_sockaddr_port(name, &temp->sa, &templen)) - throw std::runtime_error(std::string("Unable to parse as IP addresss: ")+name); - (*this) = temp; -} - -bool evsockaddr::isLO() const -{ - switch(store.sa.sa_family) { - case AF_INET: return store.in.sin_addr.s_addr==htonl(INADDR_LOOPBACK); - case AF_INET6: return IN6_IS_ADDR_LOOPBACK(&store.in6.sin6_addr); - default: return false; - } -} - -std::string evsockaddr::tostring() const -{ - std::ostringstream strm; - strm<<(*this); - return strm.str(); -} - -evsockaddr evsockaddr::any(int af, unsigned port) -{ - evsockaddr ret(af); - switch(af) { - case AF_INET: - ret->in.sin_addr.s_addr = htonl(INADDR_ANY); - ret->in.sin_port = htons(port); - break; - case AF_INET6: - ret->in6.sin6_addr = IN6ADDR_ANY_INIT; - ret->in6.sin6_port = htons(port); - break; - default: - throw std::invalid_argument("Unsupported address family"); - } - return ret; -} - -evsockaddr evsockaddr::loopback(int af, unsigned port) -{ - evsockaddr ret(af); - switch(af) { - case AF_INET: - ret->in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - ret->in.sin_port = htons(port); - break; - case AF_INET6: - ret->in6.sin6_addr = IN6ADDR_LOOPBACK_INIT; - ret->in6.sin6_port = htons(port); - break; - default: - throw std::invalid_argument("Unsupported address family"); - } - return ret; -} - -void to_wire(sbuf& buf, const evsockaddr& val, bool be) +void to_wire(sbuf& buf, const SockAddr &val, bool be) { if(buf.err || buf.size()<16) { buf.err = true; @@ -330,7 +242,7 @@ void to_wire(sbuf& buf, const evsockaddr& val, bool be) buf += 16; } -void from_wire(sbuf &buf, evsockaddr& val, bool be) +void from_wire(sbuf &buf, SockAddr& val, bool be) { if(buf.err || buf.size()<16) { buf.err = true; @@ -359,38 +271,6 @@ void from_wire(sbuf &buf, evsockaddr& val, bool be) buf += 16; } -std::ostream& operator<<(std::ostream& strm, const evsockaddr& addr) -{ - switch(addr->sa.sa_family) { - case AF_INET: { - char buf[INET_ADDRSTRLEN+1]; - if(evutil_inet_ntop(AF_INET, &addr->in.sin_addr, buf, sizeof(buf))) { - buf[sizeof(buf)-1] = '\0'; // paranoia - } else { - strm<<"<\?\?\?>"; - } - strm<in.sin_port); - break; - } - case AF_INET6: { - char buf[INET6_ADDRSTRLEN+1]; - if(evutil_inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, sizeof(buf))) { - buf[sizeof(buf)-1] = '\0'; // paranoia - } else { - strm<<"<\?\?\?>"; - } - strm<in6.sin6_port); - break; - } - case AF_UNSPEC: - strm<<"<>"; - break; - default: - strm<<"<\?\?\?>"; - } - return strm; -} - evsocket::evsocket(evutil_socket_t sock) :sock(sock) { @@ -430,7 +310,7 @@ evsocket::~evsocket() evutil_closesocket(sock); } -void evsocket::bind(evsockaddr& addr) const +void evsocket::bind(SockAddr& addr) const { int ret = ::bind(sock, &addr->sa, sizeof(addr.store)); if(ret!=0) @@ -442,7 +322,7 @@ void evsocket::bind(evsockaddr& addr) const log_printf(logerr, PLVL_ERR, "Unable to fetch address of newly bound socket\n"); } -void evsocket::mcast_join(const evsockaddr& grp, const evsockaddr& iface) const +void evsocket::mcast_join(const SockAddr& grp, const SockAddr& iface) const { if(grp.family()!=iface.family() || grp.family()!=AF_INET) throw std::invalid_argument("Unsupported address family"); @@ -481,7 +361,7 @@ void evsocket::mcast_loop(bool loop) const // IPV6_MULTICAST_LOOP } -void evsocket::mcast_iface(const evsockaddr& iface) const +void evsocket::mcast_iface(const SockAddr& iface) const { if(iface.family()!=AF_INET) throw std::invalid_argument("Unsupported address family"); diff --git a/src/evhelper.h b/src/evhelper.h index 4df64d6..1e7cb6d 100644 --- a/src/evhelper.h +++ b/src/evhelper.h @@ -17,6 +17,7 @@ #include #include +#include #include "pvaproto.h" @@ -72,53 +73,11 @@ struct PVXS_API evevent { void add(const timeval *tv=nullptr); }; -struct PVXS_API evsockaddr { - union store_t { - sockaddr sa; - sockaddr_in in; - sockaddr_in6 in6; - } store; - - evsockaddr() :evsockaddr(AF_UNSPEC) {} - explicit evsockaddr(int af); - - inline size_t size() const { return sizeof(store); } - - inline unsigned short family() const { return store.sa.sa_family; } - unsigned short port() const; - void setPort(unsigned short port); - - void setAddress(const char *); - - bool isLO() const; - - store_t* operator->() { return &store; } - const store_t* operator->() const { return &store; } - - std::string tostring() const; - - static evsockaddr any(int af, unsigned port=0); - static evsockaddr loopback(int af, unsigned port=0); - - inline bool operator<(const evsockaddr& o) const { - return evutil_sockaddr_cmp(&store.sa, &o.store.sa, true)<0; - } - inline bool operator==(const evsockaddr& o) const { - return evutil_sockaddr_cmp(&store.sa, &o.store.sa, true)==0; - } - inline bool operator!=(const evsockaddr& o) const { - return !(*this==o); - } -}; +PVXS_API +void to_wire(sbuf& buf, const SockAddr& val, bool be); PVXS_API -void to_wire(sbuf& buf, const evsockaddr& val, bool be); - -PVXS_API -void from_wire(sbuf& buf, evsockaddr& val, bool be); - -PVXS_API -std::ostream& operator<<(std::ostream& strm, const evsockaddr& addr); +void from_wire(sbuf& buf, SockAddr& val, bool be); struct PVXS_API evsocket { @@ -146,10 +105,10 @@ struct PVXS_API evsocket // test validity inline operator bool() const { return sock!=-1; } - void bind(evsockaddr& addr) const; + void bind(SockAddr& addr) const; //! join mcast group. Receive mcasts send to this group which arrive on the given interface //! @see IP_ADD_MEMBERSHIP - void mcast_join(const evsockaddr& grp, const evsockaddr& iface) const; + void mcast_join(const SockAddr& grp, const SockAddr& iface) const; //! Set time-to-live out mcasts sent from this socket //! @see IP_MULTICAST_TTL void mcast_ttl(unsigned ttl) const; @@ -158,7 +117,7 @@ struct PVXS_API evsocket void mcast_loop(bool loop) const; //! Selects interface to use when sending mcasts //! @see IP_MULTICAST_IF - void mcast_iface(const evsockaddr& iface) const; + void mcast_iface(const SockAddr& iface) const; }; } // namespace pvxsimpl diff --git a/src/pvxs/util.h b/src/pvxs/util.h index e702e85..69e2f90 100644 --- a/src/pvxs/util.h +++ b/src/pvxs/util.h @@ -10,6 +10,8 @@ #include #include +#include + #include namespace pvxs { @@ -45,6 +47,51 @@ inline detail::Escaper escape(const char* s) { return detail::Escaper(s); } +//! representation of a network address +struct PVXS_API SockAddr { + union store_t { + sockaddr sa; + sockaddr_in in; +#ifdef AF_INET6 + sockaddr_in6 in6; +#endif + } store; + + SockAddr() :SockAddr(AF_UNSPEC) {} + explicit SockAddr(int af); + + inline size_t size() const { return sizeof(store); } + + inline unsigned short family() const { return store.sa.sa_family; } + unsigned short port() const; + void setPort(unsigned short port); + + void setAddress(const char *); + + bool isLO() const; + + store_t* operator->() { return &store; } + const store_t* operator->() const { return &store; } + + std::string tostring() const; + + static SockAddr any(int af, unsigned port=0); + static SockAddr loopback(int af, unsigned port=0); + + inline bool operator<(const SockAddr& o) const { + return evutil_sockaddr_cmp(&store.sa, &o.store.sa, true)<0; + } + inline bool operator==(const SockAddr& o) const { + return evutil_sockaddr_cmp(&store.sa, &o.store.sa, true)==0; + } + inline bool operator!=(const SockAddr& o) const { + return !(*this==o); + } +}; + +PVXS_API +std::ostream& operator<<(std::ostream& strm, const SockAddr& addr); + } // namespace pvxs #endif // PVXS_UTIL_H diff --git a/src/udp_collector.cpp b/src/udp_collector.cpp index 881edc7..5ce2dbf 100644 --- a/src/udp_collector.cpp +++ b/src/udp_collector.cpp @@ -34,7 +34,7 @@ DEFINE_LOGGER(logsetup, "udp.setup"); struct UDPCollector : public std::enable_shared_from_this { const std::shared_ptr manager; - evsockaddr bind_addr; + SockAddr bind_addr; std::string name; evsocket sock; evevent rx; @@ -45,7 +45,7 @@ struct UDPCollector : public std::enable_shared_from_this std::set listeners; - UDPCollector(const std::shared_ptr& manager, const evsockaddr& bind_addr); + UDPCollector(const std::shared_ptr& manager, const SockAddr& bind_addr); ~UDPCollector(); void handle(short ev) @@ -158,7 +158,7 @@ struct UDPManager::Pvt : public std::enable_shared_from_this { evbase loop; // only manipulate from loop worker thread - std::map collectors; + std::map collectors; Pvt() :loop("PVXUDP", epicsThreadPriorityCAServerLow-4) @@ -170,7 +170,7 @@ struct UDPManager::Pvt : public std::enable_shared_from_this { } }; -UDPCollector::UDPCollector(const std::shared_ptr& manager, const evsockaddr& bind_addr) +UDPCollector::UDPCollector(const std::shared_ptr& manager, const SockAddr& bind_addr) :manager(manager) ,bind_addr(bind_addr) ,sock(bind_addr.family(), SOCK_DGRAM, 0) @@ -227,7 +227,7 @@ UDPManager UDPManager::instance() return UDPManager(ret); } -std::unique_ptr UDPManager::subscribe(evsockaddr& dest, +std::unique_ptr UDPManager::subscribe(SockAddr& dest, std::function&& cb) { if(!pvt) diff --git a/src/udp_collector.h b/src/udp_collector.h index 82f2266..8d2cd13 100644 --- a/src/udp_collector.h +++ b/src/udp_collector.h @@ -21,7 +21,7 @@ struct UDPManager; struct UDPMsg { //! peer (source) address - evsockaddr src; + SockAddr src; //! points to the first byte of each message in a packet, followed by an empty message const sbuf* msgs; @@ -43,7 +43,7 @@ struct PVXS_API UDPListener { private: friend struct UDPCollector; friend struct UDPManager; - evsockaddr dest; + SockAddr dest; std::shared_ptr collector; std::function cb; }; @@ -72,7 +72,7 @@ struct PVXS_API UDPManager * @param dest Address to bind this socket. Updated with actual address (cf. getsockname() ) after bind(). * @param cb Called for each valid packet */ - std::unique_ptr subscribe(evsockaddr& dest, + std::unique_ptr subscribe(SockAddr& dest, std::function&& cb); explicit operator bool() const { return !!pvt; } diff --git a/src/util.cpp b/src/util.cpp index cc25dc6..de4cdbf 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -5,6 +5,8 @@ */ #include +#include +#include #include @@ -59,6 +61,142 @@ std::ostream& operator<<(std::ostream& strm, const Escaper& esc) } +} // namespace detail + +SockAddr::SockAddr(int af) +{ + memset(&store, 0, sizeof(store)); + store.sa.sa_family = af; + if(af!=AF_INET +#ifdef AF_INET6 + && af!=AF_INET6 +#endif + && af!=AF_UNSPEC) + throw std::invalid_argument("Unsupported address family"); +} + +unsigned short SockAddr::port() const +{ + switch(store.sa.sa_family) { + case AF_INET: return ntohs(store.in.sin_port); +#ifdef AF_INET6 + case AF_INET6:return ntohs(store.in6.sin6_port); +#endif + default: return 0; + } +} + +void SockAddr::setPort(unsigned short port) +{ + switch(store.sa.sa_family) { + case AF_INET: store.in.sin_port = htons(port); break; +#ifdef AF_INET6 + case AF_INET6:store.in6.sin6_port = htons(port); break; +#endif + default: + throw std::logic_error("SockAddr: set family before port"); + } +} + +void SockAddr::setAddress(const char *name) +{ + SockAddr temp; + int templen = sizeof(temp.store); + if(evutil_parse_sockaddr_port(name, &temp->sa, &templen)) + throw std::runtime_error(std::string("Unable to parse as IP addresss: ")+name); + (*this) = temp; +} + +bool SockAddr::isLO() const +{ + switch(store.sa.sa_family) { + case AF_INET: return store.in.sin_addr.s_addr==htonl(INADDR_LOOPBACK); +#ifdef AF_INET6 + case AF_INET6: return IN6_IS_ADDR_LOOPBACK(&store.in6.sin6_addr); +#endif + default: return false; + } +} + +std::string SockAddr::tostring() const +{ + std::ostringstream strm; + strm<<(*this); + return strm.str(); +} + +SockAddr SockAddr::any(int af, unsigned port) +{ + SockAddr ret(af); + switch(af) { + case AF_INET: + ret->in.sin_addr.s_addr = htonl(INADDR_ANY); + ret->in.sin_port = htons(port); + break; +#ifdef AF_INET6 + case AF_INET6: + ret->in6.sin6_addr = IN6ADDR_ANY_INIT; + ret->in6.sin6_port = htons(port); + break; +#endif + default: + throw std::invalid_argument("Unsupported address family"); + } + return ret; +} + +SockAddr SockAddr::loopback(int af, unsigned port) +{ + SockAddr ret(af); + switch(af) { + case AF_INET: + ret->in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + ret->in.sin_port = htons(port); + break; +#ifdef AF_INET6 + case AF_INET6: + ret->in6.sin6_addr = IN6ADDR_LOOPBACK_INIT; + ret->in6.sin6_port = htons(port); + break; +#endif + default: + throw std::invalid_argument("Unsupported address family"); + } + return ret; +} + +std::ostream& operator<<(std::ostream& strm, const SockAddr& addr) +{ + switch(addr->sa.sa_family) { + case AF_INET: { + char buf[INET_ADDRSTRLEN+1]; + if(evutil_inet_ntop(AF_INET, &addr->in.sin_addr, buf, sizeof(buf))) { + buf[sizeof(buf)-1] = '\0'; // paranoia + } else { + strm<<"<\?\?\?>"; + } + strm<in.sin_port); + break; + } +#ifdef AF_INET6 + case AF_INET6: { + char buf[INET6_ADDRSTRLEN+1]; + if(evutil_inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, sizeof(buf))) { + buf[sizeof(buf)-1] = '\0'; // paranoia + } else { + strm<<"<\?\?\?>"; + } + strm<in6.sin6_port); + break; + } +#endif + case AF_UNSPEC: + strm<<"<>"; + break; + default: + strm<<"<\?\?\?>"; + } + return strm; } } diff --git a/test/testsock.cpp b/test/testsock.cpp index dfdfeca..630f441 100644 --- a/test/testsock.cpp +++ b/test/testsock.cpp @@ -25,12 +25,12 @@ void test_udp() evsocket A(AF_INET, SOCK_DGRAM, 0), B(AF_INET, SOCK_DGRAM, 0); - evsockaddr bind_addr(evsockaddr::loopback(AF_INET)); + SockAddr bind_addr(SockAddr::loopback(AF_INET)); A.bind(bind_addr); testNotEq(bind_addr.port(), 0)<<"bound port"; - evsockaddr send_addr(bind_addr); + SockAddr send_addr(bind_addr); send_addr.setPort(0); B.bind(send_addr); testNotEq(send_addr.port(), 0); @@ -41,7 +41,7 @@ void test_udp() testOk(ret==(int)sizeof(msg), "Send test ret==%d", ret); uint8_t rxbuf[8] = {}; - evsockaddr src; + SockAddr src; testDiag("Call recvfrom()"); socklen_t slen = src.size(); @@ -59,19 +59,19 @@ void test_local_mcast() evsocket A(AF_INET, SOCK_DGRAM, 0), B(AF_INET, SOCK_DGRAM, 0); - evsockaddr mcast_addr(AF_INET); + SockAddr mcast_addr(AF_INET); mcast_addr.setAddress("224.0.0.128"); #ifdef _WIN32 - evsockaddr bind_addr(evsockaddr::any(AF_INET)); + SockAddr bind_addr(SockAddr::any(AF_INET)); #else - evsockaddr bind_addr(mcast_addr); + SockAddr bind_addr(mcast_addr); #endif A.bind(bind_addr); mcast_addr.setPort(bind_addr.port()); - evsockaddr sender_addr(evsockaddr::loopback(AF_INET)); + SockAddr sender_addr(SockAddr::loopback(AF_INET)); B.bind(sender_addr); // receiving socket joins on the loopback interface @@ -87,7 +87,7 @@ void test_local_mcast() testEq(ret, (int)sizeof(msg))<<"Send test"; uint8_t rxbuf[8] = {}; - evsockaddr src; + SockAddr src; testDiag("Call recvfrom()"); socklen_t slen = src.size(); @@ -136,7 +136,7 @@ void test_from_wire() } { - evsockaddr val; + SockAddr val; const uint8_t buf[] = {0,0,0,0, 0,0,0,0, 0,0,0xff,0xff, 0x7f,0,0,1, 0xde, 0xad, 0xbe, 0xef}; sbuf pkt(buf, 16); @@ -175,7 +175,7 @@ void test_to_wire() } { - const evsockaddr val(evsockaddr::loopback(AF_INET)); + const SockAddr val(SockAddr::loopback(AF_INET)); uint8_t buf[16+4]; sbuf pkt(buf, 16); diff --git a/tools/pvxvct.cpp b/tools/pvxvct.cpp index 6cb366e..bf4ac8d 100644 --- a/tools/pvxvct.cpp +++ b/tools/pvxvct.cpp @@ -121,7 +121,7 @@ int main(int argc, char *argv[]) std::set pvnames; } opts; - std::vector bindaddrs; + std::vector bindaddrs; { int opt; @@ -141,7 +141,7 @@ int main(int argc, char *argv[]) opts.server = true; break; case 'B': { - pva::evsockaddr addr; + pva::SockAddr addr; int slen = addr.size(); if(evutil_parse_sockaddr_port(optarg, &addr->sa, &slen)) { throw std::runtime_error(pva::SB()<<"Expected address[:port] to bind. Not "<(M, guid, false);