1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#include "network.h"
4
5#include "config.h"
6#include "huffman.h"
7
8#include <base/system.h>
9#include <base/types.h>
10
11#include <engine/shared/protocolglue.h>
12
13const unsigned char SECURITY_TOKEN_MAGIC[4] = {'T', 'K', 'E', 'N'};
14
15SECURITY_TOKEN ToSecurityToken(const unsigned char *pData)
16{
17 return bytes_be_to_uint(bytes: pData);
18}
19
20void WriteSecurityToken(unsigned char *pData, SECURITY_TOKEN Token)
21{
22 uint_to_bytes_be(bytes: pData, value: Token);
23}
24
25void CNetRecvUnpacker::Clear()
26{
27 m_Valid = false;
28}
29
30void CNetRecvUnpacker::Start(const NETADDR *pAddr, CNetConnection *pConnection, int ClientId)
31{
32 m_Addr = *pAddr;
33 m_pConnection = pConnection;
34 m_ClientId = ClientId;
35 m_CurrentChunk = 0;
36 m_Valid = true;
37}
38
39// TODO: rename this function
40int CNetRecvUnpacker::FetchChunk(CNetChunk *pChunk)
41{
42 CNetChunkHeader Header;
43 unsigned char *pEnd = m_Data.m_aChunkData + m_Data.m_DataSize;
44
45 while(true)
46 {
47 unsigned char *pData = m_Data.m_aChunkData;
48
49 // check for old data to unpack
50 if(!m_Valid || m_CurrentChunk >= m_Data.m_NumChunks)
51 {
52 Clear();
53 return 0;
54 }
55
56 // TODO: add checking here so we don't read too far
57 for(int i = 0; i < m_CurrentChunk; i++)
58 {
59 pData = Header.Unpack(pData, Split: (m_pConnection && m_pConnection->m_Sixup) ? 6 : 4);
60 pData += Header.m_Size;
61 }
62
63 // unpack the header
64 pData = Header.Unpack(pData, Split: (m_pConnection && m_pConnection->m_Sixup) ? 6 : 4);
65 m_CurrentChunk++;
66
67 if(pData + Header.m_Size > pEnd)
68 {
69 Clear();
70 return 0;
71 }
72
73 // handle sequence stuff
74 if(m_pConnection && (Header.m_Flags & NET_CHUNKFLAG_VITAL))
75 {
76 // anti spoof: ignore unknown sequence
77 if(Header.m_Sequence == (m_pConnection->m_Ack + 1) % NET_MAX_SEQUENCE || m_pConnection->m_UnknownSeq)
78 {
79 m_pConnection->m_UnknownSeq = false;
80
81 // in sequence
82 m_pConnection->m_Ack = Header.m_Sequence;
83 }
84 else
85 {
86 // old packet that we already got
87 if(CNetBase::IsSeqInBackroom(Seq: Header.m_Sequence, Ack: m_pConnection->m_Ack))
88 continue;
89
90 // out of sequence, request resend
91 if(g_Config.m_Debug)
92 dbg_msg(sys: "conn", fmt: "asking for resend %d %d", Header.m_Sequence, (m_pConnection->m_Ack + 1) % NET_MAX_SEQUENCE);
93 m_pConnection->SignalResend();
94 continue; // take the next chunk in the packet
95 }
96 }
97
98 // fill in the info
99 pChunk->m_ClientId = m_ClientId;
100 pChunk->m_Address = m_Addr;
101 pChunk->m_Flags = Header.m_Flags;
102 pChunk->m_DataSize = Header.m_Size;
103 pChunk->m_pData = pData;
104 return 1;
105 }
106}
107
108bool CNetBase::IsValidConnectionOrientedPacket(const CNetPacketConstruct *pPacket)
109{
110 if((pPacket->m_Flags & ~(NET_PACKETFLAG_CONTROL | NET_PACKETFLAG_RESEND | NET_PACKETFLAG_COMPRESSION)) != 0)
111 {
112 return false;
113 }
114
115 if((pPacket->m_Flags & NET_PACKETFLAG_CONTROL) != 0)
116 {
117 // At least one byte is required as the control message code in control packets.
118 // Control packets always contain zero chunks and are never compressed.
119 return pPacket->m_NumChunks == 0 &&
120 pPacket->m_DataSize > 0 &&
121 (pPacket->m_Flags & NET_PACKETFLAG_COMPRESSION) == 0;
122 }
123
124 // Packets are allowed to contain no chunks if they are used to request a resend,
125 // otherwise at least one chunk is required or the packet would have no effect.
126 const int MinChunks = (pPacket->m_Flags & NET_PACKETFLAG_RESEND) != 0 ? 0 : 1;
127 return pPacket->m_NumChunks >= MinChunks &&
128 pPacket->m_NumChunks <= NET_MAX_PACKET_CHUNKS;
129}
130
131static const unsigned char NET_HEADER_EXTENDED[] = {'x', 'e'};
132// packs the data tight and sends it
133void CNetBase::SendPacketConnless(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize, bool Extended, unsigned char aExtra[NET_CONNLESS_EXTRA_SIZE])
134{
135 unsigned char aBuffer[NET_MAX_PACKETSIZE];
136 static constexpr int DATA_OFFSET = sizeof(NET_HEADER_EXTENDED) + NET_CONNLESS_EXTRA_SIZE;
137 dbg_assert(DataSize <= (int)sizeof(aBuffer) - DATA_OFFSET,
138 "Invalid DataSize for CNetBase::SendPacketConnless: %d > %d", DataSize, (int)sizeof(aBuffer) - DATA_OFFSET);
139
140 if(Extended)
141 {
142 mem_copy(dest: aBuffer, source: NET_HEADER_EXTENDED, size: sizeof(NET_HEADER_EXTENDED));
143 mem_copy(dest: aBuffer + sizeof(NET_HEADER_EXTENDED), source: aExtra, size: NET_CONNLESS_EXTRA_SIZE);
144 }
145 else
146 {
147 std::fill(first: aBuffer, last: aBuffer + DATA_OFFSET, value: 0xFF);
148 }
149 mem_copy(dest: aBuffer + DATA_OFFSET, source: pData, size: DataSize);
150 net_udp_send(sock: Socket, addr: pAddr, data: aBuffer, size: DataSize + DATA_OFFSET);
151}
152
153void CNetBase::SendPacketConnlessWithToken7(NETSOCKET Socket, NETADDR *pAddr, const void *pData, int DataSize, SECURITY_TOKEN Token, SECURITY_TOKEN ResponseToken)
154{
155 unsigned char aBuffer[NET_MAX_PACKETSIZE];
156 static constexpr int DATA_OFFSET = 1 + 2 * sizeof(SECURITY_TOKEN);
157 dbg_assert(DataSize <= (int)sizeof(aBuffer) - DATA_OFFSET,
158 "Invalid DataSize for CNetBase::SendPacketConnlessWithToken7: %d > %d", DataSize, (int)sizeof(aBuffer) - DATA_OFFSET);
159
160 aBuffer[0] = (NET_PACKETFLAG_CONNLESS << 2) | 1;
161 WriteSecurityToken(pData: aBuffer + 1, Token);
162 WriteSecurityToken(pData: aBuffer + 1 + sizeof(SECURITY_TOKEN), Token: ResponseToken);
163 mem_copy(dest: aBuffer + DATA_OFFSET, source: pData, size: DataSize);
164 net_udp_send(sock: Socket, addr: pAddr, data: aBuffer, size: DataSize + DATA_OFFSET);
165}
166
167void CNetBase::SendPacket(NETSOCKET Socket, NETADDR *pAddr, CNetPacketConstruct *pPacket, SECURITY_TOKEN SecurityToken, bool Sixup)
168{
169 dbg_assert(IsValidConnectionOrientedPacket(pPacket), "Invalid packet to send. Flags=%d Ack=%d NumChunks=%d Size=%d",
170 pPacket->m_Flags, pPacket->m_Ack, pPacket->m_NumChunks, pPacket->m_DataSize);
171 dbg_assert((pPacket->m_Flags & NET_PACKETFLAG_COMPRESSION) == 0, "Do not set NET_PACKETFLAG_COMPRESSION, it will be set automatically when appropriate");
172
173 unsigned char aBuffer[NET_MAX_PACKETSIZE];
174
175 // log the data
176 if(ms_DataLogSent)
177 {
178 int Type = 1;
179 io_write(io: ms_DataLogSent, buffer: &Type, size: sizeof(Type));
180 io_write(io: ms_DataLogSent, buffer: &pPacket->m_DataSize, size: sizeof(pPacket->m_DataSize));
181 io_write(io: ms_DataLogSent, buffer: &pPacket->m_aChunkData, size: pPacket->m_DataSize);
182 io_flush(io: ms_DataLogSent);
183 }
184
185 int HeaderSize = NET_PACKETHEADERSIZE;
186 if(Sixup)
187 {
188 HeaderSize += sizeof(SecurityToken);
189 WriteSecurityToken(pData: aBuffer + 3, Token: SecurityToken);
190 }
191 else if(SecurityToken != NET_SECURITY_TOKEN_UNSUPPORTED)
192 {
193 // append security token
194 // if SecurityToken is NET_SECURITY_TOKEN_UNKNOWN we will still append it hoping to negotiate it
195 WriteSecurityToken(pData: pPacket->m_aChunkData + pPacket->m_DataSize, Token: SecurityToken);
196 pPacket->m_DataSize += sizeof(SecurityToken);
197 }
198
199 // only compress non-control packets
200 int CompressedSize = -1;
201 if((pPacket->m_Flags & NET_PACKETFLAG_CONTROL) == 0)
202 {
203 CompressedSize = ms_Huffman.Compress(pInput: pPacket->m_aChunkData, InputSize: pPacket->m_DataSize, pOutput: &aBuffer[HeaderSize], OutputSize: NET_MAX_PACKETSIZE - HeaderSize);
204 }
205
206 // check if the compression was enabled, successful and good enough
207 int FinalSize;
208 if(CompressedSize > 0 && CompressedSize < pPacket->m_DataSize)
209 {
210 FinalSize = CompressedSize;
211 pPacket->m_Flags |= NET_PACKETFLAG_COMPRESSION;
212 }
213 else
214 {
215 // use uncompressed data
216 FinalSize = pPacket->m_DataSize;
217 mem_copy(dest: &aBuffer[HeaderSize], source: pPacket->m_aChunkData, size: pPacket->m_DataSize);
218 }
219
220 if(Sixup)
221 {
222 pPacket->m_Flags = PacketFlags_SixToSeven(Flags: pPacket->m_Flags);
223 }
224
225 // set header and send the packet if all things are good
226 if(FinalSize >= 0)
227 {
228 FinalSize += HeaderSize;
229 aBuffer[0] = ((pPacket->m_Flags << 2) & 0xfc) | ((pPacket->m_Ack >> 8) & 0x3);
230 aBuffer[1] = pPacket->m_Ack & 0xff;
231 aBuffer[2] = pPacket->m_NumChunks;
232 net_udp_send(sock: Socket, addr: pAddr, data: aBuffer, size: FinalSize);
233
234 // log raw socket data
235 if(ms_DataLogSent)
236 {
237 int Type = 0;
238 io_write(io: ms_DataLogSent, buffer: &Type, size: sizeof(Type));
239 io_write(io: ms_DataLogSent, buffer: &FinalSize, size: sizeof(FinalSize));
240 io_write(io: ms_DataLogSent, buffer: aBuffer, size: FinalSize);
241 io_flush(io: ms_DataLogSent);
242 }
243 }
244}
245
246std::optional<int> CNetBase::UnpackPacketFlags(unsigned char *pBuffer, int Size)
247{
248 if(Size < NET_PACKETHEADERSIZE || Size > NET_MAX_PACKETSIZE)
249 {
250 return std::nullopt;
251 }
252 return pBuffer[0] >> 2;
253}
254
255// TODO: rename this function
256int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket, bool &Sixup, SECURITY_TOKEN *pSecurityToken, SECURITY_TOKEN *pResponseToken)
257{
258 std::optional<int> Flags = UnpackPacketFlags(pBuffer, Size);
259 if(!Flags)
260 {
261 return -1;
262 }
263
264 // log the data
265 if(ms_DataLogRecv)
266 {
267 int Type = 0;
268 io_write(io: ms_DataLogRecv, buffer: &Type, size: sizeof(Type));
269 io_write(io: ms_DataLogRecv, buffer: &Size, size: sizeof(Size));
270 io_write(io: ms_DataLogRecv, buffer: pBuffer, size: Size);
271 io_flush(io: ms_DataLogRecv);
272 }
273
274 // read the packet
275 pPacket->m_Flags = *Flags;
276
277 if(pPacket->m_Flags & NET_PACKETFLAG_CONNLESS)
278 {
279 Sixup = (pBuffer[0] & 0x3) == 1;
280 if(Sixup && (pSecurityToken == nullptr || pResponseToken == nullptr))
281 return -1;
282 int Offset = Sixup ? 9 : 6;
283 if(Size < Offset)
284 return -1;
285
286 if(Sixup)
287 {
288 *pSecurityToken = ToSecurityToken(pData: pBuffer + 1);
289 *pResponseToken = ToSecurityToken(pData: pBuffer + 5);
290 }
291
292 pPacket->m_Flags = NET_PACKETFLAG_CONNLESS;
293 pPacket->m_Ack = 0;
294 pPacket->m_NumChunks = 0;
295 pPacket->m_DataSize = Size - Offset;
296 mem_copy(dest: pPacket->m_aChunkData, source: pBuffer + Offset, size: pPacket->m_DataSize);
297
298 if(!Sixup && mem_comp(a: pBuffer, b: NET_HEADER_EXTENDED, size: sizeof(NET_HEADER_EXTENDED)) == 0)
299 {
300 pPacket->m_Flags |= NET_PACKETFLAG_EXTENDED;
301 mem_copy(dest: pPacket->m_aExtraData, source: pBuffer + sizeof(NET_HEADER_EXTENDED), size: sizeof(pPacket->m_aExtraData));
302 }
303 }
304 else
305 {
306 if(pPacket->m_Flags & NET_PACKETFLAG_UNUSED)
307 Sixup = true;
308 if(Sixup && pSecurityToken == nullptr)
309 return -1;
310 int DataStart = Sixup ? 7 : NET_PACKETHEADERSIZE;
311 if(Size < DataStart)
312 return -1;
313
314 pPacket->m_Ack = ((pBuffer[0] & 0x3) << 8) | pBuffer[1];
315 pPacket->m_NumChunks = pBuffer[2];
316 pPacket->m_DataSize = Size - DataStart;
317
318 if(Sixup)
319 {
320 pPacket->m_Flags = PacketFlags_SevenToSix(Flags: pPacket->m_Flags);
321 *pSecurityToken = ToSecurityToken(pData: pBuffer + 3);
322 }
323
324 if(!IsValidConnectionOrientedPacket(pPacket))
325 {
326 return -1;
327 }
328
329 if((pPacket->m_Flags & NET_PACKETFLAG_COMPRESSION) != 0)
330 {
331 pPacket->m_DataSize = ms_Huffman.Decompress(pInput: &pBuffer[DataStart], InputSize: pPacket->m_DataSize, pOutput: pPacket->m_aChunkData, OutputSize: sizeof(pPacket->m_aChunkData));
332 if(pPacket->m_DataSize < 0)
333 {
334 return -1;
335 }
336 }
337 else
338 {
339 mem_copy(dest: pPacket->m_aChunkData, source: &pBuffer[DataStart], size: pPacket->m_DataSize);
340 }
341 }
342
343 // set the response token (a bit hacky because this function shouldn't know about control packets)
344 if(pPacket->m_Flags & NET_PACKETFLAG_CONTROL)
345 {
346 if(pPacket->m_DataSize >= 1 + (int)sizeof(SECURITY_TOKEN)) // control byte + token
347 {
348 if(pPacket->m_aChunkData[0] == NET_CTRLMSG_CONNECT || (Sixup && pPacket->m_aChunkData[0] == protocol7::NET_CTRLMSG_TOKEN))
349 {
350 *pResponseToken = ToSecurityToken(pData: &pPacket->m_aChunkData[1]);
351 }
352 }
353 }
354
355 // log the data
356 if(ms_DataLogRecv)
357 {
358 int Type = 1;
359 io_write(io: ms_DataLogRecv, buffer: &Type, size: sizeof(Type));
360 io_write(io: ms_DataLogRecv, buffer: &pPacket->m_DataSize, size: sizeof(pPacket->m_DataSize));
361 io_write(io: ms_DataLogRecv, buffer: pPacket->m_aChunkData, size: pPacket->m_DataSize);
362 io_flush(io: ms_DataLogRecv);
363 }
364
365 // return success
366 return 0;
367}
368
369void CNetBase::SendControlMsg(NETSOCKET Socket, NETADDR *pAddr, int Ack, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken, bool Sixup)
370{
371 CNetPacketConstruct Construct;
372 Construct.m_Flags = NET_PACKETFLAG_CONTROL;
373 Construct.m_Ack = Ack;
374 Construct.m_NumChunks = 0;
375 Construct.m_DataSize = 1 + ExtraSize;
376 Construct.m_aChunkData[0] = ControlMsg;
377 if(pExtra)
378 mem_copy(dest: &Construct.m_aChunkData[1], source: pExtra, size: ExtraSize);
379
380 CNetBase::SendPacket(Socket, pAddr, pPacket: &Construct, SecurityToken, Sixup);
381}
382
383void CNetBase::SendControlMsgWithToken7(NETSOCKET Socket, NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, TOKEN MyToken, bool Extended)
384{
385 dbg_assert((Token & ~NET_TOKEN_MASK) == 0, "token out of range");
386 dbg_assert((MyToken & ~NET_TOKEN_MASK) == 0, "resp token out of range");
387
388 unsigned char aRequestTokenBuf[NET_TOKENREQUEST_DATASIZE] = {};
389 aRequestTokenBuf[0] = (MyToken >> 24) & 0xff;
390 aRequestTokenBuf[1] = (MyToken >> 16) & 0xff;
391 aRequestTokenBuf[2] = (MyToken >> 8) & 0xff;
392 aRequestTokenBuf[3] = (MyToken) & 0xff;
393 const int Size = Extended ? sizeof(aRequestTokenBuf) : sizeof(TOKEN);
394 CNetBase::SendControlMsg(Socket, pAddr, Ack, ControlMsg, pExtra: aRequestTokenBuf, ExtraSize: Size, SecurityToken: Token, Sixup: true);
395}
396
397unsigned char *CNetChunkHeader::Pack(unsigned char *pData, int Split) const
398{
399 pData[0] = ((m_Flags & 3) << 6) | ((m_Size >> Split) & 0x3f);
400 pData[1] = (m_Size & ((1 << Split) - 1));
401 if(m_Flags & NET_CHUNKFLAG_VITAL)
402 {
403 pData[1] |= (m_Sequence >> 2) & (~((1 << Split) - 1));
404 pData[2] = m_Sequence & 0xff;
405 return pData + 3;
406 }
407 return pData + 2;
408}
409
410unsigned char *CNetChunkHeader::Unpack(unsigned char *pData, int Split)
411{
412 m_Flags = (pData[0] >> 6) & 3;
413 m_Size = ((pData[0] & 0x3f) << Split) | (pData[1] & ((1 << Split) - 1));
414 m_Sequence = -1;
415 if(m_Flags & NET_CHUNKFLAG_VITAL)
416 {
417 m_Sequence = ((pData[1] & (~((1 << Split) - 1))) << 2) | pData[2];
418 return pData + 3;
419 }
420 return pData + 2;
421}
422
423bool CNetBase::IsSeqInBackroom(int Seq, int Ack)
424{
425 int Bottom = (Ack - NET_MAX_SEQUENCE / 2);
426 if(Bottom < 0)
427 {
428 if(Seq <= Ack)
429 return true;
430 if(Seq >= (Bottom + NET_MAX_SEQUENCE))
431 return true;
432 }
433 else
434 {
435 if(Seq <= Ack && Seq >= Bottom)
436 return true;
437 }
438
439 return false;
440}
441
442IOHANDLE CNetBase::ms_DataLogSent = nullptr;
443IOHANDLE CNetBase::ms_DataLogRecv = nullptr;
444CHuffman CNetBase::ms_Huffman;
445
446void CNetBase::OpenLog(IOHANDLE DataLogSent, IOHANDLE DataLogRecv)
447{
448 if(DataLogSent)
449 {
450 ms_DataLogSent = DataLogSent;
451 dbg_msg(sys: "network", fmt: "logging sent packages");
452 }
453 else
454 dbg_msg(sys: "network", fmt: "failed to start logging sent packages");
455
456 if(DataLogRecv)
457 {
458 ms_DataLogRecv = DataLogRecv;
459 dbg_msg(sys: "network", fmt: "logging recv packages");
460 }
461 else
462 dbg_msg(sys: "network", fmt: "failed to start logging recv packages");
463}
464
465void CNetBase::CloseLog()
466{
467 if(ms_DataLogSent)
468 {
469 dbg_msg(sys: "network", fmt: "stopped logging sent packages");
470 io_close(io: ms_DataLogSent);
471 ms_DataLogSent = nullptr;
472 }
473
474 if(ms_DataLogRecv)
475 {
476 dbg_msg(sys: "network", fmt: "stopped logging recv packages");
477 io_close(io: ms_DataLogRecv);
478 ms_DataLogRecv = nullptr;
479 }
480}
481
482int CNetBase::Compress(const void *pData, int DataSize, void *pOutput, int OutputSize)
483{
484 return ms_Huffman.Compress(pInput: pData, InputSize: DataSize, pOutput, OutputSize);
485}
486
487int CNetBase::Decompress(const void *pData, int DataSize, void *pOutput, int OutputSize)
488{
489 return ms_Huffman.Decompress(pInput: pData, InputSize: DataSize, pOutput, OutputSize);
490}
491
492void CNetBase::Init()
493{
494 ms_Huffman.Init();
495}
496
497void CNetTokenCache::Init(NETSOCKET Socket)
498{
499 m_Socket = Socket;
500}
501
502void CNetTokenCache::SendPacketConnless(CNetChunk *pChunk)
503{
504 TOKEN Token = GetToken(pAddr: &pChunk->m_Address);
505
506 if(Token != NET_TOKEN_NONE)
507 {
508 CNetBase::SendPacketConnlessWithToken7(Socket: m_Socket, pAddr: &pChunk->m_Address, pData: pChunk->m_pData, DataSize: pChunk->m_DataSize, Token, ResponseToken: GenerateToken());
509 }
510 else
511 {
512 FetchToken(pAddr: &pChunk->m_Address);
513
514 CConnlessPacketInfo ConnlessPacket;
515 ConnlessPacket.m_Addr = pChunk->m_Address;
516 ConnlessPacket.m_Addr.type = pChunk->m_Address.type & ~(NETTYPE_IPV4 | NETTYPE_IPV6);
517 mem_copy(dest: ConnlessPacket.m_aData, source: pChunk->m_pData, size: pChunk->m_DataSize);
518 ConnlessPacket.m_DataSize = pChunk->m_DataSize;
519 ConnlessPacket.m_Expiry = time_get() + time_freq() * NET_TOKENCACHE_PACKETEXPIRY;
520
521 unsigned int NetType = pChunk->m_Address.type;
522 auto SavePacketFor = [&](unsigned int Type) {
523 if(NetType & Type)
524 {
525 ConnlessPacket.m_Addr.type |= Type;
526 m_ConnlessPackets.push_back(x: ConnlessPacket);
527 ConnlessPacket.m_Addr.type &= ~Type;
528 }
529 };
530
531 SavePacketFor(NETTYPE_IPV4);
532 SavePacketFor(NETTYPE_IPV6);
533 }
534}
535
536void CNetTokenCache::FetchToken(NETADDR *pAddr)
537{
538 CNetBase::SendControlMsgWithToken7(Socket: m_Socket, pAddr, Token: NET_TOKEN_NONE, Ack: 0, ControlMsg: protocol7::NET_CTRLMSG_TOKEN, MyToken: GenerateToken(), Extended: true);
539}
540
541void CNetTokenCache::AddToken(const NETADDR *pAddr, TOKEN Token)
542{
543 if(Token == NET_TOKEN_NONE)
544 return;
545
546 NETADDR NullAddr = NETADDR_ZEROED;
547 NullAddr.port = pAddr->port;
548 NullAddr.type = (pAddr->type & ~(NETTYPE_WEBSOCKET_IPV4 | NETTYPE_WEBSOCKET_IPV6)) | NETTYPE_LINK_BROADCAST;
549
550 for(auto Iter = m_ConnlessPackets.begin(); Iter != m_ConnlessPackets.end();)
551 {
552 if(Iter->m_Addr == NullAddr)
553 {
554 CNetBase::SendPacketConnlessWithToken7(Socket: m_Socket, pAddr: &Iter->m_Addr, pData: Iter->m_aData, DataSize: Iter->m_DataSize, Token, ResponseToken: GenerateToken());
555
556 Iter = m_ConnlessPackets.erase(position: Iter);
557 }
558 else
559 {
560 Iter++;
561 }
562 }
563
564 CAddressInfo Info;
565 Info.m_Addr = *pAddr,
566 Info.m_Token = Token,
567 Info.m_Expiry = time_get() + (time_freq() * NET_TOKENCACHE_ADDRESSEXPIRY);
568
569 m_TokenCache.push_back(x: Info);
570}
571
572TOKEN CNetTokenCache::GetToken(const NETADDR *pAddr)
573{
574 for(const auto &AddrInfo : m_TokenCache)
575 {
576 if(AddrInfo.m_Addr == *pAddr)
577 {
578 return AddrInfo.m_Token;
579 }
580 }
581
582 return NET_TOKEN_NONE;
583}
584
585TOKEN CNetTokenCache::GenerateToken()
586{
587 TOKEN Token;
588 secure_random_fill(bytes: &Token, length: sizeof(Token));
589 return Token;
590}
591
592void CNetTokenCache::Update()
593{
594 int64_t Now = time_get();
595
596 m_TokenCache.erase(
597 first: std::remove_if(first: m_TokenCache.begin(), last: m_TokenCache.end(), pred: [&](const CAddressInfo &Info) {
598 return Info.m_Expiry <= Now;
599 }),
600 last: m_TokenCache.end());
601
602 m_ConnlessPackets.erase(
603 first: std::remove_if(first: m_ConnlessPackets.begin(), last: m_ConnlessPackets.end(), pred: [&](CConnlessPacketInfo &Packet) {
604 return Packet.m_Expiry <= Now;
605 }),
606 last: m_ConnlessPackets.end());
607}
608