aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/netliba/socket/creators.cpp
blob: 3821bf55b96c9a21deb362c9e1a1b357b8b62731 (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "stdafx.h"
#include <string.h>
#include <util/generic/utility.h>
#include <util/network/init.h>
#include <util/system/defaults.h>
#include <util/system/yassert.h>
#include "socket.h"

namespace NNetlibaSocket {
    void* CreateTos(const ui8 tos, void* buffer) {
#ifdef _win_
        *(int*)buffer = (int)tos;
#else
        // glibc bug: http://sourceware.org/bugzilla/show_bug.cgi?id=13500
        memset(buffer, 0, TOS_BUFFER_SIZE);

        msghdr dummy;
        Zero(dummy);
        dummy.msg_control = buffer;
        dummy.msg_controllen = TOS_BUFFER_SIZE;

        // TODO: in FreeBSD setting TOS for dual stack sockets does not affect ipv4 frames
        cmsghdr* cmsg = CMSG_FIRSTHDR(&dummy);
        cmsg->cmsg_level = IPPROTO_IPV6;
        cmsg->cmsg_type = IPV6_TCLASS;
        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
        memcpy(CMSG_DATA(cmsg), &tos, sizeof(tos)); // memcpy shut ups alias restrict warning

        Y_ASSERT(CMSG_NXTHDR(&dummy, cmsg) == nullptr);
#endif
        return buffer;
    }

    TMsgHdr* AddSockAuxData(TMsgHdr* header, const ui8 tos, const sockaddr_in6& myAddr, void* buffer, size_t bufferSize) {
#ifdef _win_
        Y_UNUSED(header);
        Y_UNUSED(tos);
        Y_UNUSED(myAddr);
        Y_UNUSED(buffer);
        Y_UNUSED(bufferSize);
        return nullptr;
#else
        header->msg_control = buffer;
        header->msg_controllen = bufferSize;

        size_t totalLen = 0;
#ifdef _cygwin_
        Y_UNUSED(tos);
#else
        // Cygwin does not support IPV6_TCLASS, so we ignore it
        cmsghdr* cmsgTos = CMSG_FIRSTHDR(header);
        if (cmsgTos == nullptr) {
            header->msg_control = nullptr;
            header->msg_controllen = 0;
            return nullptr;
        }
        cmsgTos->cmsg_level = IPPROTO_IPV6;
        cmsgTos->cmsg_type = IPV6_TCLASS;
        cmsgTos->cmsg_len = CMSG_LEN(sizeof(int));
        totalLen = CMSG_SPACE(sizeof(int));
        *(ui8*)CMSG_DATA(cmsgTos) = tos;
#endif

        if (*(ui64*)myAddr.sin6_addr.s6_addr != 0u) {
            in6_pktinfo* pktInfo;
#ifdef _cygwin_
            cmsghdr* cmsgAddr = CMSG_FIRSTHDR(header);
#else
            cmsghdr* cmsgAddr = CMSG_NXTHDR(header, cmsgTos);
#endif
            if (cmsgAddr == nullptr) {
                // leave only previous record
                header->msg_controllen = totalLen;
                return nullptr;
            }
            cmsgAddr->cmsg_level = IPPROTO_IPV6;
            cmsgAddr->cmsg_type = IPV6_PKTINFO;
            cmsgAddr->cmsg_len = CMSG_LEN(sizeof(*pktInfo));
            totalLen += CMSG_SPACE(sizeof(*pktInfo));
            pktInfo = (in6_pktinfo*)CMSG_DATA(cmsgAddr);

            pktInfo->ipi6_addr = myAddr.sin6_addr;
            pktInfo->ipi6_ifindex = 0; /* 0 = use interface specified in routing table */
        }
        header->msg_controllen = totalLen; //write right len

        return header;
#endif
    }

    TIoVec CreateIoVec(char* data, const size_t dataSize) {
        TIoVec result;
        Zero(result);

        result.iov_base = data;
        result.iov_len = dataSize;

        return result;
    }

    TMsgHdr CreateSendMsgHdr(const sockaddr_in6& addr, const TIoVec& iov, void* tosBuffer) {
        TMsgHdr result;
        Zero(result);

        result.msg_name = (void*)&addr;
        result.msg_namelen = sizeof(addr);
        result.msg_iov = (TIoVec*)&iov;
        result.msg_iovlen = 1;

        if (tosBuffer) {
#ifdef _win_
            result.Tos = *(int*)tosBuffer;
#else
            result.msg_control = tosBuffer;
            result.msg_controllen = TOS_BUFFER_SIZE;
#endif
        }

        return result;
    }

    TMsgHdr CreateRecvMsgHdr(sockaddr_in6* addrBuf, const TIoVec& iov, void* controllBuffer) {
        TMsgHdr result;
        Zero(result);

        Zero(*addrBuf);
        result.msg_name = addrBuf;
        result.msg_namelen = sizeof(*addrBuf);

        result.msg_iov = (TIoVec*)&iov;
        result.msg_iovlen = 1;
#ifndef _win_
        if (controllBuffer) {
            memset(controllBuffer, 0, CTRL_BUFFER_SIZE);
            result.msg_control = controllBuffer;
            result.msg_controllen = CTRL_BUFFER_SIZE;
        }
#endif
        return result;
    }
}