1 /*
2
3 Packet reordering test implementation, intended to cause packets to be
4 reordered for testing pptpd and other servers. Avoids the use of
5 pqueue.c so that it can be tested independently.
6
7 */
8
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "util.h"
13 #include "test-redirections.h"
14
15 /* whether we are asked to test ordering, obtained from command line */
16 extern int test_type;
17
18 /* rate at which to do test ordering changes */
19 extern int test_rate;
20
21 /* trigger cycle */
22 static int test_ordering_cycle = 0;
23
24 /* phase of reordering */
25 static int test_ordering_phase = 0;
26
27 /* swap a packet every now and then */
write_reordered_swap(int fd,const void * buf,size_t count)28 static ssize_t write_reordered_swap(int fd, const void *buf, size_t count)
29 {
30 static void *pocket_buf = NULL;
31 static int pocket_count = 0;
32 int stat;
33
34 switch (test_ordering_phase) {
35 case 0: /* between triggers, send as normal */
36 test_ordering_cycle++;
37 if (test_ordering_cycle == test_rate) test_ordering_phase++;
38 return write(fd, buf, count);
39 case 1: /* triggered, swap a packet */
40 test_ordering_cycle++;
41 if (test_ordering_cycle == (test_rate+1)) {
42 /* pocket the packet */
43 pocket_count = count;
44 pocket_buf = malloc(count);
45 memcpy(pocket_buf, buf, count);
46 log("test order swap, packet buffered");
47 /* lie about the result */
48 return count;
49 } else {
50 /* after this, reset to normal */
51 test_ordering_cycle = 0;
52 test_ordering_phase = 0;
53 /* send the new packet first */
54 stat = write(fd, buf, count);
55 if ((size_t)stat != count) return stat;
56 /* then send the old packet next */
57 stat = write(fd, pocket_buf, pocket_count);
58 free(pocket_buf);
59 log("test order swap, packets sent");
60 return count;
61 }
62 default:
63 return write(fd, buf, count);
64 }
65 }
66
67 /* hold ten packets and send the eleventh, then the ten in order */
write_reordered_retransmit(int fd,const void * buf,size_t count)68 static ssize_t write_reordered_retransmit(int fd, const void *buf, size_t count)
69 {
70 int test_length = 10;
71 static void *pocket_buf[10];
72 static int pocket_count[10];
73 int stat, n;
74
75 switch (test_ordering_phase) {
76 case 0: /* between triggers, send as normal */
77 test_ordering_cycle++;
78 if (test_ordering_cycle == test_rate) test_ordering_phase++;
79 return write(fd, buf, count);
80 case 1: /* triggered, buffer the packets */
81 test_ordering_cycle++;
82 if (test_ordering_cycle == (test_rate+test_length)) {
83 test_ordering_phase = 2;
84 }
85 /* pocket the packet */
86 n = test_ordering_cycle - test_rate - 1;
87 pocket_count[n] = count;
88 pocket_buf[n] = malloc(count);
89 memcpy(pocket_buf[n], buf, count);
90 log("test order retransmit, packet buffered");
91 /* lie about the result */
92 return count;
93 case 2:
94 /* after this, reset to normal */
95 test_ordering_cycle = 0;
96 test_ordering_phase = 0;
97 /* send the new packet first */
98 stat = write(fd, buf, count);
99 if ((size_t)stat != count) return stat;
100 /* send the buffered packets in normal order */
101 for (n=0; n<test_length; n++) {
102 stat = write(fd, pocket_buf[n], pocket_count[n]);
103 /* ignores failures */
104 free(pocket_buf[n]);
105 }
106 log("test order retransmit, packets sent");
107 return count;
108 default:
109 return write(fd, buf, count);
110 }
111 }
112
113 /* hold ten packets and send them in reverse order */
write_reordered_reverse(int fd,const void * buf,size_t count)114 static ssize_t write_reordered_reverse(int fd, const void *buf, size_t count)
115 {
116 int test_length = 10;
117 static void *pocket_buf[10];
118 static int pocket_count[10];
119 int stat, n;
120
121 switch (test_ordering_phase) {
122 case 0: /* between triggers, send as normal */
123 test_ordering_cycle++;
124 if (test_ordering_cycle == test_rate) test_ordering_phase++;
125 return write(fd, buf, count);
126 case 1: /* triggered, buffer the packets */
127 test_ordering_cycle++;
128 if (test_ordering_cycle == (test_rate+test_length)) {
129 test_ordering_phase = 2;
130 }
131 /* pocket the packet */
132 n = test_ordering_cycle - test_rate - 1;
133 pocket_count[n] = count;
134 pocket_buf[n] = malloc(count);
135 memcpy(pocket_buf[n], buf, count);
136 log("test order reverse, packet buffered");
137 /* lie about the result */
138 return count;
139 case 2:
140 /* after this, reset to normal */
141 test_ordering_cycle = 0;
142 test_ordering_phase = 0;
143 /* send the new packet first */
144 stat = write(fd, buf, count);
145 if ((size_t)stat != count) return stat;
146 /* send the buffered packets in reverse order */
147 for (n=test_length-1; n>0; n--) {
148 stat = write(fd, pocket_buf[n], pocket_count[n]);
149 /* ignores failures */
150 free(pocket_buf[n]);
151 }
152 log("test order reverse, packets sent");
153 return count;
154 default:
155 return write(fd, buf, count);
156 }
157 }
158
159 /* dispatcher for write reordering tests */
write_reordered(int fd,const void * buf,size_t count)160 static ssize_t write_reordered(int fd, const void *buf, size_t count)
161 {
162 switch (test_type) {
163 case 1: /* swap a packet every now and then */
164 return write_reordered_swap(fd, buf, count);
165 case 2: /* hold ten packets and send the eleventh, then the ten in order */
166 return write_reordered_retransmit(fd, buf, count);
167 case 3: /* hold ten packets and send them in reverse order */
168 return write_reordered_reverse(fd, buf, count);
169 default:
170 return write(fd, buf, count);
171 }
172 }
173
test_redirections(void)174 struct test_redirections *test_redirections(void)
175 {
176 static struct test_redirections *my = NULL;
177
178 if (my == NULL) my = malloc(sizeof(struct test_redirections));
179
180 my->write = write;
181 if (test_type) my->write = write_reordered;
182
183 return my;
184 }
185