From 132ad1ae6fe7936cecab71c918b9bdcd0b1b83a5 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 16 Apr 2021 23:28:17 -0700 Subject: [PATCH] client: handle CMD_SEARCH_RESPONSE over TCP --- src/client.cpp | 160 +++++++++++++++++++++++++++-------------------- src/clientimpl.h | 1 + src/conn.cpp | 2 + src/conn.h | 1 + 4 files changed, 95 insertions(+), 69 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index e889169..1bb3cd7 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -536,6 +536,83 @@ void ContextImpl::onBeacon(const UDPManager::Beacon& msg) poke(false); } +static +void procSearchReply(ContextImpl& self, const SockAddr& src, Buffer& M, bool istcp) +{ + ServerGUID guid; + SockAddr serv(AF_INET); + uint16_t port = 0; + uint8_t found = 0u; + + _from_wire<12>(M, &guid[0], false); + // searchSequenceID + // we don't use this and instead rely on ID for individual PVs + M.skip(4u, __FILE__, __LINE__); + + from_wire(M, serv); + if(serv.isAny()) + serv = src; + from_wire(M, port); + if(istcp && port==0) + port = src.port(); + serv.setPort(port); + + if(M.size()<4u || M[0]!=3u || M[1]!='t' || M[2]!='c' || M[3]!='p') + return; + M.skip(4u, __FILE__, __LINE__); + + from_wire(M, found); + if(!found) + return; + + uint16_t nSearch = 0u; + from_wire(M, nSearch); + + for(auto n : range(nSearch)) { + (void)n; + + uint32_t id=0u; + from_wire(M, id); + if(!M.good()) + break; + + std::shared_ptr chan; + { + auto it = self.chanByCID.find(id); + if(it==self.chanByCID.end()) + continue; + + chan = it->second.lock(); + if(!chan) + continue; + } + + log_debug_printf(io, "Search reply for %s\n", chan->name.c_str()); + + if(chan->state==Channel::Searching) { + chan->guid = guid; + chan->replyAddr = serv; + + auto it = self.connByAddr.find(serv); + if(it==self.connByAddr.end() || !(chan->conn = it->second.lock())) { + self.connByAddr[serv] = chan->conn = std::make_shared(self.shared_from_this(), serv); + } + + chan->conn->pending.push_back(chan); + chan->state = Channel::Connecting; + + chan->conn->createChannels(); + + } else if(chan->guid!=guid) { + log_err_printf(duppv, "Duplicate PV name %s from %s and %s\n", + chan->name.c_str(), + chan->replyAddr.tostring().c_str(), + serv.tostring().c_str()); + } + } + +} + bool ContextImpl::onSearch() { searchMsg.resize(0x10000); @@ -597,75 +674,7 @@ bool ContextImpl::onSearch() } if(cmd==CMD_SEARCH_RESPONSE) { - ServerGUID guid; - SockAddr serv; - uint16_t port = 0; - uint8_t found = 0u; - - _from_wire<12>(M, &guid[0], false); - // searchSequenceID - // we don't use this and instead rely on ID for individual PVs - M.skip(4u, __FILE__, __LINE__); - - from_wire(M, serv); - if(serv.isAny()) - serv = src; - from_wire(M, port); - serv.setPort(port); - - if(M.size()<4u || M[0]!=3u || M[1]!='t' || M[2]!='c' || M[3]!='p') - return true; - M.skip(4u, __FILE__, __LINE__); - - from_wire(M, found); - if(!found) - return true; - - uint16_t nSearch = 0u; - from_wire(M, nSearch); - - for(auto n : range(nSearch)) { - (void)n; - - uint32_t id=0u; - from_wire(M, id); - if(!M.good()) - break; - - std::shared_ptr chan; - { - auto it = chanByCID.find(id); - if(it==chanByCID.end()) - continue; - - chan = it->second.lock(); - if(!chan) - continue; - } - - log_debug_printf(io, "Search reply for %s\n", chan->name.c_str()); - - if(chan->state==Channel::Searching) { - chan->guid = guid; - chan->replyAddr = serv; - - auto it = connByAddr.find(serv); - if(it==connByAddr.end() || !(chan->conn = it->second.lock())) { - connByAddr[serv] = chan->conn = std::make_shared(shared_from_this(), serv); - } - - chan->conn->pending.push_back(chan); - chan->state = Channel::Connecting; - - chan->conn->createChannels(); - - } else if(chan->guid!=guid) { - log_err_printf(duppv, "Duplicate PV name %s from %s and %s\n", - chan->name.c_str(), - chan->replyAddr.tostring().c_str(), - serv.tostring().c_str()); - } - } + procSearchReply(*this, src, M, false); } else { M.fault(__FILE__, __LINE__); @@ -680,6 +689,19 @@ bool ContextImpl::onSearch() return true; } +void Connection::handle_SEARCH_RESPONSE() +{ + EvInBuf M(peerBE, segBuf.get(), 16); + + procSearchReply(*context, peerAddr, M, true); + + if(!M.good()) { + log_crit_printf(io, "%s:%d Server %s sends invalid SEARCH_RESPONSE. Disconnecting...\n", + M.file(), M.line(), peerName.c_str()); + bev.reset(); + } +} + void ContextImpl::onSearchS(evutil_socket_t fd, short evt, void *raw) { try { diff --git a/src/clientimpl.h b/src/clientimpl.h index 78f1347..a6be356 100644 --- a/src/clientimpl.h +++ b/src/clientimpl.h @@ -108,6 +108,7 @@ struct Connection : public ConnBase, public std::enable_shared_from_this