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;
}
|