common/recipes-core/rackmon2/rackmon/UnixSock.h (88 lines of code) (raw):

// Copyright 2021-present Facebook. All Rights Reserved. #pragma once #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> #include <atomic> #include <cstring> #include <list> #include <memory> #include <mutex> #include <string_view> #include <system_error> #include <tuple> #include <vector> namespace rackmonsvc { class UnixSock { protected: int sock_ = -1; std::tuple<struct sockaddr_un, size_t> getServiceAddr( const std::string& sockPath); int getServiceSock(); int createService(const std::string& sockPath); int createClient(const std::string& sockPath); void sendChunk(const char* buf, uint16_t bufLen); bool recvChunk(std::vector<char>& resp); public: explicit UnixSock(int fd) : sock_(fd) {} int getSock() const { return sock_; } virtual ~UnixSock(); void send(const char* buf, size_t len); void send(const std::vector<char>& buf) { send(buf.data(), buf.size()); } void recv(std::vector<char>& resp); }; class UnixServiceSock : public UnixSock { public: UnixServiceSock(const std::string& sockPath) : UnixSock(createService(sockPath)) {} }; class UnixClientSock : public UnixSock { public: UnixClientSock(const std::string& sockPath) : UnixSock(createClient(sockPath)) {} }; class UnixService { private: // The pipe used for the signal handler to request // for the loops to exit. int backChannelFDs_[2] = {-1, -1}; // End of the pipe used by the service loop. int& backChannelHandler_ = backChannelFDs_[0]; // End of the pipe to be used by the signal handler. int& backChannelRequestor_ = backChannelFDs_[1]; // The socket we want to receive connections from. std::unique_ptr<UnixServiceSock> sock_ = nullptr; const std::string sockPath_; void registerExitHandler(); void unregisterExitHandler(); void handleConnection(std::unique_ptr<UnixSock> sock); virtual void handleRequest(const std::vector<char>& req, UnixSock& cli) = 0; public: UnixService(const std::string& sockPath) : sockPath_(sockPath) {} virtual ~UnixService() {} // Request the doLoop to exit. void requestExit(); virtual void initialize(int /* argc */, char** /* argv */); virtual void deinitialize(); // The main service loop. This will block // till someone requests it to exit. void doLoop(); static std::mutex activeServiceListLock; static std::list<UnixService*> activeServiceList; static void triggerExit(int /* unused */); static void registerStaticExitHandler(); static void unregisterStaticExitHandler(); }; class UnixClient { UnixClientSock sock_; public: UnixClient(const std::string& sockPath) : sock_(sockPath) {} std::string request(const std::string& req) { sock_.send(req.data(), req.size()); std::vector<char> resp; sock_.recv(resp); return std::string(resp.begin(), resp.end()); } std::vector<char> request(const std::vector<char>& req) { sock_.send(req.data(), req.size()); std::vector<char> resp; sock_.recv(resp); return resp; } }; } // namespace rackmonsvc