FreeRDP
Loading...
Searching...
No Matches
TestRdpUdp.c
1
18/* The client side of RDP-UDP against a server played by the test over a loopback socket.
19 *
20 * Nothing in rdpudp.c is opened up for this: the test answers the SYN, sends the datagrams a
21 * Windows server would, and reads what the client delivers through its receive callback and
22 * sends back on the wire. */
23
24#include <stdio.h>
25#include <string.h>
26
27#include <winpr/wtypes.h>
28#include <winpr/crt.h>
29#include <winpr/stream.h>
30#include <winpr/synch.h>
31#include <winpr/sysinfo.h>
32#include <winpr/winsock.h>
33#include <winpr/wlog.h>
34
35#if !defined(_WIN32)
36#include <sys/socket.h>
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#endif
40
41#include "../rdpudp.h"
42
43#define TAG "com.freerdp.core.test.rdpudp"
44
45/* [MS-RDPEUDP] 2.2.2.1 uFlags */
46#define FLAG_SYN 0x0001
47#define FLAG_ACK 0x0004
48#define FLAG_SYNEX 0x1000
49
50/* [MS-RDPEUDP2] 2.2.1.1 Flags */
51#define V3_ACK 0x001
52#define V3_DATA 0x004
53#define V3_ACKVEC 0x008
54#define V3_AOA 0x010
55#define V3_OVERHEADSIZE 0x040
56#define V3_DELAYACKINFO 0x100
57
58#define V3_TYPE_STANDARD 0
59#define V3_TYPE_DUMMY 8
60
61#define SYN_LENGTH 1232
62#define FIRST_SEQUENCE 100
63
64#define CHECK(cond) \
65 do \
66 { \
67 if (!(cond)) \
68 { \
69 (void)fprintf(stderr, "%s:%d: check failed: %s\n", __FILE__, __LINE__, #cond); \
70 goto fail; \
71 } \
72 } while (0)
73
74/* A datagram the client sent, decoded. */
75typedef struct
76{
77 UINT16 flags;
78 BYTE logWindow;
79 UINT16 ack;
80 BOOL hasAoA;
81 UINT16 aoa;
82 BOOL hasData;
83 UINT16 dataSeq;
84 UINT16 channelSeq;
85 BYTE payload[64];
86 size_t payloadLength;
87 UINT16 vecBase;
88 BYTE vec[127];
89 size_t vecLength;
90} V3Packet;
91
92#define MAX_SEEN 256
93
94typedef struct
95{
96 SOCKET server;
97 struct sockaddr_in serverAddr;
98 rdpUdp* udp;
99 wStream* delivered;
100
101 /* what the client sent since the last drain, the newest MAX_SEEN of it */
102 V3Packet seen[MAX_SEEN];
103 size_t seenCount;
104} TestCtx;
105
106/* ---------------------------------------------------------------------------------------- */
107/* The server's socket */
108/* ---------------------------------------------------------------------------------------- */
109
110static BOOL on_receive(void* custom, const BYTE* data, size_t length)
111{
112 TestCtx* ctx = custom;
113 if (!Stream_EnsureRemainingCapacity(ctx->delivered, length))
114 return FALSE;
115 Stream_Write(ctx->delivered, data, length);
116 return TRUE;
117}
118
119static BOOL server_open(TestCtx* ctx)
120{
121 ctx->server = _socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
122 if (ctx->server == INVALID_SOCKET)
123 return FALSE;
124
125 struct sockaddr_in addr = WINPR_C_ARRAY_INIT;
126 addr.sin_family = AF_INET;
127 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
128 addr.sin_port = 0;
129 if (_bind(ctx->server, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
130 return FALSE;
131
132 socklen_t length = sizeof(ctx->serverAddr);
133 if (_getsockname(ctx->server, (struct sockaddr*)&ctx->serverAddr, &length) != 0)
134 return FALSE;
135
136 u_long arg = 1;
137 return _ioctlsocket(ctx->server, FIONBIO, &arg) == 0;
138}
139
140/* One datagram from the client, waiting up to timeoutMs for it. 0 when none came. */
141static size_t server_recv(TestCtx* ctx, BYTE* buffer, size_t size, UINT32 timeoutMs)
142{
143 const UINT64 deadline = GetTickCount64() + timeoutMs;
144 while (TRUE)
145 {
146 const int rc = _recv(ctx->server, (char*)buffer, (int)size, 0);
147 if (rc > 0)
148 return (size_t)rc;
149 if (GetTickCount64() >= deadline)
150 return 0;
151 Sleep(1);
152 }
153}
154
155static BOOL server_send_raw(TestCtx* ctx, const BYTE* data, size_t length)
156{
157 return _send(ctx->server, (const char*)data, (int)length, 0) == (int)length;
158}
159
160/* Lets the client read what arrived and run its timers. */
161static BOOL pump(TestCtx* ctx)
162{
163 Sleep(1);
164 return rdpudp_check(ctx->udp);
165}
166
167/* ---------------------------------------------------------------------------------------- */
168/* RDP-UDP2 packets ([MS-RDPEUDP2] 2.2.1) */
169/* ---------------------------------------------------------------------------------------- */
170
171static void write_uint24(wStream* s, UINT32 value)
172{
173 Stream_Write_UINT8(s, (BYTE)(value & 0xFF));
174 Stream_Write_UINT8(s, (BYTE)((value >> 8) & 0xFF));
175 Stream_Write_UINT8(s, (BYTE)((value >> 16) & 0xFF));
176}
177
178/* What the test server puts in one packet. */
179typedef struct
180{
181 BOOL dummy;
182 BOOL hasAck;
183 UINT16 ack;
184 BOOL hasDelayAck;
185 BYTE maxDelayedAcks;
186 UINT16 delayedAckTimeout;
187 BOOL hasAoA;
188 UINT16 aoa;
189 BOOL hasData;
190 UINT16 dataSeq;
191 UINT16 channelSeq;
192 const BYTE* payload;
193 size_t payloadLength;
194} V3Out;
195
196/* Encodes the packet the way Windows puts it on the wire: prefix byte in front, a short layout
197 * padded to 7 bytes, then the first and eighth byte swapped. */
198static BOOL server_send_v3(TestCtx* ctx, const V3Out* out)
199{
200 BYTE wire[1500] = WINPR_C_ARRAY_INIT;
201 wStream sbuffer = WINPR_C_ARRAY_INIT;
202 wStream* s = Stream_StaticInit(&sbuffer, wire, sizeof(wire));
203
204 UINT16 flags = 0;
205 if (out->hasAck)
206 flags |= V3_ACK;
207 if (out->hasDelayAck)
208 flags |= V3_DELAYACKINFO;
209 if (out->hasAoA)
210 flags |= V3_AOA;
211 if (out->hasData)
212 flags |= V3_DATA;
213
214 Stream_Seek(s, 1); /* the prefix byte */
215 Stream_Write_UINT16(s, (UINT16)(flags | (15u << 12)));
216 if (out->hasAck)
217 {
218 Stream_Write_UINT16(s, out->ack); /* SeqNum */
219 write_uint24(s, 0); /* receivedTS */
220 Stream_Write_UINT8(s, 0); /* sendAckTimeGapInMs */
221 Stream_Write_UINT8(s, 0); /* numDelayedAcks */
222 }
223 if (out->hasDelayAck)
224 {
225 Stream_Write_UINT8(s, out->maxDelayedAcks); /* MaxDelayedAcks */
226 Stream_Write_UINT16(s, out->delayedAckTimeout); /* DelayedAckTimeoutInMs */
227 }
228 if (out->hasAoA)
229 Stream_Write_UINT16(s, out->aoa);
230 if (out->hasData)
231 {
232 Stream_Write_UINT16(s, out->dataSeq);
233 Stream_Write_UINT16(s, out->channelSeq);
234 Stream_Write(s, out->payload, out->payloadLength);
235 }
236
237 const size_t layout = Stream_GetPosition(s) - 1;
238 BYTE shortLength = 7;
239 if (layout < 7)
240 {
241 shortLength = (BYTE)layout;
242 Stream_Zero(s, 7 - layout);
243 }
244 const size_t length = Stream_GetPosition(s);
245 const BYTE type = out->dummy ? V3_TYPE_DUMMY : V3_TYPE_STANDARD;
246 wire[0] = (BYTE)((shortLength << 5) | (type << 1));
247 const BYTE eighth = wire[7];
248 wire[7] = wire[0];
249 wire[0] = eighth;
250 return server_send_raw(ctx, wire, length);
251}
252
253static BOOL send_data(TestCtx* ctx, UINT16 dataSeq, UINT16 channelSeq, const char* text)
254{
255 const V3Out out = { .hasData = TRUE,
256 .dataSeq = dataSeq,
257 .channelSeq = channelSeq,
258 .payload = (const BYTE*)text,
259 .payloadLength = strlen(text) };
260 return server_send_v3(ctx, &out);
261}
262
263static BOOL send_aoa(TestCtx* ctx, UINT16 aoa)
264{
265 const V3Out out = { .hasAoA = TRUE, .aoa = aoa };
266 return server_send_v3(ctx, &out);
267}
268
269static BOOL send_ack(TestCtx* ctx, UINT16 ack)
270{
271 const V3Out out = { .hasAck = TRUE, .ack = ack };
272 return server_send_v3(ctx, &out);
273}
274
275static BOOL parse_v3(const BYTE* wire, size_t length, V3Packet* packet)
276{
277 BYTE buffer[1500] = WINPR_C_ARRAY_INIT;
278 if ((length < 8) || (length > sizeof(buffer)))
279 return FALSE;
280 memcpy(buffer, wire, length);
281 const BYTE eighth = buffer[7];
282 buffer[7] = buffer[0];
283 buffer[0] = eighth;
284
285 memset(packet, 0, sizeof(*packet));
286 const BYTE prefix = buffer[0];
287 const BYTE shortLength = prefix >> 5;
288 if (shortLength < 7)
289 length = 1ull + shortLength;
290
291 wStream sbuffer = WINPR_C_ARRAY_INIT;
292 wStream* s = Stream_StaticConstInit(&sbuffer, buffer + 1, length - 1);
293 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
294 return FALSE;
295 const UINT16 header = Stream_Get_UINT16(s);
296 packet->flags = header & 0x0FFF;
297 packet->logWindow = (BYTE)(header >> 12);
298
299 if (packet->flags & V3_ACK)
300 {
301 if (!Stream_CheckAndLogRequiredLength(TAG, s, 7))
302 return FALSE;
303 packet->ack = Stream_Get_UINT16(s);
304 Stream_Seek(s, 4); /* receivedTS, sendAckTimeGapInMs */
305 const size_t delayed = Stream_Get_UINT8(s) & 0x0F;
306 if (!Stream_SafeSeek(s, delayed))
307 return FALSE;
308 }
309 if ((packet->flags & V3_OVERHEADSIZE) && !Stream_SafeSeek(s, 1))
310 return FALSE;
311 if ((packet->flags & V3_DELAYACKINFO) && !Stream_SafeSeek(s, 3))
312 return FALSE;
313 if (packet->flags & V3_AOA)
314 {
315 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
316 return FALSE;
317 packet->hasAoA = TRUE;
318 packet->aoa = Stream_Get_UINT16(s);
319 }
320 if (packet->flags & V3_DATA)
321 {
322 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
323 return FALSE;
324 packet->dataSeq = Stream_Get_UINT16(s);
325 }
326 if (packet->flags & V3_ACKVEC)
327 {
328 if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
329 return FALSE;
330 packet->vecBase = Stream_Get_UINT16(s);
331 const BYTE control = Stream_Get_UINT8(s);
332 if ((control & 0x80) && !Stream_SafeSeek(s, 4)) /* TimeStamp, SendAckTimeGapInMs */
333 return FALSE;
334 packet->vecLength = control & 0x7F;
335 if (!Stream_CheckAndLogRequiredLength(TAG, s, packet->vecLength))
336 return FALSE;
337 Stream_Read(s, packet->vec, packet->vecLength);
338 }
339 if (packet->flags & V3_DATA)
340 {
341 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
342 return FALSE;
343 packet->hasData = TRUE;
344 packet->channelSeq = Stream_Get_UINT16(s);
345 packet->payloadLength = Stream_GetRemainingLength(s);
346 if (packet->payloadLength > sizeof(packet->payload))
347 packet->payloadLength = sizeof(packet->payload);
348 Stream_Read(s, packet->payload, packet->payloadLength);
349 }
350 return TRUE;
351}
352
353/* Reads everything the client sent, until nothing more arrives for waitMs. */
354static BOOL drain(TestCtx* ctx, UINT32 waitMs)
355{
356 BYTE buffer[1500] = WINPR_C_ARRAY_INIT;
357 ctx->seenCount = 0;
358 size_t length = 0;
359 while ((length = server_recv(ctx, buffer, sizeof(buffer), waitMs)) > 0)
360 {
361 V3Packet packet = WINPR_C_ARRAY_INIT;
362 if (!parse_v3(buffer, length, &packet))
363 return FALSE;
364 if (ctx->seenCount == MAX_SEEN)
365 {
366 memmove(&ctx->seen[0], &ctx->seen[1], sizeof(ctx->seen[0]) * (MAX_SEEN - 1));
367 ctx->seenCount--;
368 }
369 ctx->seen[ctx->seenCount++] = packet;
370 }
371 return TRUE;
372}
373
374/* Reads what the client sent until want DATA packets are in, or timeoutMs passed. */
375static BOOL collect_data(TestCtx* ctx, size_t want, UINT32 timeoutMs)
376{
377 BYTE buffer[1500] = WINPR_C_ARRAY_INIT;
378 ctx->seenCount = 0;
379 size_t count = 0;
380 while (count < want)
381 {
382 const size_t length = server_recv(ctx, buffer, sizeof(buffer), timeoutMs);
383 if (length == 0)
384 return FALSE;
385 if (ctx->seenCount == MAX_SEEN)
386 return FALSE;
387 V3Packet* packet = &ctx->seen[ctx->seenCount++];
388 if (!parse_v3(buffer, length, packet))
389 return FALSE;
390 if (packet->hasData)
391 count++;
392 }
393 return TRUE;
394}
395
396/* The newest acknowledgement the client sent, ACK or ACK vector. */
397static const V3Packet* last_ack(const TestCtx* ctx)
398{
399 for (size_t x = ctx->seenCount; x > 0; x--)
400 {
401 const V3Packet* packet = &ctx->seen[x - 1];
402 if (packet->flags & (V3_ACK | V3_ACKVEC))
403 return packet;
404 }
405 return nullptr;
406}
407
408static size_t count_data(const TestCtx* ctx)
409{
410 size_t count = 0;
411 for (size_t x = 0; x < ctx->seenCount; x++)
412 {
413 if (ctx->seen[x].hasData)
414 count++;
415 }
416 return count;
417}
418
419static const V3Packet* first_data(const TestCtx* ctx)
420{
421 for (size_t x = 0; x < ctx->seenCount; x++)
422 {
423 if (ctx->seen[x].hasData)
424 return &ctx->seen[x];
425 }
426 return nullptr;
427}
428
429static BOOL delivered_is(const TestCtx* ctx, const char* expected)
430{
431 const size_t length = strlen(expected);
432 return (Stream_GetPosition(ctx->delivered) == length) &&
433 (memcmp(Stream_Buffer(ctx->delivered), expected, length) == 0);
434}
435
436/* What was delivered after the first offset bytes. */
437static BOOL delivered_tail_is(const TestCtx* ctx, size_t offset, const char* expected)
438{
439 const size_t length = strlen(expected);
440 return (Stream_GetPosition(ctx->delivered) == offset + length) &&
441 (memcmp(Stream_Buffer(ctx->delivered) + offset, expected, length) == 0);
442}
443
444/* ---------------------------------------------------------------------------------------- */
445/* Connection setup */
446/* ---------------------------------------------------------------------------------------- */
447
448static const BYTE cookieHash[32] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
449 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
450 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
451 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA };
452
453typedef struct
454{
455 size_t length;
456 UINT16 flags;
457 UINT32 initialSequence;
458 UINT16 version;
459 BYTE cookie[32];
460} SynInfo;
461
462static void ctx_free(TestCtx* ctx)
463{
464 rdpudp_free(ctx->udp);
465 if (ctx->server != INVALID_SOCKET)
466 closesocket(ctx->server);
467 Stream_Free(ctx->delivered, TRUE);
468 memset(ctx, 0, sizeof(*ctx));
469 ctx->server = INVALID_SOCKET;
470}
471
472/* Starts the client and reads its SYN, the connection is left in SYN_SENT. */
473static BOOL ctx_start(TestCtx* ctx, BOOL offerV3, SynInfo* syn)
474{
475 memset(ctx, 0, sizeof(*ctx));
476 ctx->server = INVALID_SOCKET;
477 ctx->delivered = Stream_New(nullptr, 1024);
478 if (!ctx->delivered || !server_open(ctx))
479 return FALSE;
480
481 ctx->udp = rdpudp_new(WLog_Get(TAG), offerV3 ? cookieHash : nullptr, on_receive, ctx);
482 if (!ctx->udp)
483 return FALSE;
484 if (!rdpudp_connect(ctx->udp, (const struct sockaddr*)&ctx->serverAddr,
485 sizeof(ctx->serverAddr)))
486 return FALSE;
487
488 BYTE buffer[1500] = WINPR_C_ARRAY_INIT;
489 struct sockaddr_in from = WINPR_C_ARRAY_INIT;
490 int fromLength = sizeof(from);
491 const UINT64 deadline = GetTickCount64() + 1000;
492 int rc = -1;
493 while ((rc = _recvfrom(ctx->server, (char*)buffer, sizeof(buffer), 0, (struct sockaddr*)&from,
494 &fromLength)) <= 0)
495 {
496 if (GetTickCount64() >= deadline)
497 return FALSE;
498 Sleep(1);
499 }
500 if (_connect(ctx->server, (const struct sockaddr*)&from, fromLength) != 0)
501 return FALSE;
502
503 wStream sbuffer = WINPR_C_ARRAY_INIT;
504 wStream* s = Stream_StaticConstInit(&sbuffer, buffer, (size_t)rc);
505 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
506 return FALSE;
507 syn->length = (size_t)rc;
508 Stream_Seek(s, 6); /* snSourceAck, uReceiveWindowSize */
509 syn->flags = Stream_Get_UINT16_BE(s);
510 syn->initialSequence = Stream_Get_UINT32_BE(s);
511 Stream_Seek(s, 6); /* MTUs, uSynExFlags */
512 syn->version = Stream_Get_UINT16_BE(s);
513 if (Stream_GetRemainingLength(s) >= sizeof(syn->cookie))
514 Stream_Read(s, syn->cookie, sizeof(syn->cookie));
515 return TRUE;
516}
517
518static BOOL send_syn_ack(TestCtx* ctx, UINT32 acknowledged, UINT16 version)
519{
520 BYTE wire[20] = WINPR_C_ARRAY_INIT;
521 wStream sbuffer = WINPR_C_ARRAY_INIT;
522 wStream* s = Stream_StaticInit(&sbuffer, wire, sizeof(wire));
523 Stream_Write_UINT32_BE(s, acknowledged); /* snSourceAck */
524 Stream_Write_UINT16_BE(s, 64); /* uReceiveWindowSize */
525 Stream_Write_UINT16_BE(s, FLAG_SYN | FLAG_ACK | FLAG_SYNEX);
526 Stream_Write_UINT32_BE(s, 0x1000); /* snInitialSequenceNumber */
527 Stream_Write_UINT16_BE(s, SYN_LENGTH);
528 Stream_Write_UINT16_BE(s, SYN_LENGTH);
529 Stream_Write_UINT16_BE(s, 0x0001); /* RDPUDP_VERSION_INFO_VALID */
530 Stream_Write_UINT16_BE(s, version);
531 return server_send_raw(ctx, wire, sizeof(wire));
532}
533
534/* A client connected with RDP-UDP version 3, the way a Windows server answers. */
535static BOOL ctx_connect(TestCtx* ctx)
536{
537 SynInfo syn = WINPR_C_ARRAY_INIT;
538 if (!ctx_start(ctx, TRUE, &syn))
539 return FALSE;
540 if (!send_syn_ack(ctx, syn.initialSequence, RDPUDP_PROTOCOL_VERSION_3))
541 return FALSE;
542 for (size_t x = 0; x < 100; x++)
543 {
544 if (!pump(ctx))
545 return FALSE;
546 if (rdpudp_get_state(ctx->udp) == RDPUDP_STATE_ESTABLISHED)
547 return rdpudp_get_version(ctx->udp) == RDPUDP_PROTOCOL_VERSION_3;
548 }
549 return FALSE;
550}
551
552/* Delivers count chunks of one byte from the server, the stream moving on from channel
553 * sequence *channel and data sequence *dataSeq. A batch stays well inside the socket buffer of
554 * the client, which loses datagrams beyond it like any other. */
555static BOOL stream_ahead(TestCtx* ctx, UINT16* dataSeq, UINT16* channel, size_t count)
556{
557 while (count > 0)
558 {
559 const size_t batch = (count > 64) ? 64 : count;
560 for (size_t x = 0; x < batch; x++)
561 {
562 if (!send_data(ctx, *dataSeq, *channel, "."))
563 return FALSE;
564 (*dataSeq)++;
565 (*channel)++;
566 }
567 if (!pump(ctx) || !drain(ctx, 0))
568 return FALSE;
569 count -= batch;
570 }
571 return TRUE;
572}
573
574/* ---------------------------------------------------------------------------------------- */
575/* The SYN exchange */
576/* ---------------------------------------------------------------------------------------- */
577
578static BOOL syn_offers_version_3_with_the_cookie_hash(void)
579{
580 BOOL rc = FALSE;
581 TestCtx ctx = WINPR_C_ARRAY_INIT;
582 SynInfo syn = WINPR_C_ARRAY_INIT;
583 CHECK(ctx_start(&ctx, TRUE, &syn));
584 /* [MS-RDPEUDP] 3.1.5.1.1: zero padded to the MTU, which validates the path MTU */
585 CHECK(syn.length == SYN_LENGTH);
586 CHECK((syn.flags & (FLAG_SYN | FLAG_SYNEX)) == (FLAG_SYN | FLAG_SYNEX));
587 CHECK(syn.version == RDPUDP_PROTOCOL_VERSION_3);
588 CHECK(memcmp(syn.cookie, cookieHash, sizeof(cookieHash)) == 0);
589 rc = TRUE;
590fail:
591 ctx_free(&ctx);
592 return rc;
593}
594
595static BOOL syn_offers_version_2_without_a_cookie_hash(void)
596{
597 BOOL rc = FALSE;
598 TestCtx ctx = WINPR_C_ARRAY_INIT;
599 SynInfo syn = WINPR_C_ARRAY_INIT;
600 CHECK(ctx_start(&ctx, FALSE, &syn));
601 CHECK(syn.length == SYN_LENGTH);
602 CHECK(syn.version == RDPUDP_PROTOCOL_VERSION_2);
603 rc = TRUE;
604fail:
605 ctx_free(&ctx);
606 return rc;
607}
608
609/* ---------------------------------------------------------------------------------------- */
610/* Receiving */
611/* ---------------------------------------------------------------------------------------- */
612
613static BOOL dummy_packets_are_acknowledged_but_not_delivered(void)
614{
615 BOOL rc = FALSE;
616 TestCtx ctx = WINPR_C_ARRAY_INIT;
617 CHECK(ctx_connect(&ctx));
618
619 const V3Out dummy = { .dummy = TRUE,
620 .hasData = TRUE,
621 .dataSeq = FIRST_SEQUENCE,
622 .channelSeq = 1,
623 .payload = (const BYTE*)"junk",
624 .payloadLength = 4 };
625 CHECK(server_send_v3(&ctx, &dummy));
626 CHECK(pump(&ctx));
627 CHECK(delivered_is(&ctx, ""));
628
629 /* the dummy took no channel sequence, this is the first chunk of the stream */
630 CHECK(send_data(&ctx, FIRST_SEQUENCE + 1, 1, "payload"));
631 CHECK(pump(&ctx));
632 CHECK(delivered_is(&ctx, "payload"));
633
634 CHECK(drain(&ctx, 20));
635 const V3Packet* ack = last_ack(&ctx);
636 CHECK(ack && (ack->flags & V3_ACK));
637 CHECK(ack->ack == FIRST_SEQUENCE + 1);
638 rc = TRUE;
639fail:
640 ctx_free(&ctx);
641 return rc;
642}
643
644/* A lost chunk comes back under a new data sequence number with its original channel sequence,
645 * so it arrives after the chunks that follow it. Handing the stream up in arrival order
646 * corrupts the TLS record layer above. */
647static BOOL retransmission_is_reordered_back_into_the_stream(void)
648{
649 BOOL rc = FALSE;
650 TestCtx ctx = WINPR_C_ARRAY_INIT;
651 CHECK(ctx_connect(&ctx));
652 CHECK(send_data(&ctx, 100, 1, "a"));
653 CHECK(send_data(&ctx, 101, 3, "c"));
654 CHECK(send_data(&ctx, 102, 4, "d"));
655 CHECK(pump(&ctx));
656 CHECK(delivered_is(&ctx, "a"));
657
658 CHECK(send_data(&ctx, 103, 2, "b"));
659 CHECK(pump(&ctx));
660 CHECK(delivered_is(&ctx, "abcd"));
661 rc = TRUE;
662fail:
663 ctx_free(&ctx);
664 return rc;
665}
666
667/* An AckOfAcks writes off a data sequence number the peer stopped resending (a dummy). It moves
668 * the window, the stream is ordered by channel sequence and stays as it is. */
669static BOOL ack_of_acks_advances_the_window_without_touching_the_stream(void)
670{
671 BOOL rc = FALSE;
672 TestCtx ctx = WINPR_C_ARRAY_INIT;
673 CHECK(ctx_connect(&ctx));
674 CHECK(send_data(&ctx, 100, 1, "a"));
675 /* 101 is a dummy that never arrives */
676 CHECK(send_data(&ctx, 102, 2, "b"));
677 CHECK(pump(&ctx));
678 CHECK(delivered_is(&ctx, "ab"));
679 CHECK(drain(&ctx, 20));
680 const V3Packet* ack = last_ack(&ctx);
681 CHECK(ack && (ack->flags & V3_ACKVEC) && (ack->vecBase == 101));
682
683 CHECK(send_aoa(&ctx, 102));
684 CHECK(pump(&ctx));
685 CHECK(drain(&ctx, 20));
686 ack = last_ack(&ctx);
687 CHECK(ack && (ack->flags & V3_ACK));
688 CHECK(ack->ack == 102);
689 CHECK(delivered_is(&ctx, "ab"));
690 rc = TRUE;
691fail:
692 ctx_free(&ctx);
693 return rc;
694}
695
696static BOOL send_data_aoa(TestCtx* ctx, UINT16 dataSeq, UINT16 channelSeq, const char* text,
697 UINT16 aoa)
698{
699 const V3Out out = { .hasAoA = TRUE,
700 .aoa = aoa,
701 .hasData = TRUE,
702 .dataSeq = dataSeq,
703 .channelSeq = channelSeq,
704 .payload = (const BYTE*)text,
705 .payloadLength = strlen(text) };
706 return server_send_v3(ctx, &out);
707}
708
709/* Windows at times sends a data packet with the next sequence number as its AckOfAcks, past the
710 * packet itself. Its chunk is still data: dropped but acknowledged, it is never resent and the
711 * stream stops for good behind it. */
712static BOOL ack_of_acks_past_its_own_packet_keeps_the_chunk(void)
713{
714 BOOL rc = FALSE;
715 TestCtx ctx = WINPR_C_ARRAY_INIT;
716 CHECK(ctx_connect(&ctx));
717 CHECK(send_data(&ctx, 100, 1, "a"));
718 CHECK(send_data_aoa(&ctx, 101, 2, "b", 102));
719 CHECK(send_data_aoa(&ctx, 102, 3, "c", 102));
720 CHECK(pump(&ctx));
721 CHECK(delivered_is(&ctx, "abc"));
722 CHECK(drain(&ctx, 20));
723 const V3Packet* ack = last_ack(&ctx);
724 CHECK(ack && (ack->flags & V3_ACK) && (ack->ack == 102));
725 rc = TRUE;
726fail:
727 ctx_free(&ctx);
728 return rc;
729}
730
731/* With its AckOfAcks past the packet itself, the peer has the acknowledgment for that packet
732 * already. Windows ends the connection on an ACK vector reporting it: 00e4 with AckOfAcks 00e5 in
733 * a capture, its ACK vector followed 0.8 s later. */
734static BOOL ack_of_acks_past_its_own_packet_gets_no_ack_vector(void)
735{
736 BOOL rc = FALSE;
737 TestCtx ctx = WINPR_C_ARRAY_INIT;
738 CHECK(ctx_connect(&ctx));
739 CHECK(send_data(&ctx, 100, 1, "a"));
740 CHECK(pump(&ctx));
741 CHECK(drain(&ctx, 20));
742
743 CHECK(send_data_aoa(&ctx, 101, 2, "b", 102));
744 CHECK(send_data_aoa(&ctx, 102, 3, "c", 102));
745 CHECK(pump(&ctx));
746 CHECK(delivered_is(&ctx, "abc"));
747 CHECK(drain(&ctx, 20));
748 for (size_t x = 0; x < ctx.seenCount; x++)
749 CHECK(!(ctx.seen[x].flags & V3_ACKVEC));
750 const V3Packet* ack = last_ack(&ctx);
751 CHECK(ack && (ack->flags & V3_ACK) && (ack->ack == 102));
752 rc = TRUE;
753fail:
754 ctx_free(&ctx);
755 return rc;
756}
757
758/* The same further ahead: the chunk is kept and the sequence numbers the AckOfAcks gives up are
759 * not reported missing afterwards. */
760static BOOL ack_of_acks_far_past_its_own_packet_keeps_the_chunk(void)
761{
762 BOOL rc = FALSE;
763 TestCtx ctx = WINPR_C_ARRAY_INIT;
764 CHECK(ctx_connect(&ctx));
765 CHECK(send_data(&ctx, 100, 1, "a"));
766 CHECK(send_data_aoa(&ctx, 101, 2, "b", 104));
767 CHECK(send_data(&ctx, 104, 3, "c"));
768 CHECK(pump(&ctx));
769 CHECK(delivered_is(&ctx, "abc"));
770 CHECK(drain(&ctx, 20));
771 const V3Packet* ack = last_ack(&ctx);
772 CHECK(ack && (ack->flags & V3_ACK) && (ack->ack == 104));
773 rc = TRUE;
774fail:
775 ctx_free(&ctx);
776 return rc;
777}
778
779/* A packet the peer gave up on with an AckOfAcks can still arrive late. Its chunk fills the hole
780 * at once ([MS-RDPEUDP2] 3.1.1.2.4.2), and the resend that follows is not handed up twice. */
781static BOOL late_packet_behind_the_window_fills_the_hole(void)
782{
783 BOOL rc = FALSE;
784 TestCtx ctx = WINPR_C_ARRAY_INIT;
785 CHECK(ctx_connect(&ctx));
786 CHECK(send_data(&ctx, 100, 1, "a"));
787 /* 101, carrying channel sequence 2, is delayed */
788 CHECK(send_data(&ctx, 102, 3, "c"));
789 CHECK(send_aoa(&ctx, 102));
790 CHECK(pump(&ctx));
791 CHECK(delivered_is(&ctx, "a"));
792
793 CHECK(send_data(&ctx, 101, 2, "b"));
794 CHECK(pump(&ctx));
795 CHECK(delivered_is(&ctx, "abc"));
796
797 /* the peer's resend of channel sequence 2 */
798 CHECK(send_data(&ctx, 103, 2, "b"));
799 CHECK(send_data(&ctx, 104, 4, "d"));
800 CHECK(pump(&ctx));
801 CHECK(delivered_is(&ctx, "abcd"));
802 rc = TRUE;
803fail:
804 ctx_free(&ctx);
805 return rc;
806}
807
808/* The peer resends a packet when our acknowledgement got lost. Staying silent would make it
809 * resend until it gives up. */
810static BOOL retransmitted_packets_are_acknowledged_again(void)
811{
812 BOOL rc = FALSE;
813 TestCtx ctx = WINPR_C_ARRAY_INIT;
814 CHECK(ctx_connect(&ctx));
815 CHECK(send_data(&ctx, 100, 1, "first"));
816 CHECK(pump(&ctx));
817 CHECK(drain(&ctx, 20));
818 CHECK(last_ack(&ctx));
819
820 CHECK(send_data(&ctx, 100, 1, "first"));
821 CHECK(pump(&ctx));
822 CHECK(delivered_is(&ctx, "first"));
823 CHECK(drain(&ctx, 20));
824 /* behind the window now, it is acknowledged on its own: one run of one received packet */
825 const V3Packet* ack = last_ack(&ctx);
826 CHECK(ack && (ack->flags & V3_ACKVEC) && (ack->vecBase == 100) && (ack->vecLength == 1) &&
827 (ack->vec[0] == (0x80 | 0x40 | 1)));
828 rc = TRUE;
829fail:
830 ctx_free(&ctx);
831 return rc;
832}
833
834/* A data packet of ours carries a cumulative ACK when one is pending. While a packet behind the
835 * window waits for its ACK vector, that ACK would take the vector's place, and nothing would send
836 * the vector until the next standalone ACK. */
837static BOOL ack_vector_is_not_lost_to_outgoing_data(void)
838{
839 BOOL rc = FALSE;
840 TestCtx ctx = WINPR_C_ARRAY_INIT;
841 CHECK(ctx_connect(&ctx));
842 /* the peer lets our acknowledgements wait 200 ms */
843 const V3Out first = { .hasDelayAck = TRUE,
844 .maxDelayedAcks = 8,
845 .delayedAckTimeout = 200,
846 .hasData = TRUE,
847 .dataSeq = 100,
848 .channelSeq = 1,
849 .payload = (const BYTE*)"first",
850 .payloadLength = 5 };
851 CHECK(server_send_v3(&ctx, &first));
852 CHECK(pump(&ctx));
853 Sleep(250);
854 CHECK(pump(&ctx));
855 CHECK(drain(&ctx, 20));
856 CHECK(last_ack(&ctx));
857
858 /* the peer resends it, behind the window now, and our data goes out before its ACK is due */
859 CHECK(send_data(&ctx, 100, 1, "first"));
860 CHECK(pump(&ctx));
861 CHECK(rdpudp_send(ctx.udp, (const BYTE*)"x", 1));
862 CHECK(drain(&ctx, 20));
863 const V3Packet* sent = first_data(&ctx);
864 CHECK(sent && !(sent->flags & V3_ACK));
865
866 /* once due, the resent packet is acknowledged on its own */
867 Sleep(250);
868 CHECK(pump(&ctx));
869 CHECK(drain(&ctx, 20));
870 BOOL vector = FALSE;
871 for (size_t x = 0; x < ctx.seenCount; x++)
872 {
873 const V3Packet* p = &ctx.seen[x];
874 if ((p->flags & V3_ACKVEC) && (p->vecBase == 100) && (p->vecLength == 1) &&
875 (p->vec[0] == (0x80 | 0x40 | 1)))
876 vector = TRUE;
877 }
878 CHECK(vector);
879 CHECK(delivered_is(&ctx, "first"));
880 rc = TRUE;
881fail:
882 ctx_free(&ctx);
883 return rc;
884}
885
886/* A resend under a new data sequence number repeats a channel sequence already handed up.
887 * Delivering it again duplicates bytes in the stream. */
888static BOOL retransmitted_channel_data_is_not_delivered_twice(void)
889{
890 BOOL rc = FALSE;
891 TestCtx ctx = WINPR_C_ARRAY_INIT;
892 CHECK(ctx_connect(&ctx));
893 CHECK(send_data(&ctx, 100, 1, "a"));
894 CHECK(send_data(&ctx, 101, 2, "b"));
895 CHECK(send_data(&ctx, 102, 2, "b"));
896 CHECK(send_data(&ctx, 103, 3, "c"));
897 CHECK(pump(&ctx));
898 CHECK(delivered_is(&ctx, "abc"));
899 rc = TRUE;
900fail:
901 ctx_free(&ctx);
902 return rc;
903}
904
905static BOOL gap_produces_an_ack_vector_rather_than_a_cumulative_ack(void)
906{
907 BOOL rc = FALSE;
908 TestCtx ctx = WINPR_C_ARRAY_INIT;
909 CHECK(ctx_connect(&ctx));
910 CHECK(send_data(&ctx, 100, 1, "a"));
911 CHECK(send_data(&ctx, 102, 3, "c"));
912 CHECK(pump(&ctx));
913 CHECK(drain(&ctx, 20));
914 const V3Packet* ack = last_ack(&ctx);
915 CHECK(ack);
916 CHECK((ack->flags & V3_ACKVEC) && !(ack->flags & V3_ACK));
917 CHECK(ack->vecBase == 101);
918 /* bit 0 is the base (101, missing), bit 1 is 102 (received) */
919 CHECK((ack->vecLength == 1) && (ack->vec[0] == 0x02));
920 rc = TRUE;
921fail:
922 ctx_free(&ctx);
923 return rc;
924}
925
926static BOOL ack_advertises_the_largest_window(void)
927{
928 BOOL rc = FALSE;
929 TestCtx ctx = WINPR_C_ARRAY_INIT;
930 CHECK(ctx_connect(&ctx));
931 CHECK(send_data(&ctx, 100, 1, "a"));
932 CHECK(pump(&ctx));
933 CHECK(drain(&ctx, 20));
934 const V3Packet* ack = last_ack(&ctx);
935 CHECK(ack && (ack->flags & V3_ACK) && (ack->ack == 100));
936 /* Windows always advertises 2^15 * MTU, a smaller window throttles its sender */
937 CHECK(ack->logWindow == 15);
938 rc = TRUE;
939fail:
940 ctx_free(&ctx);
941 return rc;
942}
943
944/* Windows wraps the channel sequence 65535 -> 1, skipping 0. Waiting for a 0 the peer never sends
945 * stalls the stream for good while the transport stays healthy. */
946static BOOL channel_sequence_wraps_past_zero(void)
947{
948 BOOL rc = FALSE;
949 TestCtx ctx = WINPR_C_ARRAY_INIT;
950 CHECK(ctx_connect(&ctx));
951 UINT16 dataSeq = FIRST_SEQUENCE;
952 UINT16 channel = 1;
953 CHECK(stream_ahead(&ctx, &dataSeq, &channel, 65534));
954 CHECK(channel == 65535);
955 const size_t before = Stream_GetPosition(ctx.delivered);
956 CHECK(before == 65534);
957
958 CHECK(send_data(&ctx, dataSeq, 65535, "f"));
959 CHECK(send_data(&ctx, (UINT16)(dataSeq + 1), 1, "a"));
960 CHECK(pump(&ctx));
961 CHECK(delivered_tail_is(&ctx, before, "fa"));
962
963 CHECK(send_data(&ctx, (UINT16)(dataSeq + 2), 2, "b"));
964 CHECK(pump(&ctx));
965 CHECK(delivered_tail_is(&ctx, before, "fab"));
966 rc = TRUE;
967fail:
968 ctx_free(&ctx);
969 return rc;
970}
971
972/* A packet captured from Windows: an ACK with one delayed acknowledgement ahead of the data.
973 * Reading numDelayedAcks from the wrong nibble shifts DataHeader and loses the payload. */
974static BOOL real_server_ack_with_delayed_acks_and_data(void)
975{
976 static const BYTE raw[] = { 0x00, 0x45, 0xf0, 0x66, 0x00, 0x03, 0x22, 0xe0,
977 0x00, 0x01, 0x54, 0x08, 0xe0, 0x00, 0x02, 0x00,
978 0x17, 0x03, 0x03, 0x00, 0x62, 0x56, 0x2c, 0x9f };
979 BOOL rc = FALSE;
980 TestCtx ctx = WINPR_C_ARRAY_INIT;
981 CHECK(ctx_connect(&ctx));
982 /* the captured packet is data sequence 224 carrying channel sequence 2 */
983 CHECK(send_data(&ctx, 223, 1, "a"));
984 CHECK(server_send_raw(&ctx, raw, sizeof(raw)));
985 CHECK(pump(&ctx));
986 CHECK(Stream_GetPosition(ctx.delivered) > 6);
987 CHECK(memcmp(Stream_Buffer(ctx.delivered), "a\x17\x03\x03\x00\x62", 6) == 0);
988 rc = TRUE;
989fail:
990 ctx_free(&ctx);
991 return rc;
992}
993
994/* ---------------------------------------------------------------------------------------- */
995/* Sending */
996/* ---------------------------------------------------------------------------------------- */
997
998/* AckOfAcks is the lowest of our data sequence numbers still awaiting acknowledgement. It goes
999 * out when it changes, sending the sequence being transmitted would make the peer abandon every
1000 * packet still in flight. */
1001static BOOL ack_of_acks_reports_the_oldest_unacknowledged_packet(void)
1002{
1003 BOOL rc = FALSE;
1004 TestCtx ctx = WINPR_C_ARRAY_INIT;
1005 CHECK(ctx_connect(&ctx));
1006 CHECK(rdpudp_send(ctx.udp, (const BYTE*)"1", 1));
1007 CHECK(drain(&ctx, 20));
1008 const V3Packet* sent = first_data(&ctx);
1009 CHECK(sent && sent->hasAoA && (sent->aoa == FIRST_SEQUENCE));
1010
1011 CHECK(rdpudp_send(ctx.udp, (const BYTE*)"2", 1));
1012 CHECK(drain(&ctx, 20));
1013 sent = first_data(&ctx);
1014 CHECK(sent && !sent->hasAoA);
1015
1016 CHECK(send_ack(&ctx, FIRST_SEQUENCE));
1017 CHECK(pump(&ctx));
1018 CHECK(rdpudp_send(ctx.udp, (const BYTE*)"3", 1));
1019 CHECK(drain(&ctx, 20));
1020 sent = first_data(&ctx);
1021 CHECK(sent && sent->hasAoA && (sent->aoa == FIRST_SEQUENCE + 1));
1022 rc = TRUE;
1023fail:
1024 ctx_free(&ctx);
1025 return rc;
1026}
1027
1028/* Once the 16 bit data sequence wraps, a cumulative ACK has to be compared with serial
1029 * arithmetic: a plain comparison keeps every outstanding packet and resends them all. */
1030static BOOL acknowledgements_survive_sequence_wraparound(void)
1031{
1032 BOOL rc = FALSE;
1033 TestCtx ctx = WINPR_C_ARRAY_INIT;
1034 CHECK(ctx_connect(&ctx));
1035
1036 /* send and acknowledge until the next data sequence is 0xFFFE */
1037 UINT16 next = FIRST_SEQUENCE;
1038 while (next != 0xFFFE)
1039 {
1040 const size_t batch = ((size_t)(0xFFFE - next) > 64) ? 64 : (size_t)(0xFFFE - next);
1041 for (size_t x = 0; x < batch; x++)
1042 CHECK(rdpudp_send(ctx.udp, (const BYTE*)".", 1));
1043 CHECK(collect_data(&ctx, batch, 1000));
1044 next = (UINT16)(next + batch);
1045 CHECK(send_ack(&ctx, (UINT16)(next - 1)));
1046 CHECK(pump(&ctx));
1047 }
1048
1049 /* 0xFFFE, 0xFFFF, 0x0000 and 0x0001 go out, the peer acknowledges up to 0x0000 */
1050 for (size_t x = 0; x < 4; x++)
1051 CHECK(rdpudp_send(ctx.udp, (const BYTE*)"w", 1));
1052 CHECK(collect_data(&ctx, 4, 1000));
1053 CHECK(send_ack(&ctx, 0x0000));
1054 CHECK(pump(&ctx));
1055
1056 /* only 0x0001 is left to resend */
1057 Sleep(400);
1058 CHECK(pump(&ctx));
1059 CHECK(drain(&ctx, 20));
1060 CHECK(count_data(&ctx) == 1);
1061 const V3Packet* resent = first_data(&ctx);
1062 CHECK(resent && (resent->channelSeq == 0xFFFE - FIRST_SEQUENCE + 4));
1063 rc = TRUE;
1064fail:
1065 ctx_free(&ctx);
1066 return rc;
1067}
1068
1069/* After a silence the peer may come back more than half the sequence space ahead, Windows used
1070 * 45000 numbers in a 25 s outage. Its AckOfAcks has to become the base then: taking its numbers
1071 * for old ones, the client would acknowledge one the peer never sent. */
1072static BOOL ack_of_acks_resyncs_after_a_silence(void)
1073{
1074 BOOL rc = FALSE;
1075 TestCtx ctx = WINPR_C_ARRAY_INIT;
1076 CHECK(ctx_connect(&ctx));
1077 CHECK(send_data(&ctx, FIRST_SEQUENCE, 1, "a"));
1078 CHECK(pump(&ctx));
1079 CHECK(drain(&ctx, 20));
1080 const V3Packet* ack = last_ack(&ctx);
1081 CHECK(ack && (ack->flags & V3_ACK) && (ack->ack == FIRST_SEQUENCE));
1082
1083 /* two keepalive intervals without a datagram: no acknowledgement of the old position */
1084 Sleep(8500);
1085 CHECK(pump(&ctx));
1086 CHECK(drain(&ctx, 20));
1087 CHECK(last_ack(&ctx) == nullptr);
1088
1089 /* a packet without AckOfAcks: still no acknowledgement, and nothing left due, or the
1090 * tunnel thread would poll without waiting */
1091 const V3Out unannounced = { .dummy = TRUE,
1092 .hasData = TRUE,
1093 .dataSeq = FIRST_SEQUENCE + 1,
1094 .payload = (const BYTE*)"x",
1095 .payloadLength = 1 };
1096 CHECK(server_send_v3(&ctx, &unannounced));
1097 CHECK(pump(&ctx));
1098 CHECK(pump(&ctx));
1099 CHECK(rdpudp_get_timeout(ctx.udp) > 0);
1100 CHECK(drain(&ctx, 20));
1101 CHECK(last_ack(&ctx) == nullptr);
1102
1103 const UINT16 ahead = (UINT16)(FIRST_SEQUENCE + 45000);
1104 const V3Out out = { .hasAoA = TRUE,
1105 .aoa = ahead,
1106 .hasData = TRUE,
1107 .dataSeq = ahead,
1108 .channelSeq = 2,
1109 .payload = (const BYTE*)"b",
1110 .payloadLength = 1 };
1111 CHECK(server_send_v3(&ctx, &out));
1112 CHECK(pump(&ctx));
1113 CHECK(delivered_is(&ctx, "ab"));
1114 CHECK(drain(&ctx, 20));
1115 ack = last_ack(&ctx);
1116 CHECK(ack && (ack->flags & V3_ACK) && (ack->ack == ahead));
1117 rc = TRUE;
1118fail:
1119 ctx_free(&ctx);
1120 return rc;
1121}
1122
1123/* Through a 2 s outage Windows went on sending at 20000 packets/s and used 42500 sequence numbers,
1124 * more than half the space: its next packets look old to us. Acknowledging our own position then
1125 * names numbers it has not sent, and Windows ends the connection. Each such packet is
1126 * acknowledged on its own instead, and its chunk is kept. The numbers are those of the capture. */
1127static BOOL packets_past_a_wrap_are_acknowledged_on_their_own(void)
1128{
1129 BOOL rc = FALSE;
1130 TestCtx ctx = WINPR_C_ARRAY_INIT;
1131 CHECK(ctx_connect(&ctx));
1132 CHECK(send_data(&ctx, FIRST_SEQUENCE, 1, "a"));
1133 CHECK(pump(&ctx));
1134 CHECK(drain(&ctx, 20));
1135
1136 /* 23006 below our position as serial arithmetic sees it, 42530 ahead in fact: a run of
1137 * 100 such packets, 70 carrying chunks and 30 dummies */
1138 const UINT16 wrapped = (UINT16)(FIRST_SEQUENCE + 1 + 42530);
1139 const size_t total = 100;
1140 char expected[80] = "a";
1141 for (size_t x = 0; x < total; x++)
1142 {
1143 const UINT16 seq = (UINT16)(wrapped + x);
1144 if (x < 70)
1145 {
1146 const char text[2] = { (char)('A' + (x % 26)), '\0' };
1147 expected[x + 1] = text[0];
1148 CHECK(send_data_aoa(&ctx, seq, (UINT16)(2 + x), text, (UINT16)(wrapped - 6976)));
1149 }
1150 else
1151 {
1152 const V3Out dummy = { .dummy = TRUE,
1153 .hasData = TRUE,
1154 .dataSeq = seq,
1155 .channelSeq = 0,
1156 .payload = (const BYTE*)"x",
1157 .payloadLength = 1 };
1158 CHECK(server_send_v3(&ctx, &dummy));
1159 }
1160 if ((x % 10) == 9)
1161 CHECK(pump(&ctx));
1162 }
1163 CHECK(pump(&ctx));
1164 CHECK(delivered_is(&ctx, expected));
1165
1166 /* the ACK vectors report exactly the run, nothing names our old position */
1167 CHECK(drain(&ctx, 50));
1168 BOOL reported[100] = WINPR_C_ARRAY_INIT;
1169 size_t vectors = 0;
1170 for (size_t x = 0; x < ctx.seenCount; x++)
1171 {
1172 const V3Packet* p = &ctx.seen[x];
1173 CHECK(!(p->flags & V3_ACK) || (p->ack != FIRST_SEQUENCE));
1174 if (!(p->flags & V3_ACKVEC))
1175 continue;
1176 vectors++;
1177 size_t pos = (UINT16)(p->vecBase - wrapped);
1178 for (size_t y = 0; y < p->vecLength; y++)
1179 {
1180 /* run-length entries of received packets only */
1181 CHECK((p->vec[y] & 0xC0) == 0xC0);
1182 for (size_t z = 0; z < (p->vec[y] & 0x3F); z++)
1183 {
1184 CHECK(pos < total);
1185 reported[pos++] = TRUE;
1186 }
1187 }
1188 }
1189 for (size_t x = 0; x < total; x++)
1190 CHECK(reported[x]);
1191 /* batched like any acknowledgement, not one per packet */
1192 CHECK(vectors < total / 4);
1193 rc = TRUE;
1194fail:
1195 ctx_free(&ctx);
1196 return rc;
1197}
1198
1199/* An ACK that rode on our data before a jump of the peer's numbers is not repeated after it,
1200 * where it would name a number the peer did not send. */
1201static BOOL piggybacked_ack_is_not_repeated_after_a_jump(void)
1202{
1203 BOOL rc = FALSE;
1204 TestCtx ctx = WINPR_C_ARRAY_INIT;
1205 CHECK(ctx_connect(&ctx));
1206 /* the peer lets our acknowledgements wait 200 ms, so our data carries the ACK */
1207 const V3Out first = { .hasDelayAck = TRUE,
1208 .maxDelayedAcks = 8,
1209 .delayedAckTimeout = 200,
1210 .hasData = TRUE,
1211 .dataSeq = FIRST_SEQUENCE,
1212 .channelSeq = 1,
1213 .payload = (const BYTE*)"a",
1214 .payloadLength = 1 };
1215 CHECK(server_send_v3(&ctx, &first));
1216 CHECK(pump(&ctx));
1217 CHECK(rdpudp_send(ctx.udp, (const BYTE*)"x", 1));
1218 CHECK(drain(&ctx, 20));
1219 const V3Packet* sent = first_data(&ctx);
1220 CHECK(sent && (sent->flags & V3_ACK) && (sent->ack == FIRST_SEQUENCE));
1221 CHECK(send_ack(&ctx, sent->dataSeq));
1222
1223 /* the peer's numbers jump past half the space */
1224 const UINT16 wrapped = (UINT16)(FIRST_SEQUENCE + 1 + 42530);
1225 for (size_t x = 0; x < 10; x++)
1226 CHECK(send_data_aoa(&ctx, (UINT16)(wrapped + x), (UINT16)(2 + x), "b",
1227 (UINT16)(wrapped - 6976)));
1228 CHECK(pump(&ctx));
1229 Sleep(250);
1230 CHECK(pump(&ctx));
1231 CHECK(drain(&ctx, 20));
1232
1233 BOOL vector = FALSE;
1234 for (size_t x = 0; x < ctx.seenCount; x++)
1235 {
1236 const V3Packet* p = &ctx.seen[x];
1237 CHECK(!(p->flags & V3_ACK) || (p->ack != FIRST_SEQUENCE));
1238 if (p->flags & V3_ACKVEC)
1239 vector = TRUE;
1240 }
1241 CHECK(vector);
1242 rc = TRUE;
1243fail:
1244 ctx_free(&ctx);
1245 return rc;
1246}
1247
1248/* ---------------------------------------------------------------------------------------- */
1249
1250typedef struct
1251{
1252 const char* name;
1253 BOOL (*fn)(void);
1254} TestCase;
1255
1256static const TestCase cases[] = {
1257 { "syn_offers_version_3_with_the_cookie_hash", syn_offers_version_3_with_the_cookie_hash },
1258 { "syn_offers_version_2_without_a_cookie_hash", syn_offers_version_2_without_a_cookie_hash },
1259 { "dummy_packets_are_acknowledged_but_not_delivered",
1260 dummy_packets_are_acknowledged_but_not_delivered },
1261 { "retransmission_is_reordered_back_into_the_stream",
1262 retransmission_is_reordered_back_into_the_stream },
1263 { "ack_of_acks_advances_the_window_without_touching_the_stream",
1264 ack_of_acks_advances_the_window_without_touching_the_stream },
1265 { "ack_of_acks_past_its_own_packet_keeps_the_chunk",
1266 ack_of_acks_past_its_own_packet_keeps_the_chunk },
1267 { "ack_of_acks_past_its_own_packet_gets_no_ack_vector",
1268 ack_of_acks_past_its_own_packet_gets_no_ack_vector },
1269 { "ack_of_acks_far_past_its_own_packet_keeps_the_chunk",
1270 ack_of_acks_far_past_its_own_packet_keeps_the_chunk },
1271 { "late_packet_behind_the_window_fills_the_hole",
1272 late_packet_behind_the_window_fills_the_hole },
1273 { "retransmitted_packets_are_acknowledged_again",
1274 retransmitted_packets_are_acknowledged_again },
1275 { "ack_vector_is_not_lost_to_outgoing_data", ack_vector_is_not_lost_to_outgoing_data },
1276 { "retransmitted_channel_data_is_not_delivered_twice",
1277 retransmitted_channel_data_is_not_delivered_twice },
1278 { "gap_produces_an_ack_vector_rather_than_a_cumulative_ack",
1279 gap_produces_an_ack_vector_rather_than_a_cumulative_ack },
1280 { "ack_advertises_the_largest_window", ack_advertises_the_largest_window },
1281 { "channel_sequence_wraps_past_zero", channel_sequence_wraps_past_zero },
1282 { "real_server_ack_with_delayed_acks_and_data", real_server_ack_with_delayed_acks_and_data },
1283 { "ack_of_acks_reports_the_oldest_unacknowledged_packet",
1284 ack_of_acks_reports_the_oldest_unacknowledged_packet },
1285 { "acknowledgements_survive_sequence_wraparound",
1286 acknowledgements_survive_sequence_wraparound },
1287 { "ack_of_acks_resyncs_after_a_silence", ack_of_acks_resyncs_after_a_silence },
1288 { "packets_past_a_wrap_are_acknowledged_on_their_own",
1289 packets_past_a_wrap_are_acknowledged_on_their_own },
1290 { "piggybacked_ack_is_not_repeated_after_a_jump",
1291 piggybacked_ack_is_not_repeated_after_a_jump },
1292};
1293
1294int TestRdpUdp(int argc, char* argv[])
1295{
1296 WINPR_UNUSED(argc);
1297 WINPR_UNUSED(argv);
1298
1299 WSADATA wsaData = WINPR_C_ARRAY_INIT;
1300 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
1301 return -1;
1302
1303 int rc = 0;
1304 for (size_t x = 0; x < ARRAYSIZE(cases); x++)
1305 {
1306 const BOOL ok = cases[x].fn();
1307 (void)printf("%s %s\n", ok ? "ok " : "FAILED", cases[x].name);
1308 if (!ok)
1309 rc = -1;
1310 }
1311
1312 WSACleanup();
1313 return rc;
1314}