diff --git a/src/clientconn.cpp b/src/clientconn.cpp index 2232166..437ecaa 100644 --- a/src/clientconn.cpp +++ b/src/clientconn.cpp @@ -15,7 +15,7 @@ namespace client { DEFINE_LOGGER(io, "pvxs.client.io"); Connection::Connection(const std::shared_ptr& context, const SockAddr& peerAddr) - :ConnBase (true, + :ConnBase (true, context->effective.sendBE(), bufferevent_socket_new(context->tcp_loop.base, -1, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS), peerAddr) ,context(context) diff --git a/src/conn.cpp b/src/conn.cpp index dfb28aa..c45d243 100644 --- a/src/conn.cpp +++ b/src/conn.cpp @@ -17,12 +17,12 @@ DEFINE_LOGGER(connio, "pvxs.tcp.io"); namespace pvxs { namespace impl { -ConnBase::ConnBase(bool isClient, bufferevent* bev, const SockAddr& peerAddr) +ConnBase::ConnBase(bool isClient, bool sendBE, bufferevent* bev, const SockAddr& peerAddr) :peerAddr(peerAddr) ,peerName(peerAddr.tostring()) ,bev(bev) ,isClient(isClient) - ,sendBE(EPICS_BYTE_ORDER==EPICS_ENDIAN_BIG) + ,sendBE(sendBE) ,peerBE(true) // arbitrary choice, default should be overwritten before use ,expectSeg(false) ,segCmd(0xff) diff --git a/src/conn.h b/src/conn.h index 5431d85..582989d 100644 --- a/src/conn.h +++ b/src/conn.h @@ -36,7 +36,7 @@ struct ConnBase size_t statTx{}, statRx{}; - ConnBase(bool isClient, bufferevent* bev, const SockAddr& peerAddr); + ConnBase(bool isClient, bool sendBE, bufferevent* bev, const SockAddr& peerAddr); ConnBase(const ConnBase&) = delete; ConnBase& operator=(const ConnBase&) = delete; virtual ~ConnBase(); diff --git a/src/pvxs/client.h b/src/pvxs/client.h index 56f6fa6..f87bf1a 100644 --- a/src/pvxs/client.h +++ b/src/pvxs/client.h @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -971,6 +972,10 @@ struct PVXS_API Config { //! @since 0.2.0 double tcpTimeout = 40.0; +private: + bool BE = EPICS_BYTE_ORDER==EPICS_ENDIAN_BIG; +public: + // compat static inline Config from_env() { return Config{}.applyEnv(); } @@ -1004,6 +1009,12 @@ struct PVXS_API Config { Context build() const { return Context(*this); } + +#ifdef PVXS_EXPERT_API_ENABLED + // for protocol compatibility testing + inline Config& overrideSendBE(bool be) { BE = be; return *this; } + inline bool sendBE() const { return BE; } +#endif }; PVXS_API diff --git a/src/pvxs/server.h b/src/pvxs/server.h index 948fe89..b3071fa 100644 --- a/src/pvxs/server.h +++ b/src/pvxs/server.h @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -172,6 +174,10 @@ struct PVXS_API Config { //! Server unique ID. Only meaningful in readback via Server::config() ServerGUID guid{}; +private: + bool BE = EPICS_BYTE_ORDER==EPICS_ENDIAN_BIG; +public: + // compat static inline Config from_env() { return Config{}.applyEnv(); } @@ -209,6 +215,12 @@ struct PVXS_API Config { inline Server build() const { return Server(*this); } + +#ifdef PVXS_EXPERT_API_ENABLED + // for protocol compatibility testing + inline Config& overrideSendBE(bool be) { BE = be; return *this; } + inline bool sendBE() const { return BE; } +#endif }; PVXS_API diff --git a/src/serverconn.cpp b/src/serverconn.cpp index 80d18a4..4e7c4ef 100644 --- a/src/serverconn.cpp +++ b/src/serverconn.cpp @@ -44,7 +44,7 @@ DEFINE_LOGGER(connio, "pvxs.tcp.io"); DEFINE_LOGGER(remote, "pvxs.remote.log"); ServerConn::ServerConn(ServIface* iface, evutil_socket_t sock, struct sockaddr *peer, int socklen) - :ConnBase(false, + :ConnBase(false, iface->server->effective.sendBE(), bufferevent_socket_new(iface->server->acceptor_loop.base, sock, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS), SockAddr(peer)) ,iface(iface) diff --git a/test/Makefile b/test/Makefile index 13ebb95..b51f28d 100644 --- a/test/Makefile +++ b/test/Makefile @@ -94,6 +94,10 @@ TESTPROD_HOST += test1000 test1000_SRCS += test1000.cpp TESTS += test1000 +TESTPROD_HOST += testendian +testendian_SRCS += testendian.cpp +TESTS += testendian + ifdef BASE_7_0 TESTPROD_HOST += benchdata diff --git a/test/testendian.cpp b/test/testendian.cpp new file mode 100644 index 0000000..9846938 --- /dev/null +++ b/test/testendian.cpp @@ -0,0 +1,73 @@ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * pvxs is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +#define PVXS_ENABLE_EXPERT_API + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace { +using namespace pvxs; + +void testEndian(bool srvBE, bool cliBE) +{ + testDiag("%s(%c, %c)", __func__, + srvBE ? 'B' : 'L', + cliBE ? 'B' : 'L'); + + const auto proto = nt::NTScalar{TypeCode::UInt32} + .create() + .update("value", 42); + + auto mbox(server::SharedPV::buildMailbox()); + + mbox.open(proto); + + auto srv = server::Config::isolated() + .overrideSendBE(srvBE) + .build() + .addPV("dut", mbox) + .start(); + + auto cli = srv.clientConfig() + .overrideSendBE(cliBE) + .build(); + + try { + auto val = cli.get("dut") + .exec() + ->wait(5.0); + + testEq(val["value"].as(), 42u); + }catch(std::exception& e){ + testFail("Unexpected exception: %s\n", e.what()); + } +} + +} // namespace + +MAIN(testendian) +{ + testPlan(4); + testSetup(); + logger_config_env(); + testEndian(false, false); + testEndian(false, true); + testEndian(true, false); + testEndian(true, true); + cleanup_for_valgrind(); + return testDone(); +}