diff --git a/navrecv.cc b/navrecv.cc index 01d7da1..01672e3 100644 --- a/navrecv.cc +++ b/navrecv.cc @@ -16,6 +16,7 @@ #include "version.hh" #include #include "navmon.hh" +#include static char program[]="navrecv"; @@ -140,8 +141,94 @@ void writeToDisk(time_t s, uint64_t sourceid, std::string_view message) } } +// This is used to report clients, so we can log them +// The idea is that cleanup runs from the Sentinel which, when destroyed, will remove the entry +struct ClientKeeper +{ + struct ClientStatus + { + bool oldProtocol; + time_t lastMessage; + int station; + uint64_t messages{0}; + }; + + struct Sentinel + { + Sentinel(ClientKeeper* parent, const ComboAddress& us) : d_parent(parent), d_us(us) + { + } + + Sentinel(Sentinel&& s) + { + // cerr<<"Moved!"<remove(d_us); + } + else + ; //cerr<<" but we were moved already!\n"; + + } + void update(int station, bool oldProtocol) + { + time_t now = time(0); + std::lock_guard l(d_parent->d_mut); + ClientStatus& cs = d_parent->d_clients[d_us]; + cs.station = station; + cs.lastMessage = now; + cs.messages++; + cs.oldProtocol = oldProtocol; + } + ClientKeeper* d_parent; + ComboAddress d_us; + }; + + Sentinel reportClient(const ComboAddress& client) + { + Sentinel s2(this, client); + + std::lock_guard l(d_mut); + d_clients[client]; + return s2; + } + + void remove(const ComboAddress& client) + { + std::lock_guard l(d_mut); + d_clients.erase(client); + } + + void dump() + { + std::lock_guard l(d_mut); + string format("{:<50}{:<5}{:<10}{:<10}{:<10}\n"); + ofstream out("clients.bak"); + time_t now=time(0); + out<< fmt::format(format, "IP Address", "ID", "Protocol", "Messages", "Age"); + for(const auto& c : d_clients) { + out << fmt::format(format, c.first.toStringWithPort(), c.second.station, c.second.oldProtocol ? "Old" : "New", c.second.messages, now-c.second.lastMessage); + } + out.close(); + unlink("clients.txt"); + rename("clients.bak", "clients.txt"); + } + + map d_clients; + std::mutex d_mut; +}; + +ClientKeeper g_ckeeper; + // note that this moves the socket -void recvSession2(Socket&& uns, ComboAddress client) +void recvSession2(Socket&& uns, ComboAddress client, ClientKeeper::Sentinel& sentinel) { string secret = SRead(uns, 8); // ignored for now cerr << "Entering compressed session for "<