forked from PKUFlyingPig/CS144-Computer-Network
-
Notifications
You must be signed in to change notification settings - Fork 0
/
txrx.sh
executable file
·238 lines (218 loc) · 7.97 KB
/
txrx.sh
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#!/bin/bash
show_usage() {
echo "Usage: $0 <-i|-u> <-c|-s> <-R|-S|-D> [-n|-o]"
echo " [-t <rtto>] [-d <size>] [-w <size>] [-l <rate>] [-L <rate>]"
echo
echo " Option Default"
echo " -- --"
echo " -i or -u Select IP or UDP mode (must specify)"
echo " -c or -s Select client or server mode (must specify)"
echo " -R, -S, -D Receive test, Send test, or Duplex test (must specify)"
echo
echo " -t <rtto> Set rtto to <rtto> ms 12"
echo " -d <size> Set total transfer size to <size> 32"
echo " -w <size> Set window size to <size> 1452"
echo
echo " -l <rate> Set downlink loss to <rate> (float in 0..1) 0"
echo " -L <rate> Set uplink loss to <rate> (float in 0..1) 0"
echo
echo " -n In IP mode, use tcp_native rather tcp_ipv4_ref False"
echo " -o In IP mode, use socat rather than tcp_ipv4_ref False"
[ ! -z "$1" ] && { echo; echo ERROR: "$1"; }
exit 1
}
get_cmdline_options () {
# prepare to use getopts
local OPT= OPTIND=1 OPTARG=
CSMODE= RSDMODE= DATASIZE=32 WINSIZE= IUMODE= USE_IPV4= RTTO="-t 12" LOSS_UP= LOSS_DN=
while getopts "t:oniucsRSDd:w:p:l:L:" OPT; do
case "$OPT" in
i|u)
[ ! -z "$IUMODE" ] && show_usage "Only one of -i and -u is allowed."
IUMODE=$OPT
;;
c|s)
[ ! -z "$CSMODE" ] && show_usage "Only one of -c and -s is allowed."
CSMODE=$OPT
;;
R|S|D)
[ ! -z "$RSDMODE" ] && show_usage "Only one of -R, -S, and -D is allowed."
RSDMODE=$OPT
;;
d)
DATASIZE="$OPTARG"
;;
w)
expand_num "$OPTARG" || show_usage "Bad numeric arg \"$OPTARG\" to -w."
WINSIZE="-w ${NUM_EXPANDED}"
;;
l)
LOSS_DN="$OPTARG"
;;
L)
LOSS_UP="$OPTARG"
;;
n|o)
[ ! -z "$USE_IPV4" ] && show_usage "Only one of -n and -o is allowed."
USE_IPV4=$OPT
;;
t)
expand_num "$OPTARG" || show_usage "Bad numeric arg \"$OPTARG\" to -t."
RTTO="-t ${NUM_EXPANDED}"
;;
*)
show_usage "Unknown option $OPT"
;;
esac
done
if [ "$OPTIND" != $(($# + 1)) ]; then
show_usage "Extraneous arguments detected."
fi
if [ -z "$CSMODE" ] || [ -z "$RSDMODE" ] || [ -z "$IUMODE" ]; then
show_usage "You must specify either -i or -u, either -c or -s, and one of -R, -S, and -D."
fi
if [ ! -z "$USE_IPV4" ] && [ "$IUMODE" != "i" ]; then
show_usage "-n and -o may only be specified in IP mode (-i)."
fi
# loss param args depend on whether we're applying to ref or test program (test uplink == loss downlink)
{ [ ! -z "$USE_IPV4" ] && local LD_SWITCH="-Ld" LU_SWITCH="-Lu"; } || local LD_SWITCH="-Lu" LU_SWITCH="-Ld"
[ ! -z "$LOSS_DN" ] && LOSS_DN="${LD_SWITCH} ${LOSS_DN}"
[ ! -z "$LOSS_UP" ] && LOSS_UP="${LU_SWITCH} ${LOSS_UP}"
}
expand_num () {
[ "$#" != "1" ] && { echo "bad args"; exit 1; }
NUM_EXPANDED=$(numfmt --from=iec "$1" 2>/dev/null)
return $?
}
_socat_listen () {
coproc socat tcp4-listen:${SERVER_PORT},reuseaddr,reuseport,linger=2 stdio >"$1" <"$2" && sleep 0.1
set +u
[ -z "$COPROC_PID" ] && { echo "Error in _socat_listen"; exit 1; }
set -u
}
_socat_connect () {
socat tcp4-connect:${TEST_HOST}:${SERVER_PORT},reuseaddr,reuseport,linger=2 stdio >"$1" <"$2" ||
{ echo "Error in _socat_connect"; exit 1; }
}
_rt_listen () {
coproc $3 -l $4 ${SERVER_PORT} >"$1" <"$2" && sleep 0.1
set +u
[ -z "$COPROC_PID" ] && { echo "Error in _rt_listen"; exit 1; }
set -u
}
_rt_connect () {
$3 $4 ${SERVER_PORT} >"$1" <"$2" || { echo "Error in _rt_connect"; exit 1; }
}
test_listen () {
[ "$#" != 2 ] && { echo "bad args"; exit 1; }
_rt_listen "$1" "$2" "${TEST_PROG}" "${TEST_HOST}"
}
test_connect () {
[ "$#" != 2 ] && { echo "bad args"; exit 1; }
_rt_connect "$1" "$2" "${TEST_PROG}" "${REF_HOST}"
}
ref_listen () {
[ "$#" != 2 ] && { echo "bad args"; exit 1; }
if [ "$IUMODE" = "u" ] || [ -z "$USE_IPV4" ] || [ "$USE_IPV4" = "n" ]; then
_rt_listen "$1" "$2" "${REF_PROG}" "${REF_HOST}"
else
_socat_listen "$1" "$2"
fi
}
ref_connect () {
[ "$#" != 2 ] && { echo "bad args"; exit 1; }
if [ "$IUMODE" = "u" ] || [ -z "$USE_IPV4" ] || [ "$USE_IPV4" = "n" ]; then
_rt_connect "$1" "$2" "${REF_PROG}" "${TEST_HOST}"
else
_socat_connect "$1" "$2"
fi
}
hash_file () {
[ "$#" != "1" ] && { echo "bad args"; exit 1; }
sha256sum "$1" | cut -d \ -f 1
}
make_test_file () {
if expand_num "$2"; then
dd status=none if=/dev/urandom of="$1" bs="${NUM_EXPANDED}" count=1 || { echo "Failed to make test file."; exit 1; }
else
# can't interpret as a number, so interpret as literal data to send
echo -en "$2" >"$1"
fi
}
exit_cleanup () {
set +u
rm -f "${TEST_IN_FILE}" "${TEST_OUT_FILE}" "${TEST_OUT2_FILE}"
[ ! -z "$COPROC_PID" ] && kill ${COPROC_PID}
}
# make sure tun device is running
ip link show tun144 &>/dev/null || { echo "please enable tun144 and re-run"; exit 1; }
ip link show tun145 &>/dev/null || { echo "please enable tun145 and re-run"; exit 1; }
set -u
trap exit_cleanup EXIT
get_cmdline_options "$@"
. "$(dirname "$0")"/etc/tunconfig
REF_HOST=${TUN_IP_PREFIX}.144.1
TEST_HOST=${TUN_IP_PREFIX}.144.1
SERVER_PORT=$(($((RANDOM % 50000)) + 1025))
if [ "$IUMODE" = "i" ]; then
# IPv4 mode
TEST_HOST=${TUN_IP_PREFIX}.144.9
if [ -z "$USE_IPV4" ]; then
REF_HOST=${TUN_IP_PREFIX}.145.9
REF_PROG="./apps/tcp_ipv4 ${RTTO} ${WINSIZE} ${LOSS_UP} ${LOSS_DN} -d tun145 -a ${REF_HOST}"
TEST_PROG="./apps/tcp_ipv4 ${RTTO} ${WINSIZE} -d tun144 -a ${TEST_HOST}"
else
REF_PROG="./apps/tcp_native"
TEST_PROG="./apps/tcp_ipv4 ${RTTO} ${WINSIZE} ${LOSS_UP} ${LOSS_DN} -d tun144 -a ${TEST_HOST}"
fi
else
# UDP mode
REF_PROG="./apps/tcp_udp ${RTTO} ${WINSIZE} ${LOSS_UP} ${LOSS_DN}"
TEST_PROG="./apps/tcp_udp ${RTTO} ${WINSIZE}"
fi
TEST_OUT_FILE=$(mktemp)
TEST_IN_FILE=$(mktemp)
make_test_file "${TEST_IN_FILE}" "${DATASIZE}"
HASH_IN=$(sha256sum ${TEST_IN_FILE} | cut -d \ -f 1)
HASH_OUT2=
case "$RSDMODE" in
S) # test sending
if [ "$CSMODE" = "c" ]; then
ref_listen "${TEST_OUT_FILE}" /dev/null
test_connect /dev/null "${TEST_IN_FILE}"
else
test_listen /dev/null "${TEST_IN_FILE}"
ref_connect "${TEST_OUT_FILE}" /dev/null
fi
;;
R) # test receiving
if [ "$CSMODE" = "c" ]; then
ref_listen /dev/null "${TEST_IN_FILE}"
test_connect "${TEST_OUT_FILE}" /dev/null
else
test_listen "${TEST_OUT_FILE}" /dev/null
ref_connect /dev/null "${TEST_IN_FILE}"
fi
;;
D) # test full-duplex
TEST_OUT2_FILE=$(mktemp)
if [ "$CSMODE" = "c" ]; then
ref_listen "${TEST_OUT_FILE}" "${TEST_IN_FILE}"
test_connect "${TEST_OUT2_FILE}" "${TEST_IN_FILE}"
else
test_listen "${TEST_OUT_FILE}" "${TEST_IN_FILE}"
ref_connect "${TEST_OUT2_FILE}" "${TEST_IN_FILE}"
fi
HASH_OUT2=$(hash_file "${TEST_OUT2_FILE}")
;;
esac
if ! wait; then
echo ERROR: subprocess failed
exit 1
fi
HASH_OUT=$(hash_file ${TEST_OUT_FILE})
if [ ! -z "${HASH_OUT2}" ] && [ "${HASH_OUT}" != "${HASH_OUT2}" ] || [ "${HASH_IN}" != "${HASH_OUT}" ]; then
echo ERROR: "$HASH_IN" neq "$HASH_OUT" or "$HASH_OUT2"
exit 1
fi
exit 0