/
test-redirections.c
184 lines (166 loc) · 5.35 KB
/
test-redirections.c
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
Packet reordering test implementation, intended to cause packets to be
reordered for testing pptpd and other servers. Avoids the use of
pqueue.c so that it can be tested independently.
*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "test-redirections.h"
/* whether we are asked to test ordering, obtained from command line */
extern int test_type;
/* rate at which to do test ordering changes */
extern int test_rate;
/* trigger cycle */
static int test_ordering_cycle = 0;
/* phase of reordering */
static int test_ordering_phase = 0;
/* swap a packet every now and then */
static ssize_t write_reordered_swap(int fd, const void *buf, size_t count)
{
static void *pocket_buf = NULL;
static int pocket_count = 0;
int stat;
switch (test_ordering_phase) {
case 0: /* between triggers, send as normal */
test_ordering_cycle++;
if (test_ordering_cycle == test_rate) test_ordering_phase++;
return write(fd, buf, count);
case 1: /* triggered, swap a packet */
test_ordering_cycle++;
if (test_ordering_cycle == (test_rate+1)) {
/* pocket the packet */
pocket_count = count;
pocket_buf = malloc(count);
memcpy(pocket_buf, buf, count);
log("test order swap, packet buffered");
/* lie about the result */
return count;
} else {
/* after this, reset to normal */
test_ordering_cycle = 0;
test_ordering_phase = 0;
/* send the new packet first */
stat = write(fd, buf, count);
if ((size_t)stat != count) return stat;
/* then send the old packet next */
stat = write(fd, pocket_buf, pocket_count);
free(pocket_buf);
log("test order swap, packets sent");
return count;
}
default:
return write(fd, buf, count);
}
}
/* hold ten packets and send the eleventh, then the ten in order */
static ssize_t write_reordered_retransmit(int fd, const void *buf, size_t count)
{
int test_length = 10;
static void *pocket_buf[10];
static int pocket_count[10];
int stat, n;
switch (test_ordering_phase) {
case 0: /* between triggers, send as normal */
test_ordering_cycle++;
if (test_ordering_cycle == test_rate) test_ordering_phase++;
return write(fd, buf, count);
case 1: /* triggered, buffer the packets */
test_ordering_cycle++;
if (test_ordering_cycle == (test_rate+test_length)) {
test_ordering_phase = 2;
}
/* pocket the packet */
n = test_ordering_cycle - test_rate - 1;
pocket_count[n] = count;
pocket_buf[n] = malloc(count);
memcpy(pocket_buf[n], buf, count);
log("test order retransmit, packet buffered");
/* lie about the result */
return count;
case 2:
/* after this, reset to normal */
test_ordering_cycle = 0;
test_ordering_phase = 0;
/* send the new packet first */
stat = write(fd, buf, count);
if ((size_t)stat != count) return stat;
/* send the buffered packets in normal order */
for (n=0; n<test_length; n++) {
stat = write(fd, pocket_buf[n], pocket_count[n]);
/* ignores failures */
free(pocket_buf[n]);
}
log("test order retransmit, packets sent");
return count;
default:
return write(fd, buf, count);
}
}
/* hold ten packets and send them in reverse order */
static ssize_t write_reordered_reverse(int fd, const void *buf, size_t count)
{
int test_length = 10;
static void *pocket_buf[10];
static int pocket_count[10];
int stat, n;
switch (test_ordering_phase) {
case 0: /* between triggers, send as normal */
test_ordering_cycle++;
if (test_ordering_cycle == test_rate) test_ordering_phase++;
return write(fd, buf, count);
case 1: /* triggered, buffer the packets */
test_ordering_cycle++;
if (test_ordering_cycle == (test_rate+test_length)) {
test_ordering_phase = 2;
}
/* pocket the packet */
n = test_ordering_cycle - test_rate - 1;
pocket_count[n] = count;
pocket_buf[n] = malloc(count);
memcpy(pocket_buf[n], buf, count);
log("test order reverse, packet buffered");
/* lie about the result */
return count;
case 2:
/* after this, reset to normal */
test_ordering_cycle = 0;
test_ordering_phase = 0;
/* send the new packet first */
stat = write(fd, buf, count);
if ((size_t)stat != count) return stat;
/* send the buffered packets in reverse order */
for (n=test_length-1; n>0; n--) {
stat = write(fd, pocket_buf[n], pocket_count[n]);
/* ignores failures */
free(pocket_buf[n]);
}
log("test order reverse, packets sent");
return count;
default:
return write(fd, buf, count);
}
}
/* dispatcher for write reordering tests */
static ssize_t write_reordered(int fd, const void *buf, size_t count)
{
switch (test_type) {
case 1: /* swap a packet every now and then */
return write_reordered_swap(fd, buf, count);
case 2: /* hold ten packets and send the eleventh, then the ten in order */
return write_reordered_retransmit(fd, buf, count);
case 3: /* hold ten packets and send them in reverse order */
return write_reordered_reverse(fd, buf, count);
default:
return write(fd, buf, count);
}
}
struct test_redirections *test_redirections(void)
{
static struct test_redirections *my = NULL;
if (my == NULL) my = malloc(sizeof(struct test_redirections));
my->write = write;
if (test_type) my->write = write_reordered;
return my;
}