1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.quic;
17
18 import io.netty.util.concurrent.FastThreadLocal;
19 import org.jetbrains.annotations.Nullable;
20
21 import java.net.InetSocketAddress;
22 import java.nio.ByteBuffer;
23 import java.util.concurrent.TimeUnit;
24
25
26
27
28 final class QuicheSendInfo {
29
30 private static final FastThreadLocal<byte[]> IPV4_ARRAYS = new FastThreadLocal<byte[]>() {
31 @Override
32 protected byte[] initialValue() {
33 return new byte[SockaddrIn.IPV4_ADDRESS_LENGTH];
34 }
35 };
36
37 private static final FastThreadLocal<byte[]> IPV6_ARRAYS = new FastThreadLocal<byte[]>() {
38 @Override
39 protected byte[] initialValue() {
40 return new byte[SockaddrIn.IPV6_ADDRESS_LENGTH];
41 }
42 };
43
44 private static final byte[] TIMESPEC_ZEROOUT = new byte[Quiche.SIZEOF_TIMESPEC];
45
46 private QuicheSendInfo() { }
47
48
49
50
51
52
53
54 @Nullable
55 static InetSocketAddress getToAddress(ByteBuffer memory) {
56 return getAddress(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_TO_LEN, Quiche.QUICHE_SEND_INFO_OFFSETOF_TO);
57 }
58
59 @Nullable
60 static InetSocketAddress getFromAddress(ByteBuffer memory) {
61 return getAddress(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_FROM_LEN, Quiche.QUICHE_SEND_INFO_OFFSETOF_FROM);
62 }
63
64 @Nullable
65 private static InetSocketAddress getAddress(ByteBuffer memory, int lenOffset, int addressOffset) {
66 int position = memory.position();
67 try {
68 long len = getLen(memory, position + lenOffset);
69
70 memory.position(position + addressOffset);
71
72 if (len == Quiche.SIZEOF_SOCKADDR_IN) {
73 return SockaddrIn.getIPv4(memory, IPV4_ARRAYS.get());
74 }
75 assert len == Quiche.SIZEOF_SOCKADDR_IN6;
76 return SockaddrIn.getIPv6(memory, IPV6_ARRAYS.get(), IPV4_ARRAYS.get());
77 } finally {
78 memory.position(position);
79 }
80 }
81
82 private static long getLen(ByteBuffer memory, int index) {
83 return Quiche.getPrimitiveValue(memory, index, Quiche.SIZEOF_SOCKLEN_T);
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 static void setSendInfo(ByteBuffer memory, InetSocketAddress from, InetSocketAddress to) {
109 int position = memory.position();
110 try {
111 setAddress(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_FROM, Quiche.QUICHE_SEND_INFO_OFFSETOF_FROM_LEN, from);
112 setAddress(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_TO, Quiche.QUICHE_SEND_INFO_OFFSETOF_TO_LEN, to);
113
114 memory.position(position + Quiche.QUICHE_SEND_INFO_OFFSETOF_AT);
115 memory.put(TIMESPEC_ZEROOUT);
116 } finally {
117 memory.position(position);
118 }
119 }
120
121 private static void setAddress(ByteBuffer memory, int addrOffset, int lenOffset, InetSocketAddress addr) {
122 int position = memory.position();
123 try {
124 memory.position(position + addrOffset);
125 int len = SockaddrIn.setAddress(memory, addr);
126 Quiche.setPrimitiveValue(memory, position + lenOffset, Quiche.SIZEOF_SOCKLEN_T, len);
127 } finally {
128 memory.position(position);
129 }
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 static long getAtNanos(ByteBuffer memory) {
153 long sec = Quiche.getPrimitiveValue(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_AT +
154 Quiche.TIMESPEC_OFFSETOF_TV_SEC, Quiche.SIZEOF_TIME_T);
155 long nsec = Quiche.getPrimitiveValue(memory, Quiche.QUICHE_SEND_INFO_OFFSETOF_AT +
156 Quiche.TIMESPEC_OFFSETOF_TV_SEC, Quiche.SIZEOF_LONG);
157 return TimeUnit.SECONDS.toNanos(sec) + nsec;
158 }
159
160
161
162
163
164
165
166
167
168 static boolean isSameAddress(ByteBuffer memory, ByteBuffer memory2) {
169 return Quiche.isSameAddress(memory, memory2, Quiche.QUICHE_SEND_INFO_OFFSETOF_TO);
170 }
171 }