aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/actors/http/http_proxy_sock64.h
blob: 29b7b34b4775c345b13268e4008cf081f20d5422 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#pragma once
#include <util/network/sock.h>
#include "http.h"

class TInet64StreamSocket: public TStreamSocket {
protected:
    TInet64StreamSocket(const TInet64StreamSocket& parent, SOCKET fd)
        : TStreamSocket(fd)
        , AF(parent.AF)
    {
    }

public:
    TInet64StreamSocket(int af = {}) {
        CreateSocket(af);
    }

    std::shared_ptr<ISockAddr> MakeAddress(const TString& address, int port) {
        if (!address) {
            if (AF == AF_INET6) {
                return std::make_shared<TSockAddrInet6>("::", port);
            } else {
                return std::make_shared<TSockAddrInet>(INADDR_ANY, port);
            }
        }
        if (NHttp::IsIPv6(address)) {
            return std::make_shared<TSockAddrInet6>(address.data(), port);
        } else if (NHttp::IsIPv4(address)) {
            return std::make_shared<TSockAddrInet>(address.data(), port);
        }
        struct addrinfo hints = {
            .ai_flags = AI_PASSIVE,
            .ai_family = AF,
            .ai_socktype = SOCK_STREAM,
        };
        struct addrinfo* gai_res = nullptr;
        int gai_ret = getaddrinfo(address.data(), nullptr, &hints, &gai_res);
        std::shared_ptr<ISockAddr> result;
        if (gai_ret == 0 && gai_res->ai_addr) {
            switch (gai_res->ai_addr->sa_family) {
                case AF_INET6: {
                        std::shared_ptr<TSockAddrInet6> resultIp6 = std::make_shared<TSockAddrInet6>();
                        if (resultIp6->Size() >= gai_res->ai_addrlen) {
                            memcpy(resultIp6->SockAddr(), gai_res->ai_addr, gai_res->ai_addrlen);
                            resultIp6->SetPort(port);
                            result = std::move(resultIp6);
                        }
                    }
                    break;
                case AF_INET: {
                        std::shared_ptr<TSockAddrInet> resultIp4 = std::make_shared<TSockAddrInet>();
                        if (resultIp4->Size() >= gai_res->ai_addrlen) {
                            memcpy(resultIp4->SockAddr(), gai_res->ai_addr, gai_res->ai_addrlen);
                            resultIp4->SetPort(port);
                            result = std::move(resultIp4);
                        }
                    }
                    break;
            }
        }
        if (gai_res) {
            freeaddrinfo(gai_res);
        }
        if (result) {
            return result;
        }
        throw yexception() << "Unable to resolve address " << address;
    }

    static std::shared_ptr<ISockAddr> MakeAddress(const sockaddr_storage& storage) {
        std::shared_ptr<ISockAddr> addr;
        switch (storage.ss_family) {
            case AF_INET:
                addr = std::make_shared<TSockAddrInet>();
                break;
            case AF_INET6:
                addr = std::make_shared<TSockAddrInet6>();
                break;
        }
        if (addr) {
            memcpy(addr->SockAddr(), &storage, addr->Size());
        }
        return addr;
    }

    std::optional<TInet64StreamSocket> Accept(std::shared_ptr<ISockAddr>& acceptedAddr) {
        sockaddr_storage addrStorage = {};
        socklen_t addrLen = sizeof(addrStorage);
        SOCKET s = accept((SOCKET)*this, reinterpret_cast<sockaddr*>(&addrStorage), &addrLen);
        if (s == INVALID_SOCKET) {
            return {};
        }
        acceptedAddr = MakeAddress(addrStorage);
        return TInet64StreamSocket(*this, s);
    }

protected:
    int AF = AF_UNSPEC;

    void CreateSocket(int af) {
        SOCKET s;
        if (af == 0) {
            s = socket(AF = AF_INET6, SOCK_STREAM, 0);
            if (s < 0) {
                s = socket(AF = AF_INET, SOCK_STREAM, 0);
            }
        } else {
            s = socket(AF = af, SOCK_STREAM, 0);
        }
        if (AF == AF_INET6) {
            SetSockOpt(s, SOL_SOCKET, IPV6_V6ONLY, (int)false);
        }
        TSocketHolder sock(s);
        sock.Swap(*this);
    }
};