aboutsummaryrefslogblamecommitdiffstats
path: root/library/cpp/actors/interconnect/interconnect_resolve.cpp
blob: 14296194df9fccf5335b163c922df5c6ddfd22e7 (plain) (tree)












































































































































































                                                                                                               
#include "interconnect.h"
#include "interconnect_address.h"
#include "events_local.h"

#include <library/cpp/actors/core/actor_bootstrapped.h>
#include <library/cpp/actors/core/hfunc.h>
#include <library/cpp/actors/dnsresolver/dnsresolver.h>

namespace NActors {

    using namespace NActors::NDnsResolver;

    class TInterconnectResolveActor : public TActorBootstrapped<TInterconnectResolveActor> {
    public:
        TInterconnectResolveActor(
                const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
                const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
            : Host(host)
            , NodeId(nodeId)
            , Port(port)
            , DefaultAddress(defaultAddress)
            , ReplyTo(replyTo)
            , ReplyFrom(replyFrom)
            , Deadline(deadline)
        { }

        TInterconnectResolveActor(
                const TString& host, ui16 port,
                const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
            : Host(host)
            , Port(port)
            , ReplyTo(replyTo)
            , ReplyFrom(replyFrom)
            , Deadline(deadline)
        { }

        static constexpr EActivityType ActorActivityType() {
            return NAMESERVICE;
        }

        void Bootstrap() {
            TMaybe<TString> errorText;
            if (auto addr = ExtractDefaultAddr(errorText)) {
                return SendAddrAndDie(std::move(addr));
            }

            if (errorText) {
                SendErrorAndDie(*errorText);
            }

            auto now = TActivationContext::Now();
            if (Deadline < now) {
                SendErrorAndDie("Deadline");
                return;
            }

            Send(MakeDnsResolverActorId(),
                    new TEvDns::TEvGetAddr(Host, AF_UNSPEC),
                    IEventHandle::FlagTrackDelivery);

            if (Deadline != TInstant::Max()) {
                Schedule(Deadline, new TEvents::TEvWakeup);
            }

            Become(&TThis::StateWork);
        }

        STRICT_STFUNC(StateWork, {
            sFunc(TEvents::TEvWakeup, HandleTimeout);
            sFunc(TEvents::TEvUndelivered, HandleUndelivered);
            hFunc(TEvDns::TEvGetAddrResult, Handle);
        });

        void HandleTimeout() {
            SendErrorAndDie("Deadline");
        }

        void HandleUndelivered() {
            SendErrorAndDie("Dns resolver is unavailable");
        }

        void Handle(TEvDns::TEvGetAddrResult::TPtr& ev) {
            if (auto addr = ExtractAddr(ev->Get())) {
                return SendAddrAndDie(std::move(addr));
            }

            SendErrorAndDie(ev->Get()->ErrorText);
        }

        void SendAddrAndDie(NAddr::IRemoteAddrPtr addr) {
            if (NodeId) {
                auto reply = new TEvLocalNodeInfo;
                reply->NodeId = *NodeId;
                reply->Address = std::move(addr);
                TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
            } else {
                auto reply = new TEvAddressInfo;
                reply->Address = std::move(addr);
                TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
            }
            PassAway();
        }

        void SendErrorAndDie(const TString& errorText) {
            auto *event = new TEvResolveError;
            event->Explain = errorText;
            TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, event));
            PassAway();
        }

        NAddr::IRemoteAddrPtr ExtractAddr(TEvDns::TEvGetAddrResult* msg) {
            if (msg->Status == 0) {
                if (msg->IsV6()) {
                    struct sockaddr_in6 sin6;
                    Zero(sin6);
                    sin6.sin6_family = AF_INET6;
                    sin6.sin6_addr = msg->GetAddrV6();
                    sin6.sin6_port = HostToInet(Port);
                    return MakeHolder<NAddr::TIPv6Addr>(sin6);
                }

                if (msg->IsV4()) {
                    return MakeHolder<NAddr::TIPv4Addr>(TIpAddress(msg->GetAddrV4().s_addr, Port));
                }

                Y_FAIL("Unexpected result address family");
            }

            return nullptr;
        }

        NAddr::IRemoteAddrPtr ExtractDefaultAddr(TMaybe<TString>& errorText) {
            if (DefaultAddress) {
                NInterconnect::TAddress address(DefaultAddress.data(), Port);

                switch (address.GetFamily()) {
                case AF_INET:
                    return MakeHolder<NAddr::TIPv4Addr>(*(sockaddr_in*)address.SockAddr());
                case AF_INET6:
                    return MakeHolder<NAddr::TIPv6Addr>(*(sockaddr_in6*)address.SockAddr());
                default:
                    errorText = "Unsupported default address: " + DefaultAddress;
                    break;
                }
            }

            return nullptr;
        }

    private:
        const TString Host;
        const std::optional<ui32> NodeId;
        const ui16 Port;
        const TString DefaultAddress;
        const TActorId ReplyTo;
        const TActorId ReplyFrom;
        const TInstant Deadline;
    };

    IActor* CreateResolveActor(
        const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
        const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
    {
        return new TInterconnectResolveActor(host, port, nodeId, defaultAddress, replyTo, replyFrom, deadline);
    }

    IActor* CreateResolveActor(
        const TString& host, ui16 port,
        const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
    {
        return new TInterconnectResolveActor(host, port, replyTo, replyFrom, deadline);
    }

} // namespace NActors