#pragma once #include <library/cpp/logger/all.h> #include <util/generic/buffer.h> #include <util/generic/map.h> #include <util/generic/vector.h> #include <util/network/address.h> #include <util/network/ip.h> #include <util/network/socket.h> #include <util/system/mutex.h> #include <util/system/yassert.h> #include <cerrno> #include <util/generic/noncopyable.h> class TAddrList: public TVector<NAddr::IRemoteAddrRef> { private: using TBase = TVector<NAddr::IRemoteAddrRef>; public: //msvc doesn't support base class constructor inheritance TAddrList() = default; template <typename T> TAddrList(T&& arg) : TBase(std::forward<T>(arg)) { } template <typename T1, typename T2> TAddrList(T1&& arg1, T2&& arg2) : TBase(std::forward<T1>(arg1), std::forward<T2>(arg2)) { } TAddrList(std::initializer_list<NAddr::IRemoteAddrRef> list) : TBase(list) { } static TAddrList MakeV4Addr(ui32 ip, TIpPort port) { return TAddrList({new NAddr::TIPv4Addr(TIpAddress(htonl(ip), htons(port)))}); } std::pair<ui32, TIpPort> GetV4Addr() const { for (const auto& addrRef : *this) { const sockaddr* sa = addrRef->Addr(); if (sa->sa_family == AF_INET) { const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(sa); return std::make_pair(ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port)); } } return std::make_pair(0, 0); } }; class TSimpleSocketHandler { public: TSimpleSocketHandler() = default; int Good() const { return static_cast<bool>(Socket); } int Connect(const TAddrList& addrs, TDuration timeout) { try { for (const auto& item : addrs) { const sockaddr* sa = item->Addr(); TSocketHolder s(socket(sa->sa_family, SOCK_STREAM, 0)); if (s.Closed()) { continue; } #ifndef WIN32 if (fcntl(s, F_SETFD, FD_CLOEXEC)) // no inherit on fork()/exec() return errno ? errno : EBADF; #endif if (connect(s, sa, item->Len())) { s.Close(); continue; } Socket.Reset(new TSocket(s.Release())); Socket->SetSocketTimeout(timeout.Seconds(), timeout.MilliSecondsOfSecond()); Socket->SetZeroLinger(); Socket->SetKeepAlive(true); return 0; } } catch (...) { return EBADF; } return errno ? errno : EBADF; } void Disconnect() { if (!Socket) return; Socket->ShutDown(SHUT_RDWR); Socket.Destroy(); } void SetSocket(SOCKET fd) { Socket.Reset(new TSocket(fd)); } void shutdown() { Socket->ShutDown(SHUT_WR); } int send(const void* message, size_t messlen) { return ((ssize_t)messlen == Socket->Send(message, messlen)); } int peek() { char buf[1]; return (1 == recv(*Socket, buf, 1, MSG_PEEK)); } ssize_t read(void* buffer, size_t buflen) { return Socket->Recv(buffer, buflen); } THolder<TSocket> PickOutSocket() { return std::move(Socket); } protected: THolder<TSocket> Socket; };