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