#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;
};