├── COPYING ├── LICENSE ├── README ├── README.md ├── auto ├── cc │ ├── acc │ ├── clang │ ├── conf │ ├── gcc │ ├── icc │ └── name ├── define ├── feature ├── have ├── have_headers ├── headers ├── include ├── init ├── install ├── linux ├── make ├── nohave ├── options ├── os │ ├── conf │ └── linux ├── sources ├── summary └── types │ ├── sizeof │ ├── typedef │ ├── uintptr_t │ └── value ├── configure ├── images └── tcpburn.png └── src ├── burn ├── burn.h ├── main.c ├── tc_manager.c ├── tc_manager.h ├── tc_message_module.c ├── tc_message_module.h ├── tc_packets_module.c ├── tc_packets_module.h ├── tc_user.c └── tc_user.h ├── communication ├── tc_msg.h ├── tc_socket.c └── tc_socket.h ├── core ├── tc_alloc.c ├── tc_alloc.h ├── tc_common.c ├── tc_config.h ├── tc_daemon.c ├── tc_link_list.c ├── tc_link_list.h ├── tc_log.c ├── tc_log.h ├── tc_palloc.c ├── tc_palloc.h ├── tc_rbtree.c ├── tc_rbtree.h ├── tc_signal.c ├── tc_signal.h ├── tc_time.c ├── tc_time.h └── xcopy.h ├── event ├── tc_event.c ├── tc_event.h ├── tc_event_timer.c ├── tc_event_timer.h ├── tc_select_module.c └── tc_select_module.h └── util ├── tc_util.c └── tc_util.h /COPYING: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 NetEase, Inc. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | * SUCH DAMAGE. 24 | */ 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 NetEase, Inc. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | * SUCH DAMAGE. 24 | */ 25 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | # A tool to simulate millions of concurrent users 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A TCP Stream Replay Tool for Concurrency 2 | 3 | 4 | ## Description 5 | TPCBurn is a replay tool designed specifically for concurrency. It can stress-test any TCP-based application that supports replay functionality. 6 | 7 | 8 | ## Characteristics 9 | 1. Network latency can be preserved. 10 | 2. There's no need to bind multiple IP addresses, and the number of client IP addresses is unlimited. 11 | 3. The maximum number of concurrent users is limited by bandwidth, memory, and CPU processing power. 12 | 4. Only TCP-based applications that support replay are supported. 13 | 14 | ## Scenarios 15 | 1. Stress Testing 16 | 2. Comet 17 | 3. Performance Testing 18 | 19 | 20 | ## Architecture 21 | 22 | ![tcpburn](images/tcpburn.png) 23 | 24 | Figure 1. Overview of the TCPBurn Architecture. 25 | 26 | As shown in the figure above, TCPBurn consists of two components: `tcpburn` and `intercept`. 27 | 28 | - **`tcpburn`** runs on the test server and sends packets from pcap files. It reads packets, performs necessary processing such as simulating TCP interactions, controlling network latency, and simulating common upper-layer interactions. By default, it uses a raw socket output technique to send packets to the target server (indicated by light pink arrows). 29 | 30 | - **`intercept`** operates on the assistant server and performs supporting tasks, such as passing response information to `tcpburn`. It captures response packets, extracts response header information, and sends this information to `tcpburn` through a special channel (indicated by light blue arrows). When `tcpburn` receives the response header, it uses the header information to modify pcap packet attributes and continues sending additional packets. 31 | 32 | The only action required on the target server for TCPBurn is to set appropriate route rules to direct response packets (indicated by light green arrows) to the assistant server. Note that the assistant server should act as a black hole for responses from the target server. 33 | 34 | 35 | ## `tcpburn` Configure Options 36 | - `--with-debug` Compile `tcpburn` with debug support (output saved in a log file). 37 | - `--pcap-send` Send packets at the data link layer instead of the IP layer. 38 | - `--single` If `intercept` is configured with the `--single` option, use this option for `tcpburn` as well. 39 | - `--comet` Replay sessions for Comet applications. 40 | 41 | 42 | ## Installation and Running 43 | 44 | ### 1. intercept 45 | a) Install `intercept` on the assistant server 46 | ``` 47 | git clone git://github.com/session-replay-tools/intercept.git 48 | cd intercept 49 | ./configure --single 50 | make 51 | make install 52 | ``` 53 | 54 | b) **On the Assistant Server Running `intercept` (Root Privilege or CAP_NET_RAW Capability Required):** 55 | 56 | ``` 57 | ./intercept -F -i 58 | ``` 59 | 60 | Note that the filter format is the same as the pcap filter. For example: 61 | 62 | ``` 63 | ./intercept -i eth0 -F 'tcp and src port 80' -d 64 | ``` 65 | 66 | In this example, `intercept` will capture response packets from a TCP-based application listening on port 80, using the eth0 network device. 67 | 68 | ### 2. **On the Target Server Running Server Applications:** 69 | 70 | Configure the `route` rules to direct response packets to the assistant server. For example, if `65.135.233.161` is the IP address of the assistant server, use the following route command to direct all responses from clients in the `62.135.200.x` range to the assistant server: 71 | 72 | `route add -net 62.135.200.0 netmask 255.255.255.0 gw 65.135.233.161` 73 | 74 | 75 | ### 3. `tcpburn` (root privilege or the CAP_NET_RAW capability is required when running) 76 | a) Install `tcpburn` on the test server 77 | ``` 78 | git clone git://github.com/session-replay-tools/tcpburn.git 79 | cd tcpburn 80 | 81 | if not comet scenarios 82 | ./configure --single 83 | else 84 | ./configure --single --comet 85 | endif 86 | 87 | make 88 | make install 89 | ``` 90 | 91 | b) **Running `tcpburn` on the Test Server(root privilege or the CAP_NET_RAW capability is required):** 92 | 93 | ``` 94 | ./tcpburn -x historyServerPort-targetServerIP:targetServerPort -f -s -u -c 95 | ``` 96 | 97 | For example, assume: 98 | 99 | - **65.135.233.160** is the IP address of the target server. 100 | - **10.110.10.161** is the internal IP address of the assistant server. 101 | - **65.135.233.161** is the external IP address of the assistant server. 102 | 103 | You would use the following command: 104 | 105 | ``` 106 | ./tcpburn -x 80-65.135.233.160:80 -f /path/to/80.pcap -s 10.110.10.161 -u 10000 -c 62.135.200.x 107 | ``` 108 | 109 | `tcpburn` extracts packets from the `80.pcap` file, destined for port 80, and replays them to the target server at **65.135.233.160**, where an application listens on port 80. It replays a total of 10,000 sessions, using client IP addresses from the **62.135.200.x** range. `tcpburn` connects to the assistant server at **10.110.10.161** to obtain response information. 110 | 111 | 112 | ## Note 113 | 1. All sessions are retrieved from pcap files; ensure the sessions in the pcap files are complete. 114 | 2. By default, `tcpburn` uses raw sockets to send packets. To avoid ip_conntrack problems or achieve better performance, configure `tcpburn` with `--pcap-send` and refer to `./tcpburn -h` for instructions on setting the appropriate parameters. 115 | 3. The test server and the assistant server can be on the same machine. 116 | 4. For Comet applications, exclude publish sessions if they are present in the pcap files. 117 | 5. tcpburn cannot replay TCP-based sessions that cannot be replayed, such as SSL/TLS sessions. 118 | 6. `ip_forward` should not be enabled on the assistant server. 119 | 7. Root privileges or the CAP_NET_RAW capability are required. 120 | 8. Execute `./tcpburn -h` or `./intercept -h` for more details. 121 | 122 | 123 | ## Release History 124 | + 2014.09 v1.0 TCPBurn released 125 | + 2024.09 v1.0 Open source fully uses English 126 | 127 | ## Bugs and Feature Requests 128 | Have a bug or a feature request? [Please open a new issue](https://github.com/session-replay-tools/tcpburn/issues). Before opening any issue, please search for existing issues. 129 | 130 | 131 | ## Copyright and License 132 | 133 | Copyright 2024 under [the BSD license](LICENSE). 134 | -------------------------------------------------------------------------------- /auto/cc/acc: -------------------------------------------------------------------------------- 1 | 2 | # aCC: HP ANSI C++ B3910B A.03.55.02 3 | 4 | # C89 mode 5 | 6 | CFLAGS="$CFLAGS -Ae" 7 | CC_TEST_FLAGS="-Ae" 8 | 9 | -------------------------------------------------------------------------------- /auto/cc/clang: -------------------------------------------------------------------------------- 1 | 2 | # clang 3 | 4 | 5 | TC_CLANG_VER=`$CC -v 2>&1 | grep 'clang version' 2>&1 \ 6 | | sed -e 's/^.*clang version \(.*\)/\1/'` 7 | 8 | echo " + clang version: $TC_CLANG_VER" 9 | 10 | have=TC_COMPILER value="\"clang $TC_CLANG_VER\"" . auto/define 11 | 12 | 13 | CC_TEST_FLAGS="-pipe" 14 | 15 | 16 | # optimizations 17 | 18 | #TC_CLANG_OPT="-O2" 19 | #TC_CLANG_OPT="-Oz" 20 | TC_CLANG_OPT="-O" 21 | 22 | case $CPU in 23 | pentium) 24 | # optimize for Pentium 25 | CPU_OPT="-march=pentium" 26 | TC_CPU_CACHE_LINE=32 27 | ;; 28 | 29 | pentiumpro | pentium3) 30 | # optimize for Pentium Pro, Pentium II and Pentium III 31 | CPU_OPT="-march=pentiumpro" 32 | TC_CPU_CACHE_LINE=32 33 | ;; 34 | 35 | pentium4) 36 | # optimize for Pentium 4 37 | CPU_OPT="-march=pentium4" 38 | TC_CPU_CACHE_LINE=128 39 | ;; 40 | 41 | athlon) 42 | # optimize for Athlon 43 | CPU_OPT="-march=athlon" 44 | TC_CPU_CACHE_LINE=64 45 | ;; 46 | 47 | opteron) 48 | # optimize for Opteron 49 | CPU_OPT="-march=opteron" 50 | TC_CPU_CACHE_LINE=64 51 | ;; 52 | 53 | esac 54 | 55 | CC_AUX_FLAGS="$CC_AUX_FLAGS $CPU_OPT" 56 | 57 | 58 | CFLAGS="$CFLAGS -pipe $CPU_OPT" 59 | 60 | CFLAGS="$CFLAGS -std=gnu99 -D_FILE_OFFSET_BITS=64" 61 | 62 | # warnings 63 | 64 | CFLAGS="$CFLAGS $TC_CLANG_OPT -Wall -Wextra -Wpointer-arith" 65 | #CFLAGS="$CFLAGS -Wmissing-prototypes" 66 | 67 | # we have a lot of unused function arguments 68 | CFLAGS="$CFLAGS -Wno-unused-parameter" 69 | 70 | CFLAGS="$CFLAGS -W -Wall -Wunused-function -pedantic" 71 | 72 | # debug 73 | CFLAGS="$CFLAGS -g" 74 | 75 | if [ ".$CPP" = "." ]; then 76 | CPP="$CC -E" 77 | fi 78 | -------------------------------------------------------------------------------- /auto/cc/conf: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | LINK="\$(CC)" 6 | 7 | tc_include_opt="-I " 8 | tc_compile_opt="-c" 9 | tc_objout="-o " 10 | tc_binout="-o " 11 | tc_objext="o" 12 | 13 | tc_long_start= 14 | tc_long_end= 15 | 16 | tc_regex_dirsep="\/" 17 | tc_dirsep='/' 18 | 19 | tc_regex_cont=' \\\ 20 | ' 21 | tc_cont=' \ 22 | ' 23 | tc_tab=' \ 24 | ' 25 | tc_spacer= 26 | 27 | tc_long_regex_cont=$tc_regex_cont 28 | tc_long_cont=$tc_cont 29 | 30 | . auto/cc/name 31 | 32 | if test -n "$CFLAGS"; then 33 | 34 | CC_TEST_FLAGS="$CFLAGS $TC_CC_OPT" 35 | 36 | else 37 | 38 | case $TC_CC_NAME in 39 | gcc) 40 | . auto/cc/gcc 41 | ;; 42 | 43 | clang) 44 | 45 | . auto/cc/clang 46 | ;; 47 | 48 | icc) 49 | . auto/cc/icc 50 | ;; 51 | 52 | acc) 53 | 54 | . auto/cc/acc 55 | ;; 56 | 57 | esac 58 | 59 | CC_TEST_FLAGS="$CC_TEST_FLAGS $TC_CC_OPT" 60 | 61 | fi 62 | 63 | CFLAGS="$CFLAGS $TC_CC_OPT" 64 | TC_TEST_LD_OPT="$TC_LD_OPT" 65 | 66 | if [ "$TC_PLATFORM" != win32 ]; then 67 | 68 | if test -n "$TC_LD_OPT"; then 69 | tc_feature=--with-ld-opt=\"$TC_LD_OPT\" 70 | tc_feature_name= 71 | tc_feature_run=no 72 | tc_feature_incs= 73 | tc_feature_path= 74 | tc_feature_libs= 75 | tc_feature_test= 76 | . auto/feature 77 | 78 | if [ $tc_found = no ]; then 79 | echo $0: error: the invalid value in --with-ld-opt=\"$TC_LD_OPT\" 80 | echo 81 | exit 1 82 | fi 83 | fi 84 | 85 | 86 | tc_feature="gcc builtin atomic operations" 87 | tc_feature_name=TC_HAVE_GCC_ATOMIC 88 | tc_feature_run=yes 89 | tc_feature_incs= 90 | tc_feature_path= 91 | tc_feature_libs= 92 | tc_feature_test="long n = 0; 93 | if (!__sync_bool_compare_and_swap(&n, 0, 1)) 94 | return 1; 95 | if (__sync_fetch_and_add(&n, 1) != 1) 96 | return 1; 97 | if (n != 2) 98 | return 1; 99 | __sync_synchronize();" 100 | . auto/feature 101 | 102 | 103 | tc_feature="C99 variadic macros" 104 | tc_feature_name="TC_HAVE_C99_VARIADIC_MACROS" 105 | tc_feature_run=yes 106 | tc_feature_incs="#include 107 | #define var(dummy, ...) sprintf(__VA_ARGS__)" 108 | tc_feature_path= 109 | tc_feature_libs= 110 | tc_feature_test="char buf[30]; buf[0] = '0'; 111 | var(0, buf, \"%d\", 1); 112 | if (buf[0] != '1') return 1" 113 | . auto/feature 114 | 115 | 116 | tc_feature="gcc variadic macros" 117 | tc_feature_name="TC_HAVE_GCC_VARIADIC_MACROS" 118 | tc_feature_run=yes 119 | tc_feature_incs="#include 120 | #define var(dummy, args...) sprintf(args)" 121 | tc_feature_path= 122 | tc_feature_libs= 123 | tc_feature_test="char buf[30]; buf[0] = '0'; 124 | var(0, buf, \"%d\", 1); 125 | if (buf[0] != '1') return 1" 126 | . auto/feature 127 | 128 | fi 129 | -------------------------------------------------------------------------------- /auto/cc/gcc: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | 6 | # gcc 2.7.2.3, 2.8.1, 2.95.4, egcs-1.1.2 7 | # 3.0.4, 3.1.1, 3.2.3, 3.3.2, 3.3.3, 3.3.4, 3.4.0, 3.4.2 8 | # 4.0.0, 4.0.1, 4.1.0 9 | 10 | 11 | TC_GCC_VER=`$CC -v 2>&1 | grep 'gcc version' 2>&1 \ 12 | | sed -e 's/^.* version \(.*\)/\1/'` 13 | 14 | echo " + gcc version: $TC_GCC_VER" 15 | 16 | have=TC_COMPILER value="\"gcc $TC_GCC_VER\"" . auto/define 17 | 18 | 19 | # Solaris 7's /usr/ccs/bin/as does not support "-pipe" 20 | 21 | CC_TEST_FLAGS="-pipe" 22 | 23 | tc_feature="gcc -pipe switch" 24 | tc_feature_name= 25 | tc_feature_run=no 26 | tc_feature_incs= 27 | tc_feature_path= 28 | tc_feature_libs= 29 | tc_feature_test= 30 | . auto/feature 31 | 32 | CC_TEST_FLAGS= 33 | 34 | if [ $tc_found = yes ]; then 35 | PIPE="-pipe" 36 | fi 37 | 38 | 39 | case "$TC_MACHINE" in 40 | 41 | sun4u | sun4v | sparc | sparc64 ) 42 | # "-mcpu=v9" enables the "casa" assembler instruction 43 | CFLAGS="$CFLAGS -mcpu=v9" 44 | ;; 45 | 46 | esac 47 | 48 | 49 | # optimizations 50 | 51 | #TC_GCC_OPT="-O2" 52 | #TC_GCC_OPT="-Os" 53 | #TC_GCC_OPT="-O3" 54 | 55 | #CFLAGS="$CFLAGS -fomit-frame-pointer" 56 | 57 | case $CPU in 58 | pentium) 59 | # optimize for Pentium and Athlon 60 | CPU_OPT="-march=pentium" 61 | TC_CPU_CACHE_LINE=32 62 | ;; 63 | 64 | pentiumpro | pentium3) 65 | # optimize for Pentium Pro, Pentium II and Pentium III 66 | CPU_OPT="-march=pentiumpro" 67 | TC_CPU_CACHE_LINE=32 68 | ;; 69 | 70 | pentium4) 71 | # optimize for Pentium 4, gcc 3.x 72 | CPU_OPT="-march=pentium4" 73 | TC_CPU_CACHE_LINE=128 74 | ;; 75 | 76 | athlon) 77 | # optimize for Athlon, gcc 3.x 78 | CPU_OPT="-march=athlon" 79 | TC_CPU_CACHE_LINE=64 80 | ;; 81 | 82 | opteron) 83 | # optimize for Opteron, gcc 3.x 84 | CPU_OPT="-march=opteron" 85 | TC_CPU_CACHE_LINE=64 86 | ;; 87 | 88 | sparc32) 89 | # build 32-bit UltraSparc binary 90 | CPU_OPT="-m32" 91 | CORE_LINK="$CORE_LINK -m32" 92 | TC_CPU_CACHE_LINE=64 93 | ;; 94 | 95 | sparc64) 96 | # build 64-bit UltraSparc binary 97 | CPU_OPT="-m64" 98 | CORE_LINK="$CORE_LINK -m64" 99 | TC_CPU_CACHE_LINE=64 100 | ;; 101 | 102 | ppc64) 103 | # build 64-bit PowerPC binary 104 | CPU_OPT="-m64" 105 | CPU_OPT="$CPU_OPT -falign-functions=32 -falign-labels=32" 106 | CPU_OPT="$CPU_OPT -falign-loops=32 -falign-jumps=32" 107 | CORE_LINK="$CORE_LINK -m64" 108 | TC_CPU_CACHE_LINE=128 109 | ;; 110 | 111 | esac 112 | 113 | CC_AUX_FLAGS="$CC_AUX_FLAGS $CPU_OPT" 114 | 115 | case "$TC_GCC_VER" in 116 | 2.7*) 117 | # batch build 118 | CPU_OPT= 119 | ;; 120 | esac 121 | 122 | 123 | CFLAGS="$CFLAGS $PIPE $CPU_OPT" 124 | 125 | CFLAGS="$CFLAGS -std=gnu99 -D_FILE_OFFSET_BITS=64" 126 | 127 | # warnings 128 | 129 | # -W requires at least -O 130 | #CFLAGS="$CFLAGS ${TC_GCC_OPT:--O}" 131 | 132 | #CFLAGS="$CFLAGS -Wall -Wpointer-arith" 133 | #CFLAGS="$CFLAGS -Wconversion" 134 | #CFLAGS="$CFLAGS -Winline" 135 | #CFLAGS="$CFLAGS -Wmissing-prototypes" 136 | 137 | 138 | case "$TC_GCC_VER" in 139 | 3.* | 4.* ) 140 | # we have a lot of the unused function arguments 141 | CFLAGS="$CFLAGS -Wno-unused-parameter" 142 | # 4.2.1 shows the warning in wrong places 143 | #CFLAGS="$CFLAGS -Wunreachable-code" 144 | ;; 145 | 146 | *) 147 | # we have a lot of the unused function arguments 148 | CFLAGS="$CFLAGS -Wno-unused" 149 | ;; 150 | esac 151 | 152 | 153 | CFLAGS="$CFLAGS -W -Wall -Wunused-function -pedantic" 154 | 155 | # debug 156 | CFLAGS="$CFLAGS -g" 157 | 158 | # DragonFly's gcc3 generates DWARF 159 | #CFLAGS="$CFLAGS -g -gstabs" 160 | 161 | if [ ".$CPP" = "." ]; then 162 | CPP="$CC -E" 163 | fi 164 | -------------------------------------------------------------------------------- /auto/cc/icc: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Intel C++ compiler 7.1, 8.0, 8.1, 9.0, 11.1 4 | 5 | TC_ICC_VER=`$CC -V 2>&1 | grep 'Version' 2>&1 \ 6 | | sed -e 's/^.* Version \([^ ]*\) *Build.*$/\1/'` 7 | 8 | echo " + icc version: $TC_ICC_VER" 9 | 10 | have=TC_COMPILER value="\"Intel C Compiler $TC_ICC_VER\"" . auto/define 11 | 12 | 13 | # optimizations 14 | 15 | CFLAGS="$CFLAGS -O" 16 | 17 | CORE_LINK="$CORE_LINK -opt_report_file=$TC_OBJS/opt_report_file" 18 | 19 | 20 | case $CPU in 21 | pentium) 22 | # optimize for Pentium and Athlon 23 | CPU_OPT="-march=pentium" 24 | ;; 25 | 26 | pentiumpro) 27 | # optimize for Pentium Pro, Pentium II and Pentium III 28 | CPU_OPT="-mcpu=pentiumpro -march=pentiumpro" 29 | ;; 30 | 31 | pentium4) 32 | # optimize for Pentium 4, default 33 | CPU_OPT="-march=pentium4" 34 | ;; 35 | esac 36 | 37 | CFLAGS="$CFLAGS $CPU_OPT" 38 | 39 | CFLAGS="$CFLAGS -std=gnu99 -D_FILE_OFFSET_BITS=64" 40 | 41 | # warnings 42 | 43 | CFLAGS="$CFLAGS -w2" 44 | 45 | # disable some warnings 46 | 47 | # invalid type conversion: "int" to "char *" 48 | CFLAGS="$CFLAGS -wd171" 49 | # argument is incompatible with corresponding format string conversion 50 | CFLAGS="$CFLAGS -wd181" 51 | # zero used for undefined preprocessing identifier 52 | CFLAGS="$CFLAGS -wd193" 53 | # the format string ends before this argument 54 | CFLAGS="$CFLAGS -wd268" 55 | # invalid format string conversion 56 | CFLAGS="$CFLAGS -wd269" 57 | # conversion from "long long" to "size_t" may lose significant bits 58 | CFLAGS="$CFLAGS -wd810" 59 | # parameter was never referenced 60 | CFLAGS="$CFLAGS -wd869" 61 | # attribute "unused" is only allowed in a function definition, warning on pTHX_ 62 | CFLAGS="$CFLAGS -wd1301" 63 | 64 | # STUB 65 | # enumerated type mixed with another type 66 | CFLAGS="$CFLAGS -wd188" 67 | # controlling expression is constant 68 | CFLAGS="$CFLAGS -wd279" 69 | # operands are evaluated in unspecified order 70 | CFLAGS="$CFLAGS -wd981" 71 | # external definition with no prior declaration 72 | CFLAGS="$CFLAGS -wd1418" 73 | # external declaration in primary source file 74 | CFLAGS="$CFLAGS -wd1419" 75 | 76 | case "$TC_ICC_VER" in 77 | 9.*) 78 | # "cc" clobber ignored, warnings for Liunx's htonl()/htons() 79 | CFLAGS="$CFLAGS -wd1469" 80 | # explicit conversion of a 64-bit integral type to a smaller 81 | # integral type 82 | CFLAGS="$CFLAGS -wd1683" 83 | # conversion from pointer to same-sized integral type, 84 | # warning on offsetof() 85 | CFLAGS="$CFLAGS -wd1684" 86 | # floating-point equality and inequality comparisons are unreliable, 87 | # warning on SvTRUE() 88 | CFLAGS="$CFLAGS -wd1572" 89 | ;; 90 | 91 | 8.*) 92 | # "cc" clobber ignored, warnings for Liunx's htonl()/htons() 93 | CFLAGS="$CFLAGS -wd1469" 94 | # floating-point equality and inequality comparisons are unreliable, 95 | # warning on SvTRUE() 96 | CFLAGS="$CFLAGS -wd1572" 97 | ;; 98 | 99 | *) 100 | ;; 101 | esac 102 | 103 | CFLAGS="$CFLAGS -W -Wall -Wunused-function -pedantic" 104 | 105 | # debug 106 | CFLAGS="$CFLAGS -g" 107 | -------------------------------------------------------------------------------- /auto/cc/name: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | 6 | tc_feature="C compiler" 7 | tc_feature_name= 8 | tc_feature_run=yes 9 | tc_feature_incs= 10 | tc_feature_path= 11 | tc_feature_libs= 12 | tc_feature_test= 13 | . auto/feature 14 | 15 | if [ $tc_found = no ]; then 16 | echo 17 | echo $0: error: C compiler $CC is not found 18 | echo 19 | exit 1 20 | fi 21 | 22 | 23 | 24 | if [ "$CC" = cl ]; then 25 | if `$TC_WINE $CC -v 2>&1 \ 26 | | grep '^Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16' \ 27 | >/dev/null 2>&1`; then 28 | 29 | TC_CC_NAME=msvc10 30 | echo " + using Microsoft Visual C++ 10 compiler" 31 | 32 | elif `$TC_WINE $CC -v 2>&1 \ 33 | | grep '^Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14' \ 34 | >/dev/null 2>&1`; then 35 | 36 | TC_CC_NAME=msvc8 37 | echo " + using Microsoft Visual C++ 8 compiler" 38 | 39 | elif `$TC_WINE $CC -v 2>&1 \ 40 | | grep '^Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13' \ 41 | >/dev/null 2>&1`; then 42 | 43 | TC_CC_NAME=msvc7 44 | echo " + using Microsoft Visual C++ 7 compiler" 45 | 46 | else 47 | TC_CC_NAME=msvc 48 | echo " + using Microsoft Visual C++ compiler" 49 | fi 50 | 51 | elif `$CC -V 2>&1 | grep '^Intel(R) C' >/dev/null 2>&1`; then 52 | TC_CC_NAME=icc 53 | echo " + using Intel C++ compiler" 54 | 55 | elif `$CC -v 2>&1 | grep 'gcc version' >/dev/null 2>&1`; then 56 | TC_CC_NAME=gcc 57 | echo " + using GNU C compiler" 58 | 59 | elif `$CC -v 2>&1 | grep 'clang version' >/dev/null 2>&1`; then 60 | TC_CC_NAME=clang 61 | echo " + using Clang C compiler" 62 | 63 | elif `$CC -V 2>&1 | grep '^aCC: ' >/dev/null 2>&1`; then 64 | TC_CC_NAME=acc 65 | echo " + using HP aC++ compiler" 66 | 67 | else 68 | TC_CC_NAME=unknown 69 | 70 | fi 71 | -------------------------------------------------------------------------------- /auto/define: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | cat << END >> $TC_AUTO_CONFIG_H 6 | 7 | #ifndef $have 8 | #define $have $value 9 | #endif 10 | 11 | END 12 | -------------------------------------------------------------------------------- /auto/feature: -------------------------------------------------------------------------------- 1 | 2 | 3 | echo $tc_n "checking for $tc_feature ...$tc_c" 4 | 5 | cat << END >> $TC_AUTOCONF_ERR 6 | 7 | ---------------------------------------- 8 | checking for $tc_feature 9 | 10 | END 11 | 12 | tc_found=no 13 | 14 | if test -n "$tc_feature_name"; then 15 | tc_have_feature=`echo $tc_feature_name \ 16 | | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ` 17 | fi 18 | 19 | if test -n "$tc_feature_path"; then 20 | for tc_temp in $tc_feature_path; do 21 | tc_feature_inc_path="$tc_feature_inc_path -I $tc_temp" 22 | done 23 | fi 24 | 25 | cat << END > $TC_AUTOTEST.c 26 | 27 | #include 28 | $TC_INCLUDE_UNISTD_H 29 | $tc_feature_incs 30 | 31 | int main() { 32 | $tc_feature_test; 33 | return 0; 34 | } 35 | 36 | END 37 | 38 | 39 | tc_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $tc_feature_inc_path \ 40 | -o $TC_AUTOTEST $TC_AUTOTEST.c $TC_TEST_LD_OPT $tc_feature_libs" 41 | 42 | tc_feature_inc_path= 43 | 44 | eval "/bin/sh -c \"$tc_test\" >> $TC_AUTOCONF_ERR 2>&1" 45 | 46 | 47 | if [ -x $TC_AUTOTEST ]; then 48 | 49 | case "$tc_feature_run" in 50 | 51 | yes) 52 | # /bin/sh is used to intercept "Killed" or "Abort trap" messages 53 | if /bin/sh -c $TC_AUTOTEST >> $TC_AUTOCONF_ERR 2>&1; then 54 | echo " found" 55 | tc_found=yes 56 | 57 | if test -n "$tc_feature_name"; then 58 | have=$tc_have_feature . auto/have 59 | fi 60 | 61 | else 62 | echo " found but is not working" 63 | fi 64 | ;; 65 | 66 | value) 67 | # /bin/sh is used to intercept "Killed" or "Abort trap" messages 68 | if /bin/sh -c $TC_AUTOTEST >> $TC_AUTOCONF_ERR 2>&1; then 69 | echo " found" 70 | tc_found=yes 71 | 72 | cat << END >> $TC_AUTO_CONFIG_H 73 | 74 | #ifndef $tc_feature_name 75 | #define $tc_feature_name `$TC_AUTOTEST` 76 | #endif 77 | 78 | END 79 | else 80 | echo " found but is not working" 81 | fi 82 | ;; 83 | 84 | bug) 85 | # /bin/sh is used to intercept "Killed" or "Abort trap" messages 86 | if /bin/sh -c $TC_AUTOTEST >> $TC_AUTOCONF_ERR 2>&1; then 87 | echo " not found" 88 | 89 | else 90 | echo " found" 91 | tc_found=yes 92 | 93 | if test -n "$tc_feature_name"; then 94 | have=$tc_have_feature . auto/have 95 | fi 96 | fi 97 | ;; 98 | 99 | *) 100 | echo " found" 101 | tc_found=yes 102 | 103 | if test -n "$tc_feature_name"; then 104 | have=$tc_have_feature . auto/have 105 | fi 106 | ;; 107 | 108 | esac 109 | 110 | else 111 | echo " not found" 112 | 113 | echo "----------" >> $TC_AUTOCONF_ERR 114 | cat $TC_AUTOTEST.c >> $TC_AUTOCONF_ERR 115 | echo "----------" >> $TC_AUTOCONF_ERR 116 | echo $tc_test >> $TC_AUTOCONF_ERR 117 | echo "----------" >> $TC_AUTOCONF_ERR 118 | fi 119 | 120 | rm $TC_AUTOTEST* 121 | -------------------------------------------------------------------------------- /auto/have: -------------------------------------------------------------------------------- 1 | 2 | cat << END >> $TC_AUTO_CONFIG_H 3 | 4 | #ifndef $have 5 | #define $have 1 6 | #endif 7 | 8 | END 9 | -------------------------------------------------------------------------------- /auto/have_headers: -------------------------------------------------------------------------------- 1 | cat << END >> $TC_AUTO_HEADERS_H 2 | 3 | #ifndef $have 4 | #define $have 1 5 | #endif 6 | 7 | END 8 | -------------------------------------------------------------------------------- /auto/headers: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | tc_include="unistd.h"; . auto/include 6 | tc_include="limits.h"; . auto/include 7 | tc_include="inttypes.h"; . auto/include 8 | tc_include="pcap.h"; . auto/include 9 | -------------------------------------------------------------------------------- /auto/include: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | 6 | echo $tc_n "checking for $tc_include ...$tc_c" 7 | 8 | cat << END >> $TC_AUTOCONF_ERR 9 | 10 | ---------------------------------------- 11 | checking for $tc_include 12 | 13 | END 14 | 15 | 16 | tc_found=no 17 | 18 | cat << END > $TC_AUTOTEST.c 19 | 20 | $TC_INCLUDE_SYS_PARAM_H 21 | #include <$tc_include> 22 | 23 | int main() { 24 | return 0; 25 | } 26 | 27 | END 28 | 29 | 30 | tc_test="$CC -o $TC_AUTOTEST $TC_AUTOTEST.c" 31 | 32 | eval "$tc_test >> $TC_AUTOCONF_ERR 2>&1" 33 | 34 | if [ -x $TC_AUTOTEST ]; then 35 | 36 | tc_found=yes 37 | 38 | echo " found" 39 | 40 | tc_name=`echo $tc_include \ 41 | | tr abcdefghijklmnopqrstuvwxyz/. ABCDEFGHIJKLMNOPQRSTUVWXYZ__` 42 | 43 | 44 | have=TC_HAVE_$tc_name . auto/have_headers 45 | 46 | eval "TC_INCLUDE_$tc_name='#include <$tc_include>'" 47 | 48 | #STUB 49 | eval "TC_$tc_name='#include <$tc_include>'" 50 | 51 | else 52 | echo " not found" 53 | 54 | echo "----------" >> $TC_AUTOCONF_ERR 55 | cat $TC_AUTOTEST.c >> $TC_AUTOCONF_ERR 56 | echo "----------" >> $TC_AUTOCONF_ERR 57 | echo $tc_test >> $TC_AUTOCONF_ERR 58 | echo "----------" >> $TC_AUTOCONF_ERR 59 | 60 | exit 1 61 | fi 62 | 63 | rm $TC_AUTOTEST* 64 | -------------------------------------------------------------------------------- /auto/init: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | TC_MAKEFILE=$TC_OBJS/Makefile 6 | 7 | TC_AUTO_HEADERS_H=$TC_OBJS/tc_auto_headers.h 8 | TC_AUTO_CONFIG_H=$TC_OBJS/tc_auto_config.h 9 | 10 | TC_AUTOTEST=$TC_OBJS/autotest 11 | TC_AUTOCONF_ERR=$TC_OBJS/autoconf.err 12 | 13 | TC_ERR=$TC_OBJS/autoconf.err 14 | MAKEFILE=$TC_OBJS/Makefile 15 | 16 | 17 | TC_PCH= 18 | TC_USE_PCH= 19 | 20 | if echo "test\c" | grep c >/dev/null; then 21 | 22 | if echo -n test | grep n >/dev/null; then 23 | tc_n= 24 | tc_c= 25 | 26 | else 27 | tc_n=-n 28 | tc_c= 29 | fi 30 | 31 | else 32 | tc_n= 33 | tc_c='\c' 34 | fi 35 | 36 | 37 | # create Makefile 38 | 39 | cat << END > Makefile 40 | 41 | default: build 42 | 43 | clean: 44 | rm -rf Makefile $TC_OBJS 45 | END 46 | -------------------------------------------------------------------------------- /auto/install: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | case ".$TC_SBIN_PATH" in 6 | ./*) 7 | ;; 8 | 9 | .) 10 | TC_SBIN_PATH=$TC_PREFIX/sbin/tcpburn 11 | ;; 12 | 13 | *) 14 | TC_SBIN_PATH=$TC_PREFIX/$TC_SBIN_PATH 15 | ;; 16 | esac 17 | 18 | 19 | case ".$TC_CONF_PATH" in 20 | ./*) 21 | ;; 22 | 23 | *) 24 | TC_CONF_PATH=$TC_PREFIX/$TC_CONF_PATH 25 | ;; 26 | esac 27 | 28 | 29 | TC_CONF_PREFIX=`dirname $TC_CONF_PATH` 30 | 31 | 32 | case ".$TC_PID_PATH" in 33 | ./*) 34 | ;; 35 | 36 | *) 37 | TC_PID_PATH=$TC_PREFIX/$TC_PID_PATH 38 | ;; 39 | esac 40 | 41 | case ".$TC_ERROR_LOG_PATH" in 42 | ./* | .) 43 | ;; 44 | 45 | *) 46 | TC_ERROR_LOG_PATH=$TC_PREFIX/$TC_ERROR_LOG_PATH 47 | ;; 48 | esac 49 | 50 | cat << END >> $TC_MAKEFILE 51 | 52 | install: $TC_OBJS${tc_dirsep}tcpburn 53 | test -d '\$(DESTDIR)$TC_PREFIX' || mkdir -p '\$(DESTDIR)$TC_PREFIX' 54 | 55 | test -d '\$(DESTDIR)`dirname "$TC_SBIN_PATH"`' \ 56 | || mkdir -p '\$(DESTDIR)`dirname "$TC_SBIN_PATH"`' 57 | test ! -f '\$(DESTDIR)$TC_SBIN_PATH' \ 58 | || mv '\$(DESTDIR)$TC_SBIN_PATH' \ 59 | '\$(DESTDIR)$TC_SBIN_PATH.old' 60 | cp $TC_OBJS/tcpburn '\$(DESTDIR)$TC_SBIN_PATH' 61 | 62 | test -d '\$(DESTDIR)`dirname "$TC_PID_PATH"`' \ 63 | || mkdir -p '\$(DESTDIR)`dirname "$TC_PID_PATH"`' 64 | 65 | END 66 | 67 | 68 | if test -n "$TC_ERROR_LOG_PATH"; then 69 | cat << END >> $TC_MAKEFILE 70 | 71 | test -d '\$(DESTDIR)`dirname "$TC_ERROR_LOG_PATH"`' || \ 72 | mkdir -p '\$(DESTDIR)`dirname "$TC_ERROR_LOG_PATH"`' 73 | END 74 | 75 | fi 76 | 77 | 78 | # create Makefile 79 | 80 | cat << END >> Makefile 81 | 82 | build: 83 | \$(MAKE) -f $TC_MAKEFILE 84 | 85 | install: 86 | \$(MAKE) -f $TC_MAKEFILE install 87 | END 88 | 89 | -------------------------------------------------------------------------------- /auto/linux: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | 6 | tc_feature="O_DIRECT" 7 | tc_feature_name="TC_HAVE_O_DIRECT" 8 | tc_feature_run=no 9 | tc_feature_incs="#include " 10 | tc_feature_path= 11 | tc_feature_libs= 12 | tc_feature_test="fcntl(0, F_SETFL, O_DIRECT);" 13 | . auto/feature 14 | 15 | 16 | tc_feature="TCP_DEFER_ACCEPT" 17 | tc_feature_name="TC_HAVE_DEFERRED_ACCEPT" 18 | tc_feature_run=no 19 | tc_feature_incs="#include 20 | #include 21 | #include " 22 | tc_feature_path= 23 | tc_feature_libs= 24 | tc_feature_test="setsockopt(0, IPPROTO_TCP, TCP_DEFER_ACCEPT, NULL, 0)" 25 | . auto/feature 26 | 27 | 28 | tc_feature="TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT" 29 | tc_feature_name="TC_HAVE_KEEPALIVE_TUNABLE" 30 | tc_feature_run=no 31 | tc_feature_incs="#include 32 | #include 33 | #include " 34 | tc_feature_path= 35 | tc_feature_libs= 36 | tc_feature_test="setsockopt(0, IPPROTO_TCP, TCP_KEEPIDLE, NULL, 0); 37 | setsockopt(0, IPPROTO_TCP, TCP_KEEPINTVL, NULL, 0); 38 | setsockopt(0, IPPROTO_TCP, TCP_KEEPCNT, NULL, 0)" 39 | . auto/feature 40 | 41 | 42 | tc_feature="TCP_INFO" 43 | tc_feature_name="TC_HAVE_TCP_INFO" 44 | tc_feature_run=no 45 | tc_feature_incs="#include 46 | #include 47 | #include " 48 | tc_feature_path= 49 | tc_feature_libs= 50 | tc_feature_test="socklen_t optlen = sizeof(struct tcp_info); 51 | struct tcp_info ti; 52 | ti.tcpi_rtt = 0; 53 | ti.tcpi_rttvar = 0; 54 | ti.tcpi_snd_cwnd = 0; 55 | ti.tcpi_rcv_space = 0; 56 | getsockopt(0, IPPROTO_TCP, TCP_INFO, &ti, &optlen)" 57 | . auto/feature 58 | 59 | 60 | # C types 61 | 62 | tc_type="int"; . auto/types/sizeof 63 | 64 | tc_type="long"; . auto/types/sizeof 65 | 66 | tc_type="long long"; . auto/types/sizeof 67 | 68 | tc_type="void *"; . auto/types/sizeof; tc_ptr_size=$tc_size 69 | tc_param=TC_PTR_SIZE; tc_value=$tc_size; . auto/types/value 70 | 71 | 72 | # POSIX types 73 | 74 | case "$TC_AUTO_CONFIG_H" in 75 | /*) 76 | TC_INCLUDE_AUTO_CONFIG_H="#include \"$TC_AUTO_CONFIG_H\"" 77 | ;; 78 | *) 79 | TC_INCLUDE_AUTO_CONFIG_H="#include \"../$TC_AUTO_CONFIG_H\"" 80 | ;; 81 | esac 82 | 83 | tc_type="uint64_t"; tc_types="u_int64_t"; . auto/types/typedef 84 | 85 | tc_type="sig_atomic_t"; tc_types="int"; . auto/types/typedef 86 | . auto/types/sizeof 87 | tc_param=TC_SIG_ATOMIC_T_SIZE; tc_value=$tc_size; . auto/types/value 88 | 89 | tc_type="socklen_t"; tc_types="int"; . auto/types/typedef 90 | 91 | tc_type="in_addr_t"; tc_types="uint32_t"; . auto/types/typedef 92 | 93 | tc_type="in_port_t"; tc_types="u_short"; . auto/types/typedef 94 | 95 | tc_type="rlim_t"; tc_types="int"; . auto/types/typedef 96 | 97 | . auto/types/uintptr_t 98 | 99 | tc_type="size_t"; . auto/types/sizeof 100 | tc_param=TC_MAX_SIZE_T_VALUE; tc_value=$tc_max_value; . auto/types/value 101 | tc_param=TC_SIZE_T_LEN; tc_value=$tc_max_len; . auto/types/value 102 | 103 | tc_type="off_t"; . auto/types/sizeof 104 | tc_param=TC_MAX_OFF_T_VALUE; tc_value=$tc_max_value; . auto/types/value 105 | tc_param=TC_OFF_T_LEN; tc_value=$tc_max_len; . auto/types/value 106 | 107 | tc_type="time_t"; . auto/types/sizeof 108 | tc_param=TC_TIME_T_SIZE; tc_value=$tc_size; . auto/types/value 109 | tc_param=TC_TIME_T_LEN; tc_value=$tc_max_len; . auto/types/value 110 | 111 | 112 | tc_feature="pread()" 113 | tc_feature_name="TC_HAVE_PREAD" 114 | tc_feature_run=no 115 | tc_feature_incs= 116 | tc_feature_path= 117 | tc_feature_libs= 118 | tc_feature_test="char buf[1]; ssize_t n; n = pread(0, buf, 1, 0); 119 | if (n == -1) return 1" 120 | . auto/feature 121 | 122 | 123 | tc_feature="pwrite()" 124 | tc_feature_name="TC_HAVE_PWRITE" 125 | tc_feature_run=no 126 | tc_feature_incs= 127 | tc_feature_path= 128 | tc_feature_libs= 129 | tc_feature_test="char buf[1]; ssize_t n; n = pwrite(1, buf, 1, 0); 130 | if (n == -1) return 1" 131 | . auto/feature 132 | 133 | 134 | tc_feature="posix_memalign()" 135 | tc_feature_name="TC_HAVE_POSIX_MEMALIGN" 136 | tc_feature_run=no 137 | tc_feature_incs="#include " 138 | tc_feature_path= 139 | tc_feature_libs= 140 | tc_feature_test="void *p; int n; n = posix_memalign(&p, 4096, 4096); 141 | if (n != 0) return 1" 142 | . auto/feature 143 | 144 | 145 | tc_feature="memalign()" 146 | tc_feature_name="TC_HAVE_MEMALIGN" 147 | tc_feature_run=no 148 | tc_feature_incs="#include 149 | #include " 150 | tc_feature_path= 151 | tc_feature_libs= 152 | tc_feature_test="void *p; p = memalign(4096, 4096); 153 | if (p == NULL) return 1" 154 | . auto/feature 155 | 156 | 157 | tc_feature="mmap(MAP_ANON|MAP_SHARED)" 158 | tc_feature_name="TC_HAVE_MAP_ANON" 159 | tc_feature_run=yes 160 | tc_feature_incs="#include " 161 | tc_feature_path= 162 | tc_feature_libs= 163 | tc_feature_test="void *p; 164 | p = mmap(NULL, 4096, PROT_READ|PROT_WRITE, 165 | MAP_ANON|MAP_SHARED, -1, 0); 166 | if (p == MAP_FAILED) return 1;" 167 | . auto/feature 168 | 169 | 170 | tc_feature='mmap("/dev/zero", MAP_SHARED)' 171 | tc_feature_name="TC_HAVE_MAP_DEVZERO" 172 | tc_feature_run=yes 173 | tc_feature_incs="#include 174 | #include 175 | #include " 176 | tc_feature_path= 177 | tc_feature_libs= 178 | tc_feature_test='void *p; int fd; 179 | fd = open("/dev/zero", O_RDWR); 180 | p = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 181 | if (p == MAP_FAILED) return 1;' 182 | . auto/feature 183 | 184 | 185 | tc_feature="openat(), fstatat()" 186 | tc_feature_name="TC_HAVE_OPENAT" 187 | tc_feature_run=no 188 | tc_feature_incs="#include 189 | #include 190 | #include " 191 | tc_feature_path= 192 | tc_feature_libs= 193 | tc_feature_test="struct stat sb; 194 | openat(AT_FDCWD, \".\", O_RDONLY|O_NOFOLLOW); 195 | fstatat(AT_FDCWD, \".\", &sb, AT_SYMLINK_NOFOLLOW);" 196 | . auto/feature 197 | 198 | 199 | tc_feature="getaddrinfo()" 200 | tc_feature_name="TC_HAVE_GETADDRINFO" 201 | tc_feature_run=no 202 | tc_feature_incs="#include 203 | #include 204 | #include " 205 | tc_feature_path= 206 | tc_feature_libs= 207 | tc_feature_test='struct addrinfo *res; 208 | if (getaddrinfo("localhost", NULL, NULL, &res) != 0) return 1; 209 | freeaddrinfo(res)' 210 | . auto/feature 211 | -------------------------------------------------------------------------------- /auto/make: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | echo "creating $TC_MAKEFILE" 6 | 7 | mkdir -p $TC_OBJS/src/core $TC_OBJS/src/util\ 8 | $TC_OBJS/src/event $TC_OBJS/src/communication\ 9 | $TC_OBJS/src/burn 10 | 11 | tc_objs_dir=$TC_OBJS$tc_regex_dirsep 12 | 13 | 14 | cat << END > $TC_MAKEFILE 15 | 16 | CC = $CC 17 | CFLAGS = $CFLAGS 18 | CPP = $CPP 19 | LINK = $LINK 20 | 21 | END 22 | 23 | 24 | tc_incs=`echo $CORE_INCS $DIGEST_INCS $EVENT_INCS $COMMUNICATION_INCS $UTIL_INCS\ 25 | $BURN_INCS $TC_OBJS\ 26 | | sed -e "s/ *\([^ ][^ ]*\)/$tc_regex_cont$tc_include_opt\1/g" \ 27 | -e "s/\//$tc_regex_dirsep/g"` 28 | 29 | cat << END >> $TC_MAKEFILE 30 | 31 | ALL_INCS = $tc_include_opt$tc_incs 32 | 33 | END 34 | 35 | 36 | # the core dependences and include paths 37 | 38 | tc_deps=`echo $CORE_DEPS $DIGEST_DEPS $EVENT_DEPS $COMMUNICATION_DEPS $UTIL_DEPS\ 39 | $BURN_DEPS $TC_AUTO_CONFIG_H $TC_PCH \ 40 | | sed -e "s/ *\([^ ][^ ]*\)/$tc_regex_cont\1/g" \ 41 | -e "s/\//$tc_regex_dirsep/g"` 42 | 43 | tc_incs=`echo $CORE_INCS $DIGEST_INCS $EVENT_INCS $COMMUNICATION_INCS $UTIL_INCS\ 44 | $BURN_INCS $TC_OBJS\ 45 | | sed -e "s/ *\([^ ][^ ]*\)/$tc_regex_cont$tc_include_opt\1/g" \ 46 | -e "s/\//$tc_regex_dirsep/g"` 47 | 48 | cat << END >> $TC_MAKEFILE 49 | 50 | 51 | CORE_DEPS = $tc_deps 52 | 53 | 54 | CORE_INCS = $tc_include_opt$tc_incs 55 | 56 | END 57 | 58 | tc_common_srcs="$CORE_SRCS $DIGEST_SRCS $EVENT_SRCS $COMMUNICATION_SRCS $UTIL_SRCS" 59 | tc_client_srcs="$tc_common_srcs $BURN_SRCS" 60 | 61 | tc_client_with_no_plugin="$tc_client_srcs" 62 | 63 | # tcpburn 64 | 65 | tc_client_srcs=`echo $tc_client_srcs | sed -e "s/\//$tc_regex_dirsep/g"` 66 | 67 | for tc_src in $TC_ADDON_SRCS 68 | do 69 | tc_obj="addon/`basename \`dirname $tc_src\``" 70 | 71 | test -d $TC_OBJS/$tc_obj || mkdir -p $TC_OBJS/$tc_obj 72 | 73 | tc_obj=`echo $tc_obj/\`basename $tc_src\` \ 74 | | sed -e "s/\//$tc_regex_dirsep/g"` 75 | 76 | tc_client_srcs="$tc_client_srcs $tc_obj" 77 | done 78 | 79 | tc_all_objs=`echo $tc_client_srcs \ 80 | | sed -e "s#\([^ ]*\.\)cpp#$TC_OBJS\/\1$tc_objext#g" \ 81 | -e "s#\([^ ]*\.\)cc#$TC_OBJS\/\1$tc_objext#g" \ 82 | -e "s#\([^ ]*\.\)c#$TC_OBJS\/\1$tc_objext#g" \ 83 | -e "s#\([^ ]*\.\)S#$TC_OBJS\/\1$tc_objext#g"` 84 | 85 | if test -n "$TC_RES"; then 86 | tc_res=$TC_RES 87 | else 88 | tc_res="$TC_RC $TC_ICONS" 89 | tc_rcc=`echo $TC_RCC | sed -e "s/\//$tc_regex_dirsep/g"` 90 | fi 91 | 92 | tc_deps=`echo $tc_all_objs $tc_res $LINK_DEPS \ 93 | | sed -e "s/ *\([^ ][^ ]*\)/$tc_regex_cont\1/g" \ 94 | -e "s/\//$tc_regex_dirsep/g"` 95 | 96 | tc_objs=`echo $tc_all_objs \ 97 | | sed -e "s/ *\([^ ][^ ]*\)/$tc_long_regex_cont\1/g" \ 98 | -e "s/\//$tc_regex_dirsep/g"` 99 | 100 | if test -n "$TC_LD_OPT$CORE_LIBS"; then 101 | tc_libs=`echo $TC_LD_OPT $CORE_LIBS \ 102 | | sed -e "s/\//$tc_regex_dirsep/g" -e "s/^/$tc_long_regex_cont/"` 103 | fi 104 | 105 | tc_link=${CORE_LINK:+`echo $CORE_LINK \ 106 | | sed -e "s/\//$tc_regex_dirsep/g" -e "s/^/$tc_long_regex_cont/"`} 107 | 108 | 109 | cat << END >> $TC_MAKEFILE 110 | 111 | $TC_OBJS${tc_dirsep}tcpburn: $tc_deps$tc_spacer 112 | \$(LINK) ${tc_long_start}${tc_binout}$TC_OBJS${tc_dirsep}tcpburn$tc_long_cont$tc_objs$tc_libs$tc_link 113 | $tc_rcc 114 | ${tc_long_end} 115 | END 116 | 117 | 118 | tc_cc="\$(CC) $tc_compile_opt \$(CFLAGS) \$(CORE_INCS)" 119 | 120 | for tc_src in $tc_client_with_no_plugin 121 | do 122 | tc_src=`echo $tc_src | sed -e "s/\//$tc_regex_dirsep/g"` 123 | tc_obj=`echo $tc_src \ 124 | | sed -e "s#^\(.*\.\)cpp\\$#$tc_objs_dir\1$tc_objext#g" \ 125 | -e "s#^\(.*\.\)cc\\$#$tc_objs_dir\1$tc_objext#g" \ 126 | -e "s#^\(.*\.\)c\\$#$tc_objs_dir\1$tc_objext#g" \ 127 | -e "s#^\(.*\.\)S\\$#$tc_objs_dir\1$tc_objext#g"` 128 | 129 | cat << END >> $TC_MAKEFILE 130 | 131 | $tc_obj: \$(CORE_DEPS)$tc_cont$tc_src 132 | $tc_cc$tc_tab$tc_objout$tc_obj$tc_tab$tc_src$TC_AUX 133 | 134 | END 135 | 136 | done 137 | 138 | # the precompiled headers 139 | 140 | if test -n "$TC_PCH"; then 141 | echo "#include " > $TC_OBJS/tc_pch.c 142 | 143 | tc_pch="src/core/tc_config.h $OS_CONFIG $TC_OBJS/tc_auto_config.h" 144 | tc_pch=`echo "$TC_PCH: $tc_pch" | sed -e "s/\//$tc_regex_dirsep/g"` 145 | 146 | tc_src="\$(CC) \$(CFLAGS) $TC_BUILD_PCH $tc_compile_opt \$(ALL_INCS)" 147 | tc_src="$tc_src $tc_objout$TC_OBJS/tc_pch.obj $TC_OBJS/tc_pch.c" 148 | tc_src=`echo $tc_src | sed -e "s/\//$tc_regex_dirsep/g"` 149 | 150 | cat << END >> $TC_MAKEFILE 151 | 152 | $tc_pch 153 | $tc_src 154 | 155 | END 156 | 157 | fi 158 | -------------------------------------------------------------------------------- /auto/nohave: -------------------------------------------------------------------------------- 1 | 2 | 3 | cat << END >> $TC_AUTO_CONFIG_H 4 | 5 | #ifndef $have 6 | #define $have 0 7 | #endif 8 | 9 | END 10 | -------------------------------------------------------------------------------- /auto/options: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | help=no 6 | 7 | TC_PREFIX= 8 | TC_SBIN_PATH= 9 | TC_ERROR_LOG_PATH= 10 | TC_PID_PATH= 11 | 12 | CC=${CC:-cc} 13 | TC_OBJS=objs 14 | 15 | TC_PCAP_SEND=NO 16 | TC_TOPO=NO 17 | TC_COMBINED=YES 18 | TC_SINGLE=NO 19 | TC_COMET=NO 20 | TC_HIGH_PRESSURE_CHECK=NO 21 | TC_DEBUG=NO 22 | TC_DETECT_MEMORY=NO 23 | 24 | TC_CC_OPT= 25 | TC_LD_OPT= 26 | 27 | 28 | TC_ADDONS= 29 | 30 | opt= 31 | 32 | for option 33 | do 34 | opt="$opt `echo $option | sed -e \"s/\(--[^=]*=\)\(.* .*\)/\1'\2'/\"`" 35 | 36 | case "$option" in 37 | -*=*) value=`echo "$option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; 38 | *) value="" ;; 39 | esac 40 | 41 | case "$option" in 42 | --help) help=yes ;; 43 | 44 | --prefix=) TC_PREFIX="!" ;; 45 | --prefix=*) TC_PREFIX="$value" ;; 46 | --sbin-path=*) TC_SBIN_PATH="$value" ;; 47 | --error-log-path=*) TC_ERROR_LOG_PATH="$value";; 48 | --pid-path=*) TC_PID_PATH="$value" ;; 49 | 50 | --builddir=*) TC_OBJS="$value" ;; 51 | 52 | --with-cc=*) CC="$value" ;; 53 | --with-cc-opt=*) TC_CC_OPT="$value" ;; 54 | --with-ld-opt=*) TC_LD_OPT="$value" ;; 55 | 56 | --comet) TC_COMET=YES ;; 57 | --single) TC_SINGLE=YES ;; 58 | --topology) TC_TOPO=YES ;; 59 | --pcap-send) TC_PCAP_SEND=YES ;; 60 | --disable-combined) TC_COMBINED=NO ;; 61 | 62 | --with-debug) TC_DEBUG=YES ;; 63 | --with-high-pressure-check) TC_HIGH_PRESSURE_CHECK=YES ;; 64 | --with-detect-memory) TC_DETECT_MEMORY=YES ;; 65 | 66 | *) 67 | echo "$0: error: invalid option \"$option\"" 68 | exit 1 69 | ;; 70 | esac 71 | done 72 | 73 | 74 | TC_CONFIGURE="$opt" 75 | 76 | 77 | if [ $help = yes ]; then 78 | 79 | cat << END 80 | 81 | --help print this message 82 | 83 | --prefix=PATH set installation prefix 84 | --sbin-path=PATH set tcpburn binary pathname 85 | --pid-path=PATH set tcpburn.pid pathname 86 | 87 | --builddir=DIR set build directory 88 | 89 | --with-cc=PATH set C compiler pathname 90 | --with-cpp=PATH set C preprocessor pathname 91 | --with-cc-opt=OPTIONS set additional C compiler options 92 | --with-ld-opt=OPTIONS set additional linker options 93 | --with-debug enable debug logging 94 | --with-high-pressure-check enable high pressure check 95 | 96 | --comet run tcpburn at comet mode 97 | --single run tcpburn at non-distributed mode 98 | --topology run tcpburn at topology mode 99 | --pcap-send send packets at the data link 100 | --disable-combined disable combined response mode 101 | 102 | END 103 | 104 | exit 1 105 | fi 106 | 107 | 108 | TC_PID_PATH=${TC_PID_PATH:-logs/tcpburn.pid} 109 | 110 | if [ ".$TC_ERROR_LOG_PATH" = ".stderr" ]; then 111 | TC_ERROR_LOG_PATH= 112 | else 113 | TC_ERROR_LOG_PATH=${TC_ERROR_LOG_PATH:-logs/error_tcpburn.log} 114 | fi 115 | 116 | -------------------------------------------------------------------------------- /auto/os/conf: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | echo "checking for $TC_SYSTEM specific features" 6 | 7 | case "$TC_PLATFORM" in 8 | 9 | Linux:*) 10 | . auto/os/linux 11 | ;; 12 | 13 | esac 14 | 15 | 16 | case "$TC_MACHINE" in 17 | 18 | i386 | i686 | i86pc) 19 | have=TC_HAVE_NONALIGNED . auto/have 20 | TC_MACH_CACHE_LINE=32 21 | ;; 22 | 23 | amd64 | x86_64) 24 | have=TC_HAVE_NONALIGNED . auto/have 25 | TC_MACH_CACHE_LINE=64 26 | ;; 27 | 28 | *) 29 | have=TC_ALIGNMENT value=16 . auto/define 30 | TC_MACH_CACHE_LINE=32 31 | ;; 32 | 33 | esac 34 | 35 | if test -z "$TC_CPU_CACHE_LINE"; then 36 | TC_CPU_CACHE_LINE=$TC_MACH_CACHE_LINE 37 | fi 38 | 39 | have=TC_CPU_CACHE_LINE value=$TC_CPU_CACHE_LINE . auto/define 40 | -------------------------------------------------------------------------------- /auto/os/linux: -------------------------------------------------------------------------------- 1 | have=TC_LINUX . auto/have_headers 2 | 3 | CORE_INCS="$CORE_INCS" 4 | CORE_DEPS="$CORE_DEPS $LINUX_DEPS" 5 | CORE_SRCS="$CORE_SRCS $LINUX_SRCS" 6 | 7 | tc_spacer=' 8 | ' 9 | 10 | cc_aux_flags="$CC_AUX_FLAGS" 11 | CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" 12 | 13 | # Linux kernel version 14 | 15 | version=$((`uname -r \ 16 | | sed -n -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\).*/ \ 17 | \1*256*256+\2*256+\3/p' \ 18 | -e 's/^\([0-9][0-9]*\)\.\([0-9][0-9]*\).*/\1*256*256+\2*256/p'`)) 19 | 20 | version=${version:-0} 21 | 22 | -------------------------------------------------------------------------------- /auto/sources: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | CORE_INCS="src/core" 6 | 7 | CORE_DEPS="src/core/xcopy.h \ 8 | src/core/tc_config.h \ 9 | src/core/tc_alloc.h \ 10 | src/core/tc_link_list.h \ 11 | src/core/tc_palloc.h \ 12 | src/core/tc_rbtree.h \ 13 | src/core/tc_log.h \ 14 | src/core/tc_time.h \ 15 | src/core/tc_signal.h" 16 | 17 | 18 | CORE_SRCS="src/core/tc_alloc.c \ 19 | src/core/tc_log.c \ 20 | src/core/tc_palloc.c \ 21 | src/core/tc_link_list.c \ 22 | src/core/tc_signal.c \ 23 | src/core/tc_common.c \ 24 | src/core/tc_time.c \ 25 | src/core/tc_rbtree.c \ 26 | src/core/tc_daemon.c" 27 | 28 | EVENT_INCS="src/event" 29 | 30 | EVENT_DEPS="src/event/tc_event.h \ 31 | src/event/tc_event_timer.h \ 32 | src/event/tc_select_module.h" 33 | 34 | EVENT_SRCS="src/event/tc_event.c \ 35 | src/event/tc_event_timer.c \ 36 | src/event/tc_select_module.c" 37 | 38 | 39 | COMMUNICATION_INCS="src/communication" 40 | 41 | COMMUNICATION_DEPS="src/communication/tc_socket.h" 42 | 43 | COMMUNICATION_SRCS="src/communication/tc_socket.c" 44 | 45 | 46 | UTIL_INCS="src/util" 47 | 48 | UTIL_DEPS="src/util/tc_util.h" 49 | 50 | UTIL_SRCS="src/util/tc_util.c" 51 | 52 | 53 | BURN_INCS="src/burn" 54 | 55 | BURN_DEPS="src/burn/burn.h \ 56 | src/burn/tc_manager.h \ 57 | src/burn/tc_message_module.h \ 58 | src/burn/tc_packets_module.h \ 59 | src/burn/tc_user.h" 60 | 61 | BURN_SRCS="src/burn/tc_manager.c \ 62 | src/burn/tc_packets_module.c \ 63 | src/burn/tc_message_module.c \ 64 | src/burn/tc_user.c \ 65 | src/burn/main.c" 66 | 67 | -------------------------------------------------------------------------------- /auto/summary: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | echo 6 | echo "Configuration summary" 7 | 8 | 9 | echo 10 | 11 | 12 | cat << END 13 | tcpburn path prefix: "$TC_PREFIX" 14 | tcpburn binary file: "$TC_SBIN_PATH" 15 | tcpburn pid file: "$TC_PID_PATH" 16 | END 17 | 18 | if test -n "$TC_ERROR_LOG_PATH"; then 19 | echo " tcpburn error log file: \"$TC_ERROR_LOG_PATH\"" 20 | else 21 | echo " tcpburn logs errors to stderr" 22 | fi 23 | -------------------------------------------------------------------------------- /auto/types/sizeof: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | 6 | echo $tc_n "checking for $tc_type size ...$tc_c" 7 | 8 | cat << END >> $TC_AUTOCONF_ERR 9 | 10 | ---------------------------------------- 11 | checking for $tc_type size 12 | 13 | END 14 | 15 | tc_size= 16 | 17 | cat << END > $TC_AUTOTEST.c 18 | 19 | #include 20 | #include 21 | $TC_INCLUDE_UNISTD_H 22 | #include 23 | #include 24 | #include 25 | $TC_INCLUDE_INTTYPES_H 26 | $TC_INCLUDE_AUTO_CONFIG_H 27 | 28 | int main() { 29 | printf("%d", (int) sizeof($tc_type)); 30 | return 0; 31 | } 32 | 33 | END 34 | 35 | 36 | tc_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ 37 | -o $TC_AUTOTEST $TC_AUTOTEST.c $TC_LD_OPT $tc_feature_libs" 38 | 39 | eval "$tc_test >> $TC_AUTOCONF_ERR 2>&1" 40 | 41 | 42 | if [ -x $TC_AUTOTEST ]; then 43 | tc_size=`$TC_AUTOTEST` 44 | echo " $tc_size bytes" 45 | fi 46 | 47 | 48 | rm -f $TC_AUTOTEST 49 | 50 | 51 | case $tc_size in 52 | 4) 53 | if [ "$tc_type"="long" ]; then 54 | tc_max_value=2147483647L 55 | else 56 | tc_max_value=2147483647 57 | fi 58 | 59 | tc_max_len='(sizeof("-2147483648") - 1)' 60 | ;; 61 | 62 | 8) 63 | if [ "$tc_type"="long long" ]; then 64 | tc_max_value=9223372036854775807LL 65 | else 66 | tc_max_value=9223372036854775807L 67 | fi 68 | 69 | tc_max_len='(sizeof("-9223372036854775808") - 1)' 70 | ;; 71 | 72 | *) 73 | echo 74 | echo "$0: error: can not detect $tc_type size" 75 | 76 | echo "----------" >> $TC_AUTOCONF_ERR 77 | cat $TC_AUTOTEST.c >> $TC_AUTOCONF_ERR 78 | echo "----------" >> $TC_AUTOCONF_ERR 79 | echo $tc_test >> $TC_AUTOCONF_ERR 80 | echo "----------" >> $TC_AUTOCONF_ERR 81 | 82 | exit 1 83 | esac 84 | 85 | -------------------------------------------------------------------------------- /auto/types/typedef: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | 6 | echo $tc_n "checking for $tc_type ...$tc_c" 7 | 8 | cat << END >> $TC_AUTOCONF_ERR 9 | 10 | ---------------------------------------- 11 | checking for $tc_type 12 | 13 | END 14 | 15 | tc_found=no 16 | 17 | for tc_try in $tc_type $tc_types 18 | do 19 | 20 | cat << END > $TC_AUTOTEST.c 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | $TC_INCLUDE_INTTYPES_H 29 | 30 | int main() { 31 | $tc_try i = 0; 32 | return (int) i; 33 | } 34 | 35 | END 36 | 37 | tc_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ 38 | -o $TC_AUTOTEST $TC_AUTOTEST.c $TC_LD_OPT $tc_feature_libs" 39 | 40 | eval "$tc_test >> $TC_AUTOCONF_ERR 2>&1" 41 | 42 | if [ -x $TC_AUTOTEST ]; then 43 | if [ $tc_try = $tc_type ]; then 44 | echo " found" 45 | tc_found=yes 46 | else 47 | echo ", $tc_try used" 48 | tc_found=$tc_try 49 | fi 50 | fi 51 | 52 | rm -f $TC_AUTOTEST 53 | 54 | if [ $tc_found = no ]; then 55 | echo $tc_n " $tc_try not found$tc_c" 56 | 57 | echo "----------" >> $TC_AUTOCONF_ERR 58 | cat $TC_AUTOTEST.c >> $TC_AUTOCONF_ERR 59 | echo "----------" >> $TC_AUTOCONF_ERR 60 | echo $tc_test >> $TC_AUTOCONF_ERR 61 | echo "----------" >> $TC_AUTOCONF_ERR 62 | 63 | else 64 | break 65 | fi 66 | done 67 | 68 | if [ $tc_found = no ]; then 69 | echo 70 | echo "$0: error: can not define $tc_type" 71 | 72 | exit 1 73 | fi 74 | 75 | if [ $tc_found != yes ]; then 76 | echo "typedef $tc_found $tc_type;" >> $TC_AUTO_CONFIG_H 77 | fi 78 | -------------------------------------------------------------------------------- /auto/types/uintptr_t: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | 6 | echo $tc_n "checking for uintptr_t ...$tc_c" 7 | echo >> $TC_AUTOCONF_ERR 8 | echo "checking for uintptr_t" >> $TC_AUTOCONF_ERR 9 | 10 | found=no 11 | 12 | cat << END > $TC_AUTOTEST.c 13 | 14 | #include 15 | $TC_INTTYPES_H 16 | 17 | int main() { 18 | uintptr_t i = 0; 19 | return (int) i; 20 | } 21 | 22 | END 23 | 24 | tc_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ 25 | -o $TC_AUTOTEST $TC_AUTOTEST.c $TC_LD_OPT" 26 | 27 | eval "$tc_test >> $TC_AUTOCONF_ERR 2>&1" 28 | 29 | if [ -x $TC_AUTOTEST ]; then 30 | echo " uintptr_t found" 31 | found=yes 32 | else 33 | echo $tc_n " uintptr_t not found" $tc_c 34 | fi 35 | 36 | rm $TC_AUTOTEST* 37 | 38 | 39 | if [ $found = no ]; then 40 | found="uint`expr 8 \* $tc_ptr_size`_t" 41 | echo ", $found used" 42 | 43 | echo "typedef $found uintptr_t;" >> $TC_AUTO_CONFIG_H 44 | echo "typedef $found intptr_t;" | sed -e 's/u//g' >> $TC_AUTO_CONFIG_H 45 | fi 46 | -------------------------------------------------------------------------------- /auto/types/value: -------------------------------------------------------------------------------- 1 | 2 | 3 | cat << END >> $TC_AUTO_CONFIG_H 4 | 5 | #ifndef $tc_param 6 | #define $tc_param $tc_value 7 | #endif 8 | 9 | END 10 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | LC_ALL=C 4 | export LC_ALL 5 | 6 | . auto/options 7 | . auto/init 8 | . auto/sources 9 | 10 | test -d $TC_OBJS || mkdir $TC_OBJS 11 | 12 | echo > $TC_AUTO_HEADERS_H 13 | echo > $TC_AUTOCONF_ERR 14 | 15 | echo "#define TC_CONFIGURE \"$TC_CONFIGURE\"" > $TC_AUTO_CONFIG_H 16 | 17 | if test -z "$TC_PLATFORM"; then 18 | echo "checking for OS" 19 | 20 | TC_SYSTEM=`uname -s 2>/dev/null` 21 | TC_RELEASE=`uname -r 2>/dev/null` 22 | TC_MACHINE=`uname -m 2>/dev/null` 23 | 24 | echo " + $TC_SYSTEM $TC_RELEASE $TC_MACHINE" 25 | 26 | TC_PLATFORM="$TC_SYSTEM:$TC_RELEASE:$TC_MACHINE"; 27 | 28 | else 29 | echo "building for $TC_PLATFORM" 30 | TC_SYSTEM=$TC_PLATFORM 31 | fi 32 | 33 | case "$TC_PLATFORM" in 34 | 35 | Linux:*) 36 | . auto/os/linux 37 | ;; 38 | 39 | *) 40 | echo "error: Linux only!" 41 | exit 1 42 | esac 43 | 44 | 45 | if [ $TC_DEBUG = YES ]; then 46 | have=TC_DEBUG . auto/have 47 | have=TC_DETECT_MEMORY . auto/have 48 | have=TC_HIGH_PRESSURE_CHECK . auto/have 49 | else 50 | if [ $TC_DETECT_MEMORY = YES ]; then 51 | have=TC_DETECT_MEMORY . auto/have 52 | fi 53 | if [ $TC_HIGH_PRESSURE_CHECK = YES ]; then 54 | have=TC_HIGH_PRESSURE_CHECK . auto/have 55 | fi 56 | fi 57 | 58 | if [ $TC_COMET = YES ]; then 59 | have=TC_COMET . auto/have 60 | fi 61 | 62 | if [ $TC_SINGLE = YES ]; then 63 | have=TC_SINGLE . auto/have 64 | fi 65 | 66 | if [ $TC_TOPO = YES ]; then 67 | have=TC_TOPO . auto/have 68 | fi 69 | 70 | if [ $TC_PCAP_SEND = YES ]; then 71 | have=TC_PCAP_SEND . auto/have 72 | fi 73 | 74 | if [ $TC_COMBINED = YES ]; then 75 | have=TC_COMBINED . auto/have 76 | fi 77 | 78 | . auto/cc/conf 79 | . auto/headers 80 | . auto/os/conf 81 | . auto/linux 82 | 83 | case ".$TC_PREFIX" in 84 | .) 85 | TC_PREFIX=${TC_PREFIX:-/usr/local/tcpburn} 86 | have=TC_PREFIX value="\"$TC_PREFIX/\"" . auto/define 87 | ;; 88 | 89 | .!) 90 | TC_PREFIX= 91 | ;; 92 | 93 | *) 94 | have=TC_PREFIX value="\"$TC_PREFIX/\"" . auto/define 95 | ;; 96 | esac 97 | 98 | if [ ".$TC_CONF_PREFIX" != "." ]; then 99 | have=TC_CONF_PREFIX value="\"$TC_CONF_PREFIX/\"" . auto/define 100 | fi 101 | 102 | have=TC_SBIN_PATH value="\"$TC_SBIN_PATH\"" . auto/define 103 | have=TC_PID_PATH value="\"$TC_PID_PATH\"" . auto/define 104 | have=TC_ERROR_LOG_PATH value="\"$TC_ERROR_LOG_PATH\"" . auto/define 105 | 106 | CORE_LIBS="$CORE_LIBS -lpcap" 107 | 108 | . auto/make 109 | . auto/install 110 | . auto/summary 111 | -------------------------------------------------------------------------------- /images/tcpburn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/session-replay-tools/tcpburn/34135b852eacda1025dd66fce17a25de6feaa27d/images/tcpburn.png -------------------------------------------------------------------------------- /src/burn/burn.h: -------------------------------------------------------------------------------- 1 | #ifndef BURN_INCLUDED 2 | #define BURN_INCLUDED 3 | 4 | #define LOCALHOST (inet_addr("127.0.0.1")) 5 | 6 | #define FILE_NAME_LEN 256 7 | typedef struct { 8 | char file[FILE_NAME_LEN]; 9 | } tc_pcap_file; 10 | 11 | typedef struct { 12 | /* online ip from the client perspective */ 13 | uint32_t online_ip; 14 | uint32_t target_ip; 15 | uint16_t online_port; 16 | uint16_t target_port; 17 | unsigned char src_mac[ETHER_ADDR_LEN]; 18 | unsigned char dst_mac[ETHER_ADDR_LEN]; 19 | } ip_port_pair_mapping_t; 20 | 21 | 22 | typedef struct { 23 | int num; 24 | ip_port_pair_mapping_t **mappings; 25 | } ip_port_pair_mappings_t; 26 | 27 | typedef struct real_ip_addr_s { 28 | int num; 29 | int active_num; 30 | short active[MAX_REAL_SERVERS]; 31 | uint32_t ips[MAX_REAL_SERVERS]; 32 | uint16_t ports[MAX_REAL_SERVERS]; 33 | connections_t connections[MAX_REAL_SERVERS]; 34 | } real_ip_addr_t; 35 | 36 | 37 | static inline ip_port_pair_mapping_t * 38 | get_test_pair(ip_port_pair_mappings_t *transfer, uint32_t ip, uint16_t port) 39 | { 40 | int i; 41 | ip_port_pair_mapping_t *pair, **mappings; 42 | 43 | pair = NULL; 44 | mappings = transfer->mappings; 45 | for (i = 0; i < transfer->num; i++) { 46 | pair = mappings[i]; 47 | if (ip == pair->online_ip && port == pair->online_port) { 48 | return pair; 49 | } else if (pair->online_ip == 0 && port == pair->online_port) { 50 | return pair; 51 | } 52 | } 53 | return NULL; 54 | } 55 | 56 | 57 | static inline int 58 | check_pack_src(ip_port_pair_mappings_t *transfer, uint32_t ip, 59 | uint16_t port, int src_flag) 60 | { 61 | int i, ret; 62 | ip_port_pair_mapping_t *pair, **mappings; 63 | 64 | ret = UNKNOWN; 65 | mappings = transfer->mappings; 66 | 67 | for (i = 0; i < transfer->num; i++) { 68 | 69 | pair = mappings[i]; 70 | if (CHECK_DEST == src_flag) { 71 | if (ip == pair->online_ip && port == pair->online_port) { 72 | ret = LOCAL; 73 | break; 74 | } else if (0 == pair->online_ip && port == pair->online_port) { 75 | ret = LOCAL; 76 | break; 77 | } 78 | } else if (CHECK_SRC == src_flag) { 79 | if (ip == pair->target_ip && port == pair->target_port) { 80 | ret = REMOTE; 81 | break; 82 | } 83 | } 84 | } 85 | 86 | return ret; 87 | } 88 | 89 | 90 | typedef struct xcopy_clt_settings { 91 | unsigned int mtu:16; /* MTU sent to backend */ 92 | unsigned int mss:16; /* MSS sent to backend */ 93 | unsigned int par_connections:8; /* parallel connections */ 94 | unsigned int client_mode:3; 95 | 96 | unsigned int target_localhost:1; 97 | unsigned int ignite_complete:1; 98 | unsigned int do_daemonize:1; /* daemon flag */ 99 | unsigned int percentage:7; /* percentage of the full flow that 100 | will be tranfered to the backend */ 101 | unsigned int sess_timeout:16; /* max value for sess timeout. 102 | If reaching this value, the sess 103 | will be removed */ 104 | unsigned int sess_keepalive_timeout:16; 105 | 106 | tc_pool_t *pool; 107 | char *raw_transfer; /* online_ip online_port target_ip 108 | target_port string */ 109 | 110 | char *pid_file; /* pid file */ 111 | char *log_path; /* error log path */ 112 | char *raw_clt_ips; 113 | #if (TC_TOPO) 114 | link_list *s_list; 115 | int topo_time_diff; 116 | #endif 117 | int valid_ip_num; 118 | uint32_t valid_ips[M_CLIENT_IP_NUM]; 119 | uint32_t sess_ms_timeout; 120 | int users; 121 | int throughput_factor; 122 | int accelerated_times; 123 | char *raw_pcap_files; 124 | char *filter; 125 | tc_pcap_file pcap_files[MAX_PCAP_FILES]; 126 | int num_pcap_files; 127 | int conn_init_sp_fact; 128 | long pcap_time; 129 | time_t ignite_complete_time; 130 | pcap_t *pcap; 131 | #if (TC_PCAP_SEND) 132 | char *output_if_name; 133 | #endif 134 | uint16_t rand_port_shifted; /* random port shifted */ 135 | uint16_t srv_port; /* server listening port */ 136 | 137 | char *raw_rs_list; /* raw real server list */ 138 | real_ip_addr_t real_servers; /* the intercept servers running intercept */ 139 | ip_port_pair_mappings_t transfer; /* transfered online_ip online_port 140 | target_ip target_port */ 141 | unsigned int port_seed; /* port seed */ 142 | int multiplex_io; 143 | int sig; 144 | uint64_t tries; 145 | tc_event_t *ev[MAX_FD_NUM]; 146 | 147 | uint64_t mem_pool_size; 148 | unsigned char *mem_pool_cur_p; 149 | unsigned char *mem_pool_end_p; 150 | unsigned char *mem_pool; 151 | unsigned char frame[MAX_FRAME_LENGTH]; 152 | } xcopy_clt_settings; 153 | 154 | 155 | extern int tc_raw_socket_out; 156 | extern tc_event_loop_t event_loop; 157 | extern xcopy_clt_settings clt_settings; 158 | 159 | #include 160 | 161 | #include 162 | #include 163 | #include 164 | #include 165 | 166 | #endif /* BURN_INCLUDED */ 167 | -------------------------------------------------------------------------------- /src/burn/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * tcpburn 3 | * A powerful tool to simulate millions of concurrent users for loading testing 4 | * 5 | * Copyright 2013 Netease, Inc. All rights reserved. 6 | * Use and distribution licensed under the BSD license. 7 | * See the LICENSE file for full text. 8 | * 9 | * Authors: 10 | * Bin Wang 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | /* global variables for burn client */ 17 | xcopy_clt_settings clt_settings; 18 | tc_stat_t tc_stat; 19 | 20 | int tc_raw_socket_out; 21 | tc_event_loop_t event_loop; 22 | 23 | #if (TC_SIGACTION) 24 | static signal_t signals[] = { 25 | { SIGINT, "SIGINT", 0, burn_over }, 26 | { SIGPIPE, "SIGPIPE", 0, burn_over }, 27 | { SIGHUP, "SIGHUP", 0, burn_over }, 28 | { SIGTERM, "SIGTERM", 0, burn_over }, 29 | { 0, NULL, 0, NULL } 30 | }; 31 | #endif 32 | 33 | static void 34 | usage(void) 35 | { 36 | printf("tcpburn " VERSION "\n"); 37 | #if (!TC_PCAP_SEND) 38 | printf("-x use to specify the IPs and ports of the source and target\n" 39 | " servers. Suppose 'sourceIP' and 'sourcePort' are the IP and port \n" 40 | " number of the source server you want to copy from, 'targetIP' and \n"); 41 | printf(" 'targetPort' are the IP and port number of the target server you want\n" 42 | " to send requests to, the format of could be as follows:\n" 43 | " 'sourceIP:sourcePort-targetIP:targetPort,...'. Most of the time,\n"); 44 | printf(" sourceIP could be omitted and thus could also be:\n" 45 | " 'sourcePort-targetIP:targetPort,...'. As seen, the IP address and the\n" 46 | " port number are segmented by ':' (colon), the sourcePort and the\n"); 47 | printf(" targetIP are segmented by '-', and two 'transfer's are segmented by\n" 48 | " ',' (comma).\n"); 49 | #else 50 | printf("-x use to specify the IPs, ports and MAC addresses of\n" 51 | " the source and target. The format of could be as follow:\n"); 52 | printf(" 'sourceIP:sourcePort@sourceMac-targetIP:targetPort@targetMac,...'.\n" 53 | " Most of the time, sourceIP could be omitted and thus could\n" 54 | " also be: sourcePort@sourceMac-targetIP:targetPort@targetMac,...'.\n"); 55 | printf(" Note that sourceMac is the MAC address of the interface where \n" 56 | " packets are going out and targetMac is the next hop's MAC address.\n"); 57 | #endif 58 | printf("-f set the pcap file list\n"); 59 | printf("-F user filter (same as pcap filter)\n"); 60 | #if (TC_PCAP_SEND) 61 | printf("-o The name of the interface to send. This is usually a driver\n" 62 | " name followed by a unit number, for example eth0 for the first\n" 63 | " Ethernet interface.\n"); 64 | #endif 65 | printf("-M MTU value sent to backend (default 1500)\n"); 66 | printf("-u concurrent users\n"); 67 | printf("-c client ips\n"); 68 | #if (TC_TOPO) 69 | printf("-T topology time diff(default 6)\n"); 70 | #endif 71 | printf("-a accelerated times for replay\n"); 72 | printf("-A throughput factor(default 1)\n"); 73 | printf("-i connection init speed fact(default 1024 connectins per second)\n"); 74 | printf("-S MSS value sent back(default 1460)\n"); 75 | printf("-C parallel connections between burn and intercept.\n" 76 | " The maximum value allowed is 16(default 2 connections)\n"); 77 | printf("-s intercept server list\n" 78 | " Format:\n" 79 | " ip_addr1:port1, ip_addr2:port2, ...\n"); 80 | printf("-t set the session timeout limit. If burn does not receive response\n" 81 | " from the target server within the timeout limit, the session would \n" 82 | " be dropped by burn. When the response from the target server is\n" 83 | " slow or the application protocol is context based, the value should \n" 84 | " be set larger. The default value is 120 seconds\n"); 85 | printf("-l save the log information in \n" 86 | "-p set the target server listening port. The default value is 36524.\n"); 87 | printf("-e port seed\n"); 88 | printf("-P save PID in , only used with -d option\n"); 89 | printf("-h print this help and exit\n" 90 | "-v version\n" 91 | "-m define how to simulate client properties(default 0).\n" 92 | " 0, ip prioritized; otherwise,port prioritized\n" 93 | "-d run as a daemon\n"); 94 | } 95 | 96 | 97 | 98 | static int 99 | read_args(int argc, char **argv) 100 | { 101 | int c; 102 | 103 | opterr = 0; 104 | while (-1 != (c = getopt(argc, argv, 105 | "x:" /* */ 106 | "f:" /* input pcap file list */ 107 | "F:" 108 | "c:" /* client ip list */ 109 | "a:" 110 | "A:" /* throughput factor */ 111 | "i:" 112 | #if (TC_PCAP_SEND) 113 | "o:" /* */ 114 | #endif 115 | "m:" 116 | "u:" 117 | "C:" /* parallel connections between burn and intercept */ 118 | "p:" /* target server port to listen on */ 119 | "e:" /* port seed */ 120 | #if (TC_TOPO) 121 | "T:" 122 | #endif 123 | "M:" /* MTU sent to backend */ 124 | "S:" /* mss value sent to backend */ 125 | "t:" /* set the session timeout limit */ 126 | "s:" /* real servers running intercept*/ 127 | "l:" /* error log file */ 128 | "P:" /* save PID in file */ 129 | "L" /* lonely */ 130 | "h" /* help, licence info */ 131 | "v" /* version */ 132 | "d" /* daemon mode */ 133 | ))) { 134 | switch (c) { 135 | case 'x': 136 | clt_settings.raw_transfer = optarg; 137 | break; 138 | case 'f': 139 | clt_settings.raw_pcap_files = optarg; 140 | break; 141 | case 'F': 142 | clt_settings.filter = optarg; 143 | break; 144 | case 'a': 145 | clt_settings.accelerated_times = atoi(optarg); 146 | break; 147 | case 'A': 148 | clt_settings.throughput_factor = atoi(optarg); 149 | break; 150 | case 'c': 151 | clt_settings.raw_clt_ips = optarg; 152 | break; 153 | #if (TC_TOPO) 154 | case 'T': 155 | clt_settings.topo_time_diff = 1000 * atoi(optarg); 156 | break; 157 | #endif 158 | case 'i': 159 | clt_settings.conn_init_sp_fact = atoi(optarg); 160 | break; 161 | #if (TC_PCAP_SEND) 162 | case 'o': 163 | clt_settings.output_if_name = optarg; 164 | break; 165 | #endif 166 | case 'm': 167 | clt_settings.client_mode = atoi(optarg); 168 | break; 169 | case 'C': 170 | clt_settings.par_connections = atoi(optarg); 171 | break; 172 | case 'l': 173 | clt_settings.log_path = optarg; 174 | break; 175 | case 'u': 176 | clt_settings.users = atoi(optarg); 177 | break; 178 | case 'M': 179 | clt_settings.mtu = atoi(optarg); 180 | break; 181 | case 'S': 182 | clt_settings.mss = atoi(optarg); 183 | break; 184 | case 's': 185 | clt_settings.raw_rs_list = optarg; 186 | break; 187 | case 't': 188 | clt_settings.sess_timeout = atoi(optarg); 189 | break; 190 | case 'h': 191 | usage(); 192 | return -1; 193 | case 'v': 194 | printf ("tcpburn version:%s\n", VERSION); 195 | return -1; 196 | case 'd': 197 | clt_settings.do_daemonize = 1; 198 | break; 199 | case 'e': 200 | clt_settings.port_seed = (unsigned int) atoi(optarg); 201 | break; 202 | case 'p': 203 | clt_settings.srv_port = atoi(optarg); 204 | break; 205 | case 'P': 206 | clt_settings.pid_file = optarg; 207 | break; 208 | case '?': 209 | switch (optopt) { 210 | case 'x': 211 | fprintf(stderr, "burn: option -%c require a string\n", 212 | optopt); 213 | break; 214 | case 'l': 215 | case 'P': 216 | fprintf(stderr, "burn: option -%c require a file name\n", 217 | optopt); 218 | break; 219 | #if (TC_PCAP_SEND) 220 | case 'o': 221 | fprintf(stderr, "burn: option -%c require a device name\n", 222 | optopt); 223 | break; 224 | #endif 225 | case 's': 226 | fprintf(stderr, "burn: option -%c require an ip address list\n", 227 | optopt); 228 | break; 229 | 230 | case 'C': 231 | case 'm': 232 | case 'M': 233 | #if (TC_TOPO) 234 | case 'T': 235 | #endif 236 | case 'S': 237 | case 't': 238 | case 'a': 239 | case 'A': 240 | case 'e': 241 | case 'p': 242 | fprintf(stderr, "burn: option -%c require a number\n", 243 | optopt); 244 | break; 245 | 246 | default: 247 | fprintf(stderr, "burn: illegal argument \"%c\"\n", 248 | optopt); 249 | break; 250 | } 251 | return -1; 252 | 253 | default: 254 | fprintf(stderr, "burn: illegal argument \"%c\"\n", optopt); 255 | return -1; 256 | } 257 | } 258 | 259 | return 0; 260 | } 261 | 262 | static void 263 | output_for_debug() 264 | { 265 | /* print out version info */ 266 | tc_log_info(LOG_NOTICE, 0, "tcpburn version:%s", VERSION); 267 | /* print out target info */ 268 | tc_log_info(LOG_NOTICE, 0, "target:%s", clt_settings.raw_transfer); 269 | /* print pcap version for debug */ 270 | tc_log_info(LOG_NOTICE, 0, "pcap version:%s", pcap_lib_version()); 271 | 272 | #if (TC_DEBUG) 273 | tc_log_info(LOG_NOTICE, 0, "TC_DEBUG mode"); 274 | #endif 275 | #if (TC_SINGLE) 276 | tc_log_info(LOG_NOTICE, 0, "TC_SINGLE mode"); 277 | #endif 278 | #if (TC_COMET) 279 | tc_log_info(LOG_NOTICE, 0, "TC_COMET mode"); 280 | #endif 281 | #if (TC_PCAP_SEND) 282 | tc_log_info(LOG_NOTICE, 0, "TC_PCAP_SEND mode"); 283 | #endif 284 | #if (TC_TOPO) 285 | tc_log_info(LOG_NOTICE, 0, "TC_TOPO mode"); 286 | #endif 287 | 288 | } 289 | 290 | 291 | static unsigned char 292 | char_to_data(const char ch) 293 | { 294 | if (ch >= '0' && ch <= '9') { 295 | return ch - '0'; 296 | } 297 | 298 | if (ch >= 'a' && ch <= 'f') { 299 | return ch - 'a' + 10; 300 | } 301 | 302 | if (ch >= 'A' && ch <= 'Z') { 303 | return ch - 'A' + 10; 304 | } 305 | 306 | return 0; 307 | } 308 | 309 | static int 310 | parse_ip_port_pair(char *addr, uint32_t *ip, uint16_t *port, 311 | unsigned char *mac) 312 | { 313 | int i, len; 314 | char *p, *seq, *before_mac, *ip_s, *port_s; 315 | uint16_t tmp_port; 316 | 317 | if ((before_mac = strchr(addr, '@')) != NULL) { 318 | *before_mac = '\0'; 319 | } 320 | 321 | if ((seq = strchr(addr, ':')) == NULL) { 322 | tc_log_info(LOG_NOTICE, 0, "set global port for tcpburn"); 323 | *ip = 0; 324 | port_s = addr; 325 | } else { 326 | ip_s = addr; 327 | port_s = seq + 1; 328 | 329 | *seq = '\0'; 330 | *ip = inet_addr(ip_s); 331 | *seq = ':'; 332 | } 333 | 334 | tmp_port = atoi(port_s); 335 | *port = htons(tmp_port); 336 | 337 | if (before_mac != NULL) { 338 | p = before_mac + 1; 339 | len = strlen(p); 340 | 341 | if (len < ETHER_ADDR_STR_LEN) { 342 | tc_log_info(LOG_WARN, 0, "mac address is too short:%d", len); 343 | return -1; 344 | } 345 | 346 | for (i = 0; i < ETHER_ADDR_LEN; ++i) { 347 | mac[i] = char_to_data(*p++) << 4; 348 | mac[i] += char_to_data(*p++); 349 | p++; 350 | } 351 | 352 | *before_mac = '@'; 353 | } 354 | 355 | return 0; 356 | } 357 | 358 | /* 359 | * two kinds of target formats: 360 | * 1) 192.168.0.1:80-192.168.0.2:8080 361 | * 2) 80-192.168.0.2:8080 362 | */ 363 | static int 364 | parse_target(ip_port_pair_mapping_t *ip_port, char *addr) 365 | { 366 | char *seq, *addr1, *addr2; 367 | 368 | if ((seq = strchr(addr, '-')) == NULL) { 369 | tc_log_info(LOG_WARN, 0, "target \"%s\" is invalid", addr); 370 | return -1; 371 | } else { 372 | *seq = '\0'; 373 | } 374 | 375 | addr1 = addr; 376 | addr2 = seq + 1; 377 | 378 | parse_ip_port_pair(addr1, &ip_port->online_ip, &ip_port->online_port, 379 | ip_port->src_mac); 380 | parse_ip_port_pair(addr2, &ip_port->target_ip, &ip_port->target_port, 381 | ip_port->dst_mac); 382 | 383 | if (ip_port->target_ip == LOCALHOST) { 384 | clt_settings.target_localhost = 1; 385 | tc_log_info(LOG_WARN, 0, "target host is 127.0.0.1"); 386 | tc_log_info(LOG_WARN, 0, 387 | "only client requests from localhost are valid"); 388 | } 389 | 390 | *seq = '-'; 391 | 392 | return 0; 393 | } 394 | 395 | 396 | /* 397 | * retrieve target addresses 398 | * format 399 | * 192.168.0.1:80-192.168.0.2:8080,192.168.0.1:8080-192.168.0.3:80 400 | */ 401 | static int 402 | retrieve_target_addresses(char *raw_transfer, 403 | ip_port_pair_mappings_t *transfer) 404 | { 405 | int i; 406 | char *p, *seq; 407 | 408 | if (raw_transfer == NULL) { 409 | tc_log_info(LOG_ERR, 0, "it must have -x argument"); 410 | fprintf(stderr, "no -x argument\n"); 411 | return -1; 412 | } 413 | 414 | for (transfer->num = 1, p = raw_transfer; *p; p++) { 415 | if (*p == ',') { 416 | transfer->num++; 417 | } 418 | } 419 | 420 | transfer->mappings = tc_palloc(clt_settings.pool, 421 | transfer->num * sizeof(ip_port_pair_mapping_t *)); 422 | if (transfer->mappings == NULL) { 423 | return -1; 424 | } 425 | memset(transfer->mappings, 0 , 426 | transfer->num * sizeof(ip_port_pair_mapping_t *)); 427 | 428 | for (i = 0; i < transfer->num; i++) { 429 | transfer->mappings[i] = tc_palloc(clt_settings.pool, 430 | sizeof(ip_port_pair_mapping_t)); 431 | if (transfer->mappings[i] == NULL) { 432 | return -1; 433 | } 434 | memset(transfer->mappings[i], 0, sizeof(ip_port_pair_mapping_t)); 435 | } 436 | 437 | p = raw_transfer; 438 | i = 0; 439 | for ( ;; ) { 440 | if ((seq = strchr(p, ',')) == NULL) { 441 | parse_target(transfer->mappings[i++], p); 442 | break; 443 | } else { 444 | *seq = '\0'; 445 | parse_target(transfer->mappings[i++], p); 446 | *seq = ','; 447 | 448 | p = seq + 1; 449 | } 450 | } 451 | 452 | return 0; 453 | } 454 | 455 | 456 | static int 457 | retrieve_real_servers() 458 | { 459 | int count = 0; 460 | char *split, *p, *seq, *port_s; 461 | uint16_t port; 462 | uint32_t ip; 463 | 464 | p = clt_settings.raw_rs_list; 465 | 466 | while (true) { 467 | split = strchr(p, ','); 468 | if (split != NULL) { 469 | *split = '\0'; 470 | } 471 | 472 | if ((seq = strchr(p, ':')) == NULL) { 473 | tc_log_info(LOG_NOTICE, 0, "set only ip for burn"); 474 | port = 0; 475 | ip = inet_addr(p); 476 | } else { 477 | port_s = seq + 1; 478 | *seq = '\0'; 479 | ip = inet_addr(p); 480 | port = atoi(port_s); 481 | *seq = ':'; 482 | } 483 | 484 | if (split != NULL) { 485 | *split = ','; 486 | } 487 | 488 | clt_settings.real_servers.ips[count] = ip; 489 | clt_settings.real_servers.ports[count++] = port; 490 | 491 | if (count == MAX_REAL_SERVERS) { 492 | tc_log_info(LOG_WARN, 0, "reach the limit for real servers"); 493 | break; 494 | } 495 | 496 | if (split == NULL) { 497 | break; 498 | } else { 499 | p = split + 1; 500 | } 501 | 502 | } 503 | 504 | clt_settings.real_servers.num = count; 505 | 506 | return 1; 507 | 508 | } 509 | 510 | 511 | static bool 512 | check_client_ip_valid(uint32_t ip) 513 | { 514 | int i; 515 | 516 | for (i = 0; i < clt_settings.transfer.num; i++) { 517 | if (ip == clt_settings.transfer.mappings[i]->target_ip) { 518 | return false; 519 | } 520 | } 521 | 522 | return true; 523 | } 524 | 525 | 526 | static int 527 | retrieve_client_ips() 528 | { 529 | int count = 0, len, i; 530 | char *split, *p, tmp_ip[32], *q; 531 | uint32_t ip; 532 | 533 | p = clt_settings.raw_clt_ips; 534 | 535 | while (true) { 536 | split = strchr(p, ','); 537 | if (split != NULL) { 538 | *split = '\0'; 539 | } 540 | 541 | len = strlen(p); 542 | if (len == 0) { 543 | tc_log_info(LOG_WARN, 0, "ip is empty"); 544 | break; 545 | } 546 | 547 | if (p[len - 1] == 'x') { 548 | strncpy(tmp_ip, p, len -1); 549 | q = tmp_ip + len - 1; 550 | for (i = 1; i < 255; i++) { 551 | sprintf(q, "%d", i); 552 | ip = inet_addr(tmp_ip); 553 | tc_log_debug1(LOG_DEBUG, 0, "clt ip addr:%s", tmp_ip); 554 | if (check_client_ip_valid(ip)) { 555 | clt_settings.valid_ips[count++] = ip; 556 | if (count == M_CLIENT_IP_NUM) { 557 | tc_log_info(LOG_WARN, 0, "reach limit for clt ips"); 558 | break; 559 | } 560 | } 561 | } 562 | } else if (p[len - 1] == '*') { 563 | tc_log_info(LOG_ERR, 0, "%s not valid, use x instead of *", p); 564 | fprintf(stderr, "%s not valid, use x instead of *\n", p); 565 | } else { 566 | ip = inet_addr(p); 567 | if (check_client_ip_valid(ip)) { 568 | clt_settings.valid_ips[count++] = ip; 569 | if (count == M_CLIENT_IP_NUM) { 570 | tc_log_info(LOG_WARN, 0, "reach limit for clt ips"); 571 | break; 572 | } 573 | } 574 | } 575 | 576 | if (split != NULL) { 577 | *split = ','; 578 | } 579 | 580 | if (count == M_CLIENT_IP_NUM) { 581 | tc_log_info(LOG_WARN, 0, "reach the limit for clt_tf_ip"); 582 | break; 583 | } 584 | 585 | if (split == NULL) { 586 | break; 587 | } else { 588 | p = split + 1; 589 | } 590 | 591 | } 592 | 593 | clt_settings.valid_ip_num = count; 594 | 595 | return 1; 596 | 597 | } 598 | 599 | 600 | static int 601 | retrieve_pcap_files() 602 | { 603 | int count = 0; 604 | char *split, *p; 605 | 606 | p = clt_settings.raw_pcap_files; 607 | 608 | while (true) { 609 | split = strchr(p, ','); 610 | if (split != NULL) { 611 | *split = '\0'; 612 | } 613 | 614 | strncpy(clt_settings.pcap_files[count++].file, p, FILE_NAME_LEN - 1); 615 | if (split != NULL) { 616 | *split = ','; 617 | } 618 | 619 | if (count == MAX_PCAP_FILES) { 620 | tc_log_info(LOG_WARN, 0, "reach the limit for pcap files"); 621 | break; 622 | } 623 | 624 | if (split == NULL) { 625 | break; 626 | } else { 627 | p = split + 1; 628 | } 629 | 630 | } 631 | 632 | clt_settings.num_pcap_files = count; 633 | 634 | return 1; 635 | 636 | } 637 | 638 | 639 | static int 640 | set_details() 641 | { 642 | clt_settings.sess_keepalive_timeout = clt_settings.sess_timeout; 643 | tc_log_info(LOG_NOTICE, 0, "keepalive timeout:%d", 644 | clt_settings.sess_keepalive_timeout); 645 | 646 | if (clt_settings.users <= 0) { 647 | tc_log_info(LOG_ERR, 0, "please set the -u parameter"); 648 | return -1; 649 | } 650 | 651 | clt_settings.sess_ms_timeout = clt_settings.sess_timeout * 1000; 652 | #if (TC_TOPO) 653 | if (clt_settings.topo_time_diff <= 0) { 654 | clt_settings.topo_time_diff = 6000; 655 | } 656 | tc_log_info(LOG_NOTICE, 0, "topology time diff:%d", 657 | clt_settings.topo_time_diff); 658 | #endif 659 | /* set the ip port pair mapping according to settings */ 660 | if (retrieve_target_addresses(clt_settings.raw_transfer, 661 | &clt_settings.transfer) == -1) 662 | { 663 | return -1; 664 | } 665 | 666 | if (clt_settings.raw_clt_ips == NULL) { 667 | tc_log_info(LOG_ERR, 0, "please set the -c parameter"); 668 | return -1; 669 | } 670 | 671 | tc_log_info(LOG_NOTICE, 0, "client ips:%s", clt_settings.raw_clt_ips); 672 | 673 | retrieve_client_ips(); 674 | 675 | if (clt_settings.par_connections <= 0) { 676 | clt_settings.par_connections = 1; 677 | } else if (clt_settings.par_connections > MAX_CONNECTION_NUM) { 678 | clt_settings.par_connections = MAX_CONNECTION_NUM; 679 | } 680 | tc_log_info(LOG_NOTICE, 0, "parallel connections per target:%d", 681 | clt_settings.par_connections); 682 | 683 | if (clt_settings.raw_pcap_files == NULL) { 684 | tc_log_info(LOG_ERR, 0, "it must have -f argument for burn"); 685 | fprintf(stderr, "no -f argument\n"); 686 | return -1; 687 | } 688 | 689 | retrieve_pcap_files(); 690 | 691 | if (clt_settings.throughput_factor < 1) { 692 | clt_settings.throughput_factor = 1; 693 | } 694 | 695 | if (clt_settings.accelerated_times < 1) { 696 | clt_settings.accelerated_times = 1; 697 | } 698 | 699 | tc_log_info(LOG_NOTICE, 0, "throughput factor:%d,accelerate:%d", 700 | clt_settings.throughput_factor, clt_settings.accelerated_times); 701 | 702 | if (clt_settings.conn_init_sp_fact <= 0) { 703 | clt_settings.conn_init_sp_fact = DEFAULT_CONN_INIT_SP_FACT; 704 | } 705 | tc_log_info(LOG_NOTICE, 0, "init connections speed:%d", 706 | clt_settings.conn_init_sp_fact); 707 | 708 | #if (TC_PCAP_SEND) 709 | if (clt_settings.output_if_name != NULL) { 710 | tc_log_info(LOG_NOTICE, 0, "output device:%s", 711 | clt_settings.output_if_name); 712 | } else { 713 | tc_log_info(LOG_ERR, 0, "output device is null"); 714 | return -1; 715 | } 716 | #endif 717 | 718 | /* retrieve real server ip addresses */ 719 | if (clt_settings.raw_rs_list != NULL) { 720 | tc_log_info(LOG_NOTICE, 0, "s parameter:%s", 721 | clt_settings.raw_rs_list); 722 | retrieve_real_servers(); 723 | } else { 724 | tc_log_info(LOG_WARN, 0, "no real server ip addresses"); 725 | return -1; 726 | } 727 | 728 | /* daemonize */ 729 | if (clt_settings.do_daemonize) { 730 | if (sigignore(SIGHUP) == -1) { 731 | tc_log_info(LOG_ERR, errno, "Failed to ignore SIGHUP"); 732 | } 733 | if (daemonize() == -1) { 734 | fprintf(stderr, "failed to daemonize() in order to daemonize\n"); 735 | return -1; 736 | } 737 | } 738 | 739 | return 0; 740 | } 741 | 742 | 743 | /* set default values for burn client */ 744 | static void 745 | settings_init() 746 | { 747 | /* init values */ 748 | clt_settings.users = 0; 749 | clt_settings.mtu = DEFAULT_MTU; 750 | clt_settings.conn_init_sp_fact = DEFAULT_CONN_INIT_SP_FACT; 751 | clt_settings.mss = DEFAULT_MSS; 752 | clt_settings.srv_port = SERVER_PORT; 753 | clt_settings.port_seed = 0; 754 | clt_settings.par_connections = 2; 755 | #if (TC_TOPO) 756 | clt_settings.topo_time_diff = 6000; 757 | #endif 758 | clt_settings.client_mode = 0; 759 | clt_settings.sess_timeout = DEFAULT_SESSION_TIMEOUT; 760 | 761 | #if (TC_PCAP_SEND) 762 | clt_settings.output_if_name = NULL; 763 | #endif 764 | 765 | tc_pagesize = getpagesize(); 766 | 767 | tc_raw_socket_out = TC_INVALID_SOCKET; 768 | } 769 | 770 | 771 | /* 772 | * main entry point 773 | */ 774 | int 775 | main(int argc, char **argv) 776 | { 777 | int ret, is_continue = 1; 778 | 779 | settings_init(); 780 | 781 | #if (TC_SIGACTION) 782 | if (set_signal_handler(signals) == -1) { 783 | return -1; 784 | } 785 | #else 786 | signal(SIGINT, burn_over); 787 | signal(SIGPIPE, burn_over); 788 | signal(SIGHUP, burn_over); 789 | signal(SIGTERM, burn_over); 790 | #endif 791 | 792 | tc_time_init(); 793 | 794 | if (read_args(argc, argv) == -1) { 795 | return -1; 796 | } 797 | 798 | if (tc_log_init(clt_settings.log_path) == -1) { 799 | return -1; 800 | } 801 | 802 | /* output debug info */ 803 | output_for_debug(); 804 | 805 | clt_settings.pool = tc_create_pool(TC_DEFAULT_POOL_SIZE, 0); 806 | if (clt_settings.pool == NULL) { 807 | return -1; 808 | } 809 | 810 | /* set details for running */ 811 | if (set_details() == -1) { 812 | return -1; 813 | } 814 | 815 | tc_event_timer_init(); 816 | 817 | ret = tc_event_loop_init(&event_loop, MAX_FD_NUM); 818 | if (ret == TC_EVENT_ERROR) { 819 | tc_log_info(LOG_ERR, 0, "event loop init failed"); 820 | is_continue = 0; 821 | } 822 | 823 | if (is_continue) { 824 | ret = tc_build_sess_table(65536); 825 | if (ret == TC_ERROR) { 826 | is_continue = 0; 827 | } else { 828 | ret = burn_init(&event_loop); 829 | if (ret == TC_ERROR) { 830 | is_continue = 0; 831 | } else { 832 | if (!tc_build_users(clt_settings.client_mode, 833 | clt_settings.users, clt_settings.valid_ips, 834 | clt_settings.valid_ip_num)) 835 | { 836 | is_continue = 0; 837 | } 838 | } 839 | } 840 | } 841 | 842 | if (is_continue) { 843 | /* run now */ 844 | tc_event_proc_cycle(&event_loop); 845 | } 846 | 847 | tc_release_resources(); 848 | 849 | return 0; 850 | } 851 | 852 | -------------------------------------------------------------------------------- /src/burn/tc_manager.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | 6 | /* check resource usage, such as memory usage and cpu usage */ 7 | static void 8 | check_res_usage(tc_event_timer_t *evt) 9 | { 10 | int ret, who; 11 | struct rusage usage; 12 | 13 | who = RUSAGE_SELF; 14 | 15 | ret = getrusage(who, &usage); 16 | if (ret == -1) { 17 | tc_log_info(LOG_ERR, errno, "getrusage"); 18 | } 19 | 20 | /* total amount of user time used */ 21 | tc_log_info(LOG_NOTICE, 0, "user time used:%ld", usage.ru_utime.tv_sec); 22 | 23 | /* total amount of system time used */ 24 | tc_log_info(LOG_NOTICE, 0, "sys time used:%ld", usage.ru_stime.tv_sec); 25 | 26 | /* maximum resident set size (in kilobytes) */ 27 | /* only valid since Linux 2.6.32 */ 28 | tc_log_info(LOG_NOTICE, 0, "max memory size:%ld", usage.ru_maxrss); 29 | 30 | if (evt != NULL) { 31 | tc_event_update_timer(evt, 60000); 32 | } 33 | } 34 | 35 | void 36 | tc_release_resources() 37 | { 38 | tc_log_info(LOG_WARN, 0, "sig %d received", tc_over); 39 | 40 | output_stat(); 41 | 42 | release_user_resources(); 43 | 44 | tc_event_loop_finish(&event_loop); 45 | tc_log_info(LOG_NOTICE, 0, "tc_event_loop_finish over"); 46 | 47 | tc_log_end(); 48 | 49 | 50 | if (tc_raw_socket_out > 0) { 51 | close(tc_raw_socket_out); 52 | tc_raw_socket_out = -1; 53 | } 54 | 55 | #if (TC_PCAP_SEND) 56 | tc_pcap_over(); 57 | #endif 58 | 59 | tc_destroy_pool(clt_settings.pool); 60 | } 61 | 62 | void 63 | burn_over(const int sig) 64 | { 65 | tc_over = sig; 66 | } 67 | 68 | static bool send_version(int fd) { 69 | msg_client_t msg; 70 | 71 | memset(&msg, 0, sizeof(msg_client_t)); 72 | msg.client_ip = htonl(0); 73 | msg.client_port = htons(0); 74 | msg.type = htons(INTERNAL_VERSION); 75 | 76 | if (tc_socket_send(fd, (char *) &msg, MSG_CLIENT_SIZE) == TC_ERROR) { 77 | tc_log_info(LOG_ERR, 0, "send version error:%d", fd); 78 | return false; 79 | } 80 | 81 | return true; 82 | } 83 | 84 | static int 85 | connect_to_server(tc_event_loop_t *event_loop) 86 | { 87 | int i, j, fd; 88 | uint32_t target_ip; 89 | uint16_t target_port; 90 | connections_t *connections; 91 | 92 | /* 93 | * add connections to the real servers for sending router info 94 | * and receiving response packet 95 | */ 96 | for (i = 0; i < clt_settings.real_servers.num; i++) { 97 | 98 | target_ip = clt_settings.real_servers.ips[i]; 99 | target_port = clt_settings.real_servers.ports[i]; 100 | if (target_port == 0) { 101 | target_port = clt_settings.srv_port; 102 | } 103 | 104 | if (clt_settings.real_servers.active[i] != 0) { 105 | continue; 106 | } 107 | 108 | connections = &(clt_settings.real_servers.connections[i]); 109 | for (j = 0; j < connections->num; j++) { 110 | fd = connections->fds[j]; 111 | if (fd > 0) { 112 | tc_log_info(LOG_NOTICE, 0, "it close socket:%d", fd); 113 | tc_socket_close(fd); 114 | tc_event_del(clt_settings.ev[fd]->loop, 115 | clt_settings.ev[fd], TC_EVENT_READ); 116 | tc_event_destroy(clt_settings.ev[fd], 0); 117 | connections->fds[j] = -1; 118 | } 119 | } 120 | 121 | clt_settings.real_servers.connections[i].num = 0; 122 | clt_settings.real_servers.connections[i].remained_num = 0; 123 | 124 | for (j = 0; j < clt_settings.par_connections; j++) { 125 | fd = tc_message_init(event_loop, target_ip, target_port); 126 | if (fd == TC_INVALID_SOCKET) { 127 | return TC_ERROR; 128 | } 129 | 130 | if (!send_version(fd)) { 131 | return TC_ERROR; 132 | } 133 | 134 | if (j == 0) { 135 | clt_settings.real_servers.active_num++; 136 | clt_settings.real_servers.active[i] = 1; 137 | } 138 | 139 | clt_settings.real_servers.connections[i].fds[j] = fd; 140 | clt_settings.real_servers.connections[i].num++; 141 | clt_settings.real_servers.connections[i].remained_num++; 142 | 143 | } 144 | } 145 | 146 | return TC_OK; 147 | 148 | 149 | } 150 | 151 | 152 | /* initiate TCPCopy client */ 153 | int 154 | burn_init(tc_event_loop_t *event_loop) 155 | { 156 | int i, result, pool_used; 157 | uint64_t pool_size; 158 | 159 | /* register some timer */ 160 | tc_event_add_timer(event_loop->pool, NULL, 60000, NULL, check_res_usage); 161 | 162 | if (connect_to_server(event_loop) == TC_ERROR) { 163 | return TC_ERROR; 164 | } 165 | 166 | if (tc_send_init(event_loop) == TC_ERROR) { 167 | return TC_ERROR; 168 | } 169 | 170 | for (i = 0; i < clt_settings.num_pcap_files; i++) { 171 | result = calculate_mem_pool_size(clt_settings.pcap_files[i].file, 172 | clt_settings.filter); 173 | if (result == TC_ERROR) { 174 | return TC_ERROR; 175 | } 176 | } 177 | 178 | tc_log_info(LOG_NOTICE, 0, "pool size:%llu", clt_settings.mem_pool_size); 179 | 180 | pool_size = clt_settings.mem_pool_size; 181 | if (pool_size > 0) { 182 | clt_settings.mem_pool = (unsigned char *) tc_pcalloc(clt_settings.pool, 183 | pool_size); 184 | if (clt_settings.mem_pool == NULL) { 185 | return TC_ERROR; 186 | } 187 | clt_settings.mem_pool_cur_p = tc_align_ptr(clt_settings.mem_pool, 188 | TC_ALIGNMENT); 189 | clt_settings.mem_pool_end_p = clt_settings.mem_pool + pool_size; 190 | } 191 | 192 | for (i = 0; i < clt_settings.num_pcap_files; i++) { 193 | read_packets_from_pcap(clt_settings.pcap_files[i].file, 194 | clt_settings.filter); 195 | } 196 | 197 | #if (TC_TOPO) 198 | set_topo_for_sess(); 199 | #endif 200 | 201 | pool_used = clt_settings.mem_pool_cur_p - clt_settings.mem_pool; 202 | tc_log_info(LOG_NOTICE, 0, "pool used:%d", pool_used); 203 | 204 | tc_event_add_timer(event_loop->pool, NULL, 5000, NULL, tc_interval_dispose); 205 | 206 | return TC_OK; 207 | } 208 | 209 | -------------------------------------------------------------------------------- /src/burn/tc_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_MANAGER_INCLUDED 2 | #define TC_MANAGER_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | int burn_init(tc_event_loop_t *event_loop); 8 | void burn_over(const int sig); 9 | void tc_release_resources(); 10 | 11 | #endif /* ----- #ifndef TC_MANAGER_INCLUDED ----- */ 12 | 13 | -------------------------------------------------------------------------------- /src/burn/tc_message_module.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | static int tc_process_server_msg(tc_event_t *rev); 6 | 7 | int 8 | tc_message_init(tc_event_loop_t *event_loop, uint32_t ip, uint16_t port) 9 | { 10 | int fd; 11 | tc_event_t *ev; 12 | 13 | socklen_t len; 14 | struct timeval timeout = {3,0}; 15 | 16 | if ((fd = tc_socket_init()) == TC_INVALID_SOCKET) { 17 | return TC_INVALID_SOCKET; 18 | } 19 | 20 | if (tc_socket_connect(fd, ip, port) == TC_ERROR) { 21 | tc_socket_close(fd); 22 | return TC_INVALID_SOCKET; 23 | } 24 | 25 | if (tc_socket_set_nodelay(fd) == TC_ERROR) { 26 | tc_socket_close(fd); 27 | return TC_INVALID_SOCKET; 28 | } 29 | if (tc_socket_set_nonblocking(fd) == TC_ERROR) { 30 | tc_socket_close(fd); 31 | return TC_INVALID_SOCKET; 32 | } 33 | 34 | len = (socklen_t) sizeof(struct timeval); 35 | if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, len) == -1) { 36 | tc_socket_close(fd); 37 | return TC_INVALID_SOCKET; 38 | } 39 | 40 | ev = tc_event_create(event_loop->pool, fd, tc_process_server_msg, NULL); 41 | if (ev == NULL) { 42 | tc_socket_close(fd); 43 | return TC_INVALID_SOCKET; 44 | } 45 | 46 | clt_settings.ev[fd] = ev; 47 | 48 | if (tc_event_add(event_loop, ev, TC_EVENT_READ) == TC_EVENT_ERROR) { 49 | tc_socket_close(fd); 50 | return TC_INVALID_SOCKET; 51 | } 52 | 53 | return fd; 54 | } 55 | 56 | static int 57 | tc_process_server_msg(tc_event_t *rev) 58 | { 59 | int i, j, k, num = 0; 60 | connections_t *connections; 61 | unsigned char *p, aggr_resp[COMB_LENGTH + sizeof(uint16_t)] = {0}; 62 | 63 | 64 | if (tc_socket_cmb_recv(rev->fd, &num, (char *) aggr_resp) == TC_ERROR) 65 | { 66 | tc_log_info(LOG_ERR, 0, "Recv socket(%d)error", rev->fd); 67 | 68 | for (i = 0; i < clt_settings.real_servers.num; i++) { 69 | 70 | connections = &(clt_settings.real_servers.connections[i]); 71 | for (j = 0; j < connections->num; j++) { 72 | if (connections->fds[j] == rev->fd) { 73 | if (connections->fds[j] > 0) { 74 | tc_socket_close(connections->fds[j]); 75 | tc_log_info(LOG_NOTICE, 0, "close sock:%d", 76 | connections->fds[j]); 77 | tc_event_del(rev->loop, rev, TC_EVENT_READ); 78 | connections->fds[j] = -1; 79 | connections->remained_num--; 80 | } 81 | if (connections->remained_num == 0 && 82 | clt_settings.real_servers.active[i]) 83 | { 84 | clt_settings.real_servers.active[i] = 0; 85 | clt_settings.real_servers.active_num--; 86 | } 87 | 88 | break; 89 | } 90 | } 91 | } 92 | 93 | if (clt_settings.real_servers.active_num == 0) { 94 | tc_over = SIGRTMAX; 95 | } 96 | return TC_OK; 97 | } 98 | 99 | tc_log_debug1(LOG_DEBUG, 0, "resp packets:%d", num); 100 | p = aggr_resp + sizeof(uint16_t); 101 | for (k = 0; k < num; k++) { 102 | process_outgress(p); 103 | p = p + MSG_SERVER_SIZE; 104 | } 105 | 106 | return TC_OK; 107 | } 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/burn/tc_message_module.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_MESSAGE_MODULE_INCLUDED 2 | #define TC_MESSAGE_MODULE_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | int tc_message_init(tc_event_loop_t *event_loop, uint32_t ip, uint16_t port); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/burn/tc_packets_module.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | static time_t read_pcap_over_time; 6 | static uint64_t adj_v_pack_diff = 0; 7 | static uint64_t sess_created = 0; 8 | static uint64_t packets_considered_cnt = 0; 9 | static uint64_t packets_cnt = 0; 10 | static struct timeval first_pack_time, last_v_pack_time, 11 | last_pack_time; 12 | 13 | static int dispose_packet(unsigned char *frame, int frame_len, int ip_recv_len); 14 | static void tc_process_packets(tc_event_timer_t *evt); 15 | static uint64_t timeval_diff(struct timeval *start, struct timeval *cur); 16 | 17 | 18 | static unsigned char * 19 | alloc_pool_mem(int length) 20 | { 21 | unsigned char *p, *q; 22 | 23 | p = clt_settings.mem_pool_cur_p; 24 | q = p; 25 | q += length; 26 | q = tc_align_ptr(q, TC_ALIGNMENT); 27 | 28 | if (q > clt_settings.mem_pool_end_p) { 29 | tc_log_info(LOG_ERR, 0, "pool full, alloc error for frame data"); 30 | return NULL; 31 | } 32 | 33 | clt_settings.mem_pool_cur_p = q; 34 | 35 | return p; 36 | } 37 | 38 | 39 | static void 40 | append_by_order(sess_data_t *s, frame_t *added_frame) 41 | { 42 | bool last_changed = true; 43 | frame_t *next, *node; 44 | 45 | node = s->last_frame; 46 | next = node->next; 47 | 48 | while (node != NULL && after(node->seq, added_frame->seq)) { 49 | next = node; 50 | node = node->prev; 51 | last_changed = false; 52 | } 53 | 54 | if (node != NULL) { 55 | node->next = added_frame; 56 | added_frame->prev = node; 57 | } 58 | if (next != NULL) { 59 | next->prev = added_frame; 60 | added_frame->next = next; 61 | } 62 | 63 | s->frames++; 64 | 65 | if (last_changed) { 66 | s->last_frame = added_frame; 67 | } 68 | } 69 | 70 | 71 | static void 72 | record_packet(uint64_t key, unsigned char *frame, int frame_len, uint32_t seq, 73 | uint32_t ack_seq, bool saved, uint16_t cont_len, int status) 74 | { 75 | frame_t *fr; 76 | sess_data_t *sess; 77 | p_sess_entry entry; 78 | #if (TC_TOPO) 79 | p_link_node ln; 80 | #endif 81 | 82 | entry = tc_retrieve_sess(key); 83 | 84 | if (status == SYN_SENT) { 85 | tc_log_debug0(LOG_DEBUG, 0, "reuse port"); 86 | entry = NULL; 87 | } 88 | if (entry == NULL) { 89 | if (status != SYN_SENT) { 90 | return; 91 | } 92 | 93 | fr = (frame_t *) alloc_pool_mem(sizeof(frame_t)); 94 | if (fr == NULL) { 95 | tc_log_info(LOG_WARN, 0, "calloc error for frame_t"); 96 | return; 97 | } 98 | fr->frame_data = alloc_pool_mem(frame_len); 99 | if (fr->frame_data == NULL) { 100 | tc_log_info(LOG_WARN, 0, "calloc error for frame data"); 101 | return; 102 | } 103 | memcpy(fr->frame_data, frame, frame_len); 104 | fr->frame_len = frame_len; 105 | 106 | fr->seq = seq; 107 | fr->has_payload = 0; 108 | entry = (p_sess_entry) alloc_pool_mem(sizeof(sess_entry_t)); 109 | if (entry == NULL) { 110 | tc_log_info(LOG_WARN, 0, "calloc error for sess_entry_t"); 111 | return; 112 | } 113 | sess_created++; 114 | entry->key = key; 115 | 116 | sess = &(entry->data); 117 | 118 | sess->first_pcap_time = clt_settings.pcap_time; 119 | sess->last_pcap_time = clt_settings.pcap_time; 120 | sess->rtt = clt_settings.pcap_time; 121 | sess->rtt_init = 1; 122 | sess->first_frame = fr; 123 | sess->first_payload_frame = NULL; 124 | sess->frames = 1; 125 | sess->last_frame = fr; 126 | sess->last_ack_seq = ack_seq; 127 | sess->status = SYN_SENT; 128 | tc_add_sess(entry); 129 | #if (TC_TOPO) 130 | ln = link_node_malloc(clt_settings.pool, sess); 131 | ln->key = clt_settings.pcap_time; 132 | link_list_append_by_order(clt_settings.s_list, ln); 133 | #endif 134 | 135 | } else { 136 | 137 | sess = &(entry->data); 138 | sess->status |= status; 139 | 140 | if (!sess->rtt_calculated) { 141 | if (sess->rtt_init) { 142 | if (clt_settings.pcap_time > sess->rtt) { 143 | sess->rtt = clt_settings.pcap_time - sess->rtt; 144 | if (clt_settings.accelerated_times > 1) { 145 | sess->rtt /= clt_settings.accelerated_times; 146 | } 147 | } else { 148 | sess->rtt = 1; 149 | } 150 | } else { 151 | tc_log_info(LOG_WARN, 0, "rtt wrong"); 152 | sess->rtt = 1; 153 | } 154 | sess->rtt_calculated = 1; 155 | tc_log_debug1(LOG_INFO, 0, "rtt:%ld", sess->rtt); 156 | } 157 | 158 | if (cont_len == 0 && ((sess->status & SEND_REQ) && 159 | (!(sess->status & CLIENT_FIN)))) 160 | { 161 | tc_log_debug0(LOG_DEBUG, 0, "dropped"); 162 | return; 163 | } 164 | 165 | if (!saved) { 166 | sess->end = 1; 167 | } 168 | 169 | if (!sess->end) { 170 | 171 | fr = (frame_t *) alloc_pool_mem(sizeof(frame_t)); 172 | if (fr == NULL) { 173 | tc_log_info(LOG_WARN, 0, "calloc error for frame_t"); 174 | return; 175 | } 176 | fr->frame_data = alloc_pool_mem(frame_len); 177 | if (fr->frame_data == NULL) { 178 | tc_log_info(LOG_WARN, 0, "calloc error for frame data"); 179 | return; 180 | } 181 | memcpy(fr->frame_data, frame, frame_len); 182 | fr->frame_len = frame_len; 183 | fr->seq = seq; 184 | 185 | append_by_order(sess, fr); 186 | 187 | if (clt_settings.pcap_time > sess->last_pcap_time) { 188 | fr->time_diff = clt_settings.pcap_time - sess->last_pcap_time; 189 | if (clt_settings.accelerated_times > 1) { 190 | fr->time_diff /= clt_settings.accelerated_times; 191 | } 192 | } else { 193 | fr->time_diff = 0; 194 | } 195 | 196 | sess->last_pcap_time = clt_settings.pcap_time; 197 | 198 | if (cont_len > 0) { 199 | if (sess->first_payload_frame == NULL) { 200 | sess->first_payload_frame = fr; 201 | } 202 | if (sess->last_ack_seq == ack_seq) { 203 | fr->belong_to_the_same_req = 1; 204 | tc_log_debug0(LOG_DEBUG, 0, "belong to the same req"); 205 | } 206 | fr->has_payload = 1; 207 | sess->has_req = 1; 208 | } 209 | sess->last_ack_seq = ack_seq; 210 | } 211 | } 212 | } 213 | 214 | 215 | static int 216 | dispose_packet(unsigned char *frame, int frame_len, int ip_recv_len) 217 | { 218 | int i, last, packet_num, max_payload, 219 | index, payload_len, status = 0; 220 | bool saved = true; 221 | char *p, buf[ETHERNET_HDR_LEN + IP_RECV_BUF_SIZE]; 222 | uint16_t id, size_ip, size_tcp, tot_len, cont_len, 223 | pack_len = 0, head_len; 224 | uint32_t seq, tmp_seq, ack_seq; 225 | uint64_t key; 226 | unsigned char *packet; 227 | tc_iph_t *ip; 228 | tc_tcph_t *tcp; 229 | 230 | packet = frame + ETHERNET_HDR_LEN; 231 | 232 | ip = (tc_iph_t *) packet; 233 | 234 | packets_cnt++; 235 | 236 | if (ip->version != 4) { 237 | tc_log_info(LOG_INFO, 0, "ip version: %d", ip->version); 238 | return TC_ERROR; 239 | } 240 | 241 | if (ip->protocol != IPPROTO_TCP) { 242 | return TC_ERROR; 243 | } 244 | 245 | size_ip = ip->ihl << 2; 246 | if (size_ip < 20) { 247 | tc_log_info(LOG_WARN, 0, "Invalid IP header length: %d", size_ip); 248 | return TC_ERROR; 249 | } 250 | tcp = (tc_tcph_t *) ((char *) ip + size_ip); 251 | size_tcp = tcp->doff << 2; 252 | 253 | if (size_tcp < 20) { 254 | tc_log_info(LOG_INFO, 0, "Invalid TCP header len: %d bytes", size_tcp); 255 | return TC_ERROR; 256 | } 257 | 258 | if (LOCAL == check_pack_src(&(clt_settings.transfer), 259 | ip->daddr, tcp->dest, CHECK_DEST)) { 260 | if (clt_settings.target_localhost) { 261 | if (ip->saddr != LOCALHOST) { 262 | tc_log_info(LOG_WARN, 0, "not localhost source ip address"); 263 | return TC_ERROR; 264 | } 265 | } 266 | tot_len = ntohs(ip -> tot_len); 267 | head_len = size_tcp + size_ip; 268 | if (tot_len < head_len) { 269 | tc_log_info(LOG_WARN, 0, "bad tot_len:%d bytes, header len:%d", 270 | tot_len, head_len); 271 | return TC_ERROR; 272 | } 273 | } else { 274 | return TC_ERROR; 275 | } 276 | 277 | #if (TC_DEBUG) 278 | tc_log_trace(LOG_NOTICE, 0, CLIENT_FLAG, ip, tcp); 279 | #endif 280 | if (tcp->syn) { 281 | status = SYN_SENT; 282 | } else if (tcp->fin || tcp->rst) { 283 | status = CLIENT_FIN; 284 | #if (TC_COMET) 285 | saved = false; 286 | #endif 287 | } 288 | 289 | packets_considered_cnt++; 290 | key = tc_get_key(ip->saddr, tcp->source); 291 | ack_seq = ntohl(tcp->ack_seq); 292 | seq = ntohl(tcp->seq); 293 | 294 | cont_len = tot_len - size_tcp - size_ip; 295 | if (cont_len > 0) { 296 | status |= SEND_REQ; 297 | } 298 | 299 | /* 300 | * If the packet length is larger than MTU, we split it. 301 | */ 302 | if (ip_recv_len > clt_settings.mtu) { 303 | 304 | /* calculate number of packets */ 305 | if (tot_len != ip_recv_len) { 306 | tc_log_info(LOG_WARN, 0, "packet len:%u, recv len:%u", 307 | tot_len, ip_recv_len); 308 | return TC_ERROR; 309 | } 310 | 311 | head_len = size_ip + size_tcp; 312 | max_payload = clt_settings.mtu - head_len; 313 | packet_num = (cont_len + max_payload - 1)/max_payload; 314 | last = packet_num - 1; 315 | id = ip->id; 316 | 317 | 318 | tc_log_debug1(LOG_DEBUG, 0, "recv:%d, more than MTU", ip_recv_len); 319 | index = head_len; 320 | 321 | for (i = 0 ; i < packet_num; i++) { 322 | tcp->seq = htonl(seq + i * max_payload); 323 | if (i != last) { 324 | pack_len = clt_settings.mtu; 325 | } else { 326 | pack_len += (cont_len - packet_num * max_payload); 327 | } 328 | payload_len = pack_len - head_len; 329 | ip->tot_len = htons(pack_len); 330 | ip->id = id++; 331 | p = buf + ETHERNET_HDR_LEN; 332 | /* copy header here */ 333 | memcpy(p, (char *) packet, head_len); 334 | p += head_len; 335 | /* copy payload here */ 336 | memcpy(p, (char *) (packet + index), payload_len); 337 | index = index + payload_len; 338 | 339 | tmp_seq = ntohl(tcp->seq); 340 | record_packet(key, (unsigned char *) buf, 341 | ETHERNET_HDR_LEN + pack_len, tmp_seq, ack_seq, 342 | saved, cont_len, status); 343 | } 344 | } else { 345 | record_packet(key, frame, frame_len, seq, ack_seq, saved, 346 | cont_len, status); 347 | } 348 | 349 | return TC_OK; 350 | } 351 | 352 | int 353 | tc_send_init(tc_event_loop_t *event_loop) 354 | { 355 | #if (!TC_PCAP_SEND) 356 | int fd; 357 | #endif 358 | 359 | #if (!TC_PCAP_SEND) 360 | /* init the raw socket to send */ 361 | if ((fd = tc_raw_socket_out_init()) == TC_INVALID_SOCKET) { 362 | return TC_ERROR; 363 | } else { 364 | tc_raw_socket_out = fd; 365 | } 366 | #else 367 | tc_pcap_send_init(clt_settings.output_if_name, clt_settings.mtu); 368 | #endif 369 | 370 | /* register a timer for activating sending packets */ 371 | tc_event_add_timer(event_loop->pool, NULL, 1, NULL, tc_process_packets); 372 | 373 | return TC_OK; 374 | } 375 | 376 | static void 377 | tc_process_packets(tc_event_timer_t *evt) 378 | { 379 | int i = 0; 380 | 381 | for (; i < clt_settings.throughput_factor; i++) { 382 | ignite_one_sess(); 383 | } 384 | 385 | if (!clt_settings.ignite_complete) { 386 | tc_event_update_timer(evt, 1); 387 | } 388 | } 389 | 390 | static uint64_t 391 | timeval_diff(struct timeval *start, struct timeval *cur) 392 | { 393 | uint64_t usec; 394 | 395 | usec = (cur->tv_sec - start->tv_sec) * 1000000; 396 | usec += cur->tv_usec - start->tv_usec; 397 | 398 | return usec; 399 | } 400 | 401 | void 402 | read_packets_from_pcap(char *pcap_file, char *filter) 403 | { 404 | int first = 1, l2_len, ip_pack_len; 405 | char ebuf[PCAP_ERRBUF_SIZE]; 406 | bool stop = false; 407 | pcap_t *pcap; 408 | unsigned char *pkt_data, *frame, *ip_data; 409 | struct bpf_program fp; 410 | struct pcap_pkthdr pkt_hdr; 411 | 412 | if ((pcap = pcap_open_offline(pcap_file, ebuf)) == NULL) { 413 | tc_log_info(LOG_ERR, 0, "open %s" , ebuf); 414 | return; 415 | } 416 | 417 | if (filter != NULL) { 418 | if (pcap_compile(pcap, &fp, filter, 0, 0) == -1) { 419 | tc_log_info(LOG_ERR, 0, "couldn't parse filter %s: %s", 420 | filter, pcap_geterr(pcap)); 421 | return; 422 | } 423 | if (pcap_setfilter(pcap, &fp) == -1) { 424 | fprintf(stderr, "Couldn't install filter %s: %s\n", 425 | filter, pcap_geterr(pcap)); 426 | pcap_freecode(&fp); 427 | return; 428 | } 429 | pcap_freecode(&fp); 430 | } 431 | 432 | while (!stop) { 433 | 434 | pkt_data = (u_char *) pcap_next(pcap, &pkt_hdr); 435 | if (pkt_data != NULL) { 436 | 437 | if (pkt_hdr.caplen < pkt_hdr.len) { 438 | 439 | tc_log_info(LOG_WARN, 0, "truncated packets,drop"); 440 | } else { 441 | 442 | ip_data = get_ip_data(pcap, pkt_data, pkt_hdr.len, &l2_len); 443 | if (l2_len < (int) ETHERNET_HDR_LEN) { 444 | tc_log_info(LOG_WARN, 0, "l2 len is %d", l2_len); 445 | continue; 446 | } 447 | 448 | last_pack_time = pkt_hdr.ts; 449 | if (ip_data != NULL) { 450 | clt_settings.pcap_time = last_pack_time.tv_sec * 1000 + 451 | last_pack_time.tv_usec / 1000; 452 | 453 | ip_pack_len = pkt_hdr.len - l2_len; 454 | tc_log_debug2(LOG_DEBUG, 0, "frame len:%d, ip len:%d", 455 | pkt_hdr.len, ip_pack_len); 456 | frame = ip_data - ETHERNET_HDR_LEN; 457 | dispose_packet(frame, ip_pack_len + ETHERNET_HDR_LEN, 458 | ip_pack_len); 459 | 460 | if (first) { 461 | first_pack_time = pkt_hdr.ts; 462 | first = 0; 463 | } else { 464 | adj_v_pack_diff = timeval_diff(&last_v_pack_time, 465 | &last_pack_time); 466 | } 467 | 468 | /* set last valid packet time in pcap file */ 469 | last_v_pack_time = last_pack_time; 470 | 471 | } 472 | } 473 | } else { 474 | 475 | stop = true; 476 | tc_log_info(LOG_NOTICE, 0, "stop, null from pcap_next"); 477 | read_pcap_over_time = tc_time(); 478 | } 479 | } 480 | 481 | pcap_close(pcap); 482 | tc_log_info(LOG_INFO, 0, "total packets: %llu, clt packets:%llu", 483 | packets_cnt, packets_considered_cnt); 484 | 485 | } 486 | 487 | 488 | int 489 | calculate_mem_pool_size(char *pcap_file, char *filter) 490 | { 491 | int l2_len, aligned_len; 492 | char ebuf[PCAP_ERRBUF_SIZE]; 493 | bool stop = false; 494 | pcap_t *pcap; 495 | uint16_t size_ip, size_tcp; 496 | tc_iph_t *ip; 497 | tc_tcph_t *tcp; 498 | unsigned char *pkt_data,*ip_data; 499 | struct bpf_program fp; 500 | struct pcap_pkthdr pkt_hdr; 501 | 502 | #if (TC_TOPO) 503 | if (clt_settings.s_list == NULL) { 504 | clt_settings.s_list = link_list_create(clt_settings.pool); 505 | if (clt_settings.s_list == NULL) { 506 | return TC_ERROR; 507 | } 508 | } 509 | #endif 510 | if ((pcap = pcap_open_offline(pcap_file, ebuf)) == NULL) { 511 | tc_log_info(LOG_ERR, 0, "open %s" , ebuf); 512 | return TC_ERROR; 513 | } 514 | 515 | if (filter != NULL) { 516 | if (pcap_compile(pcap, &fp, filter, 0, 0) == -1) { 517 | tc_log_info(LOG_ERR, 0, "couldn't parse filter %s: %s", 518 | filter, pcap_geterr(pcap)); 519 | return TC_ERROR; 520 | } 521 | if (pcap_setfilter(pcap, &fp) == -1) { 522 | fprintf(stderr, "Couldn't install filter %s: %s\n", 523 | filter, pcap_geterr(pcap)); 524 | pcap_freecode(&fp); 525 | return TC_ERROR; 526 | } 527 | pcap_freecode(&fp); 528 | } 529 | 530 | while (!stop) { 531 | 532 | pkt_data = (u_char *) pcap_next(pcap, &pkt_hdr); 533 | if (pkt_data != NULL) { 534 | 535 | if (pkt_hdr.caplen >= pkt_hdr.len) { 536 | ip_data = get_ip_data(pcap, pkt_data, pkt_hdr.len, &l2_len); 537 | if (l2_len < (int) ETHERNET_HDR_LEN) { 538 | continue; 539 | } 540 | 541 | if (ip_data != NULL) { 542 | ip = (tc_iph_t *) ip_data; 543 | if (ip->protocol != IPPROTO_TCP) { 544 | continue; 545 | } 546 | size_ip = ip->ihl << 2; 547 | if (size_ip < 20) { 548 | continue; 549 | } 550 | tcp = (tc_tcph_t *) (ip_data + size_ip); 551 | size_tcp = tcp->doff << 2; 552 | if (size_tcp < 20) { 553 | continue; 554 | } 555 | if (LOCAL != check_pack_src(&(clt_settings.transfer), 556 | ip->daddr, tcp->dest, CHECK_DEST)) 557 | { 558 | continue; 559 | } 560 | 561 | if (tcp->syn) { 562 | aligned_len = sizeof(sess_entry_t); 563 | aligned_len = tc_align(aligned_len, TC_ALIGNMENT); 564 | clt_settings.mem_pool_size += aligned_len; 565 | } 566 | aligned_len = pkt_hdr.len + sizeof(frame_t); 567 | aligned_len = tc_align(aligned_len, TC_ALIGNMENT); 568 | clt_settings.mem_pool_size += aligned_len; 569 | } 570 | } 571 | } else { 572 | 573 | stop = true; 574 | tc_log_info(LOG_NOTICE, 0, "read over from file:%s", pcap_file); 575 | read_pcap_over_time = tc_time(); 576 | } 577 | } 578 | 579 | pcap_close(pcap); 580 | 581 | return TC_OK; 582 | } 583 | 584 | 585 | #if (TC_TOPO) 586 | void 587 | set_topo_for_sess() 588 | { 589 | int i = 0, diff; 590 | p_link_node prev, cur; 591 | sess_data_t *cur_sess, *prev_sess; 592 | 593 | cur = link_list_first(clt_settings.s_list); 594 | prev = NULL; 595 | 596 | while(cur) { 597 | cur_sess = (sess_data_t *) cur->data; 598 | if (!cur_sess->has_req) { 599 | link_list_remove(clt_settings.s_list, cur); 600 | if (prev) { 601 | cur = link_list_get_next(clt_settings.s_list, prev); 602 | } else { 603 | cur = link_list_first(clt_settings.s_list); 604 | } 605 | } else { 606 | prev = cur; 607 | cur = link_list_get_next(clt_settings.s_list, cur); 608 | } 609 | } 610 | 611 | prev = link_list_first(clt_settings.s_list); 612 | prev_sess = (sess_data_t *) prev->data; 613 | cur = prev->next; 614 | 615 | while (cur) { 616 | cur_sess = (sess_data_t *) cur->data; 617 | 618 | if (cur_sess != NULL && cur_sess->has_req) { 619 | diff = cur_sess->first_pcap_time - prev_sess->first_pcap_time; 620 | if (tc_abs(diff) < clt_settings.topo_time_diff) { 621 | cur_sess->delayed = 1; 622 | tc_log_debug2(LOG_NOTICE, 0, "sess %d %d related", i, i + 1); 623 | } 624 | prev = cur; 625 | cur = cur->next; 626 | prev_sess = cur_sess; 627 | i++; 628 | } else { 629 | break; 630 | } 631 | } 632 | } 633 | #endif 634 | 635 | -------------------------------------------------------------------------------- /src/burn/tc_packets_module.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_PACKETS_MODULE_INCLUDED 2 | #define TC_PACKETS_MODULE_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | int tc_send_init(tc_event_loop_t *event_loop); 8 | void read_packets_from_pcap(char *pcap_file, char *filter); 9 | int calculate_mem_pool_size(char *pcap_file, char *filter); 10 | void set_topo_for_sess(); 11 | 12 | #endif /* TC_PACKETS_MODULE_INCLUDED */ 13 | -------------------------------------------------------------------------------- /src/burn/tc_user.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_USER_INCLUDED 2 | #define TC_USER_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | typedef struct frame_s { 8 | struct frame_s *next; 9 | struct frame_s *prev; 10 | unsigned char *frame_data; 11 | uint32_t seq; 12 | unsigned int time_diff:20; 13 | unsigned int belong_to_the_same_req:1; 14 | unsigned int has_payload:1; 15 | unsigned int frame_len:17; 16 | }frame_t; 17 | 18 | typedef struct sess_data_s { 19 | frame_t *first_frame; 20 | frame_t *first_payload_frame; 21 | frame_t *last_frame; 22 | long first_pcap_time; 23 | long last_pcap_time; 24 | long rtt; 25 | uint32_t last_ack_seq; 26 | uint32_t frames; 27 | unsigned int rtt_init:1; 28 | unsigned int rtt_calculated:1; 29 | unsigned int end:1; 30 | #if (TC_TOPO) 31 | unsigned int delayed:1; 32 | #endif 33 | unsigned int has_req:1; 34 | unsigned int status:10; 35 | }sess_data_t, *p_sess_data_t; 36 | 37 | typedef struct sess_entry_s { 38 | uint64_t key; 39 | sess_data_t data; 40 | struct sess_entry_s *next; 41 | }sess_entry_t,*p_sess_entry; 42 | 43 | typedef struct sess_table_s { 44 | int size; 45 | int num_of_sess; 46 | p_sess_entry *entries; 47 | }sess_table_t; 48 | 49 | 50 | typedef struct tc_user_state_s { 51 | uint32_t status:16; 52 | uint32_t timer_type:4; 53 | #if (TC_TOPO) 54 | uint32_t delayed:1; 55 | #endif 56 | uint32_t over:1; 57 | uint32_t over_recorded:1; 58 | uint32_t timestamped:1; 59 | uint32_t resp_syn_received:1; 60 | uint32_t resp_waiting:1; 61 | uint32_t sess_activated:1; 62 | uint32_t sess_continue:1; 63 | uint32_t last_ack_recorded:1; 64 | uint32_t evt_added:1; 65 | uint32_t set_rto:1; 66 | uint32_t already_retransmit_syn:1; 67 | uint32_t timeout_set:1; 68 | uint32_t snd_after_set_rto:1; 69 | uint32_t rewind_af_dup_syn:1; 70 | #if (TC_HIGH_PRESSURE_CHECK) 71 | uint32_t rewind_af_lack:1; 72 | #endif 73 | }tc_user_state_t; 74 | 75 | 76 | typedef struct tc_user_s { 77 | uint64_t key; 78 | tc_user_state_t state; 79 | 80 | uint32_t orig_clt_addr; 81 | uint32_t src_addr; 82 | uint32_t dst_addr; 83 | 84 | uint16_t orig_clt_port; 85 | uint16_t src_port; 86 | uint16_t dst_port; 87 | 88 | uint16_t wscale; 89 | uint32_t last_seq; /* network byte order */ 90 | uint32_t last_ack_seq; /* host byte order */ 91 | uint32_t history_last_ack_seq; /* network byte order */ 92 | uint32_t exp_seq; /* host byte order */ 93 | uint32_t exp_ack_seq; /* network byte order */ 94 | uint32_t last_snd_ack_seq; /* host byte order */ 95 | 96 | uint32_t fast_retransmit_cnt:6; 97 | 98 | uint32_t ts_ec_r; 99 | uint32_t ts_value; 100 | 101 | uint32_t srv_window; 102 | uint32_t total_packets_sent; 103 | 104 | #if (TC_PCAP_SEND) 105 | unsigned char *src_mac; 106 | unsigned char *dst_mac; 107 | #endif 108 | 109 | tc_event_timer_t ev; 110 | 111 | sess_data_t *orig_sess; 112 | frame_t *orig_frame; 113 | frame_t *orig_unack_frame; 114 | long last_recv_resp_cont_time; 115 | long rtt; 116 | #if (TC_TOPO) 117 | struct tc_user_s *topo_prev; 118 | time_t start_time; 119 | #endif 120 | time_t last_sent_time; 121 | 122 | }tc_user_t; 123 | 124 | typedef struct tc_user_index_s { 125 | int index; 126 | }tc_user_index_t; 127 | 128 | typedef struct tc_stat_s { 129 | int activated_sess_cnt; 130 | int fin_sent_cnt; 131 | int rst_sent_cnt; 132 | int conn_cnt; 133 | int conn_reject_cnt; 134 | int rst_recv_cnt; 135 | int fin_recv_cnt; 136 | int active_conn_cnt; 137 | int syn_sent_cnt; 138 | int retransmit_syn_cnt; 139 | uint64_t retransmit_cnt; 140 | uint64_t resp_cnt; 141 | uint64_t resp_cont_cnt; 142 | uint64_t packs_sent_cnt; 143 | uint64_t cont_sent_cnt; 144 | uint64_t orig_clt_packs_cnt; 145 | }tc_stat_t; 146 | 147 | extern tc_stat_t tc_stat; 148 | 149 | int tc_build_sess_table(int size); 150 | bool tc_build_users(int port_prioritized, int num_users, uint32_t *ips, 151 | int num_ip); 152 | 153 | uint64_t tc_get_key(uint32_t ip, uint16_t port); 154 | tc_user_t *tc_retrieve_user(uint64_t key); 155 | void tc_add_sess(p_sess_entry entry); 156 | p_sess_entry tc_retrieve_sess(uint64_t key); 157 | 158 | void process_outgress(unsigned char *packet); 159 | void ignite_one_sess(); 160 | void output_stat(); 161 | void tc_interval_dispose(tc_event_timer_t *evt); 162 | void release_user_resources(); 163 | 164 | #endif /* ----- #ifndef TC_USER_INCLUDED ----- */ 165 | 166 | -------------------------------------------------------------------------------- /src/communication/tc_msg.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_MSG_INCLUDED 2 | #define TC_MSG_INCLUDED 3 | 4 | #include 5 | 6 | typedef struct msg_client_s msg_client_t; 7 | typedef struct msg_server_s msg_server_t; 8 | 9 | #pragma pack(push,1) 10 | 11 | struct msg_client_s { 12 | uint32_t client_ip; 13 | uint16_t client_port; 14 | uint16_t type; 15 | uint32_t target_ip; 16 | uint16_t target_port; 17 | }; 18 | 19 | struct msg_server_s { 20 | tc_iph_t ip; 21 | tc_tcph_t tcp; 22 | unsigned char extension[MAX_OPTION_LEN]; 23 | }; 24 | #pragma pack(pop) 25 | 26 | #define MSG_CLIENT_SIZE sizeof(msg_client_t) 27 | #define MSG_SERVER_SIZE sizeof(msg_server_t) 28 | 29 | #endif /* TC_MSG_INCLUDED */ 30 | 31 | -------------------------------------------------------------------------------- /src/communication/tc_socket.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | int 5 | tc_raw_socket_out_init() 6 | { 7 | int fd, n; 8 | 9 | n = 1; 10 | 11 | /* 12 | * On Linux when setting the protocol as IPPROTO_RAW, 13 | * then by default the kernel sets the IP_HDRINCL option and 14 | * thus does not prepend its own IP header. 15 | */ 16 | fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 17 | 18 | if (fd == -1) { 19 | tc_log_info(LOG_ERR, errno, "Create raw socket to output failed"); 20 | return TC_INVALID_SOCKET; 21 | } 22 | 23 | /* 24 | * tell the IP layer not to prepend its own header. 25 | * It does not need setting for linux, but *BSD needs 26 | */ 27 | if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &n, sizeof(n)) < 0) { 28 | tc_socket_close(fd); 29 | tc_log_info(LOG_ERR, errno, 30 | "Set raw socket(%d) option \"IP_HDRINCL\" failed", fd); 31 | return TC_INVALID_SOCKET; 32 | } 33 | 34 | 35 | return fd; 36 | } 37 | 38 | #if (TC_PCAP_SEND) 39 | 40 | static pcap_t *pcap = NULL; 41 | 42 | int 43 | tc_pcap_send_init(char *if_name, int mtu) 44 | { 45 | char pcap_errbuf[PCAP_ERRBUF_SIZE]; 46 | 47 | pcap_errbuf[0] = '\0'; 48 | pcap = pcap_open_live(if_name, mtu + sizeof(struct ethernet_hdr), 49 | 0, 0, pcap_errbuf); 50 | if (pcap_errbuf[0] != '\0') { 51 | tc_log_info(LOG_ERR, errno, "pcap open %s, failed:%s", 52 | if_name, pcap_errbuf); 53 | return TC_ERROR; 54 | } 55 | 56 | return TC_OK; 57 | } 58 | 59 | int 60 | tc_pcap_send(unsigned char *frame, size_t len) 61 | { 62 | int send_len; 63 | char pcap_errbuf[PCAP_ERRBUF_SIZE]; 64 | 65 | pcap_errbuf[0]='\0'; 66 | 67 | send_len = pcap_inject(pcap, frame, len); 68 | if (send_len == -1) { 69 | return TC_ERROR; 70 | } 71 | 72 | return TC_OK; 73 | } 74 | 75 | int tc_pcap_over() 76 | { 77 | if (pcap != NULL) { 78 | pcap_close(pcap); 79 | pcap = NULL; 80 | } 81 | 82 | return TC_OK; 83 | } 84 | #endif 85 | 86 | /* 87 | * send the ip packet to the remote test server 88 | * (It will not go through ip fragmentation) 89 | */ 90 | 91 | int 92 | tc_raw_socket_send(int fd, void *buf, size_t len, uint32_t ip) 93 | { 94 | ssize_t send_len, offset = 0, num_bytes; 95 | const char *ptr; 96 | struct sockaddr_in dst_addr; 97 | 98 | if (fd > 0) { 99 | 100 | memset(&dst_addr, 0, sizeof(struct sockaddr_in)); 101 | 102 | dst_addr.sin_family = AF_INET; 103 | dst_addr.sin_addr.s_addr = ip; 104 | 105 | ptr = buf; 106 | 107 | /* 108 | * The output packet will take a special path of IP layer 109 | * (raw_sendmsg->raw_send_hdrinc->NF_INET_LOCAL_OUT->...). 110 | * No IP fragmentation will take place if needed. 111 | * This means that a raw packet larger than the MTU of the 112 | * interface will probably be discarded. Instead ip_local_error(), 113 | * which does general sk_buff cleaning, is called and an 114 | * error EMSGSIZE is returned. 115 | */ 116 | do { 117 | num_bytes = len - offset; 118 | send_len = sendto(fd, ptr + offset, num_bytes, 0, 119 | (struct sockaddr *) &dst_addr, sizeof(dst_addr)); 120 | 121 | if (send_len == -1) { 122 | if (errno == EINTR) { 123 | tc_log_info(LOG_NOTICE, errno, "raw fd:%d EINTR", fd); 124 | } else if (errno == EAGAIN) { 125 | tc_log_debug1(LOG_NOTICE, errno, "raw fd:%d EAGAIN", fd); 126 | } else { 127 | tc_log_info(LOG_ERR, errno, "raw fd:%d", fd); 128 | tc_socket_close(fd); 129 | return TC_ERROR; 130 | } 131 | 132 | } else { 133 | offset += send_len; 134 | } 135 | } while (offset < (ssize_t) len); 136 | } 137 | 138 | return TC_OK; 139 | } 140 | 141 | 142 | int 143 | tc_socket_init() 144 | { 145 | int fd; 146 | 147 | fd = socket(AF_INET, SOCK_STREAM, 0); 148 | 149 | if (fd == -1) { 150 | tc_log_info(LOG_ERR, errno, "Create socket failed"); 151 | return TC_INVALID_SOCKET; 152 | } 153 | 154 | return fd; 155 | } 156 | 157 | int 158 | tc_socket_set_nonblocking(int fd) 159 | { 160 | int flags; 161 | 162 | flags = fcntl(fd, F_GETFL, 0); 163 | if (flags < 0) { 164 | return TC_ERROR; 165 | } 166 | 167 | if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { 168 | return TC_ERROR; 169 | } 170 | 171 | return TC_OK; 172 | } 173 | 174 | int 175 | tc_socket_set_nodelay(int fd) 176 | { 177 | int flag; 178 | socklen_t len; 179 | 180 | flag = 1; 181 | len = (socklen_t) sizeof(flag); 182 | 183 | if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, len) == -1) { 184 | return TC_ERROR; 185 | } 186 | 187 | return TC_OK; 188 | } 189 | 190 | int 191 | tc_socket_connect(int fd, uint32_t ip, uint16_t port) 192 | { 193 | socklen_t len; 194 | struct sockaddr_in remote_addr; 195 | 196 | tc_memzero(&remote_addr, sizeof(remote_addr)); 197 | 198 | remote_addr.sin_family = AF_INET; 199 | remote_addr.sin_addr.s_addr = ip; 200 | remote_addr.sin_port = htons(port); 201 | 202 | len = (socklen_t) (sizeof(remote_addr)); 203 | 204 | if (connect(fd, (struct sockaddr *) &remote_addr, len) == -1) { 205 | tc_log_info(LOG_ERR, errno, "Can not connect to remote server(%s:%d)", 206 | inet_ntoa(remote_addr.sin_addr), port); 207 | tc_socket_close(fd); 208 | return TC_ERROR; 209 | } else { 210 | tc_log_info(LOG_INFO, 0, "connect to remote server(%s:%d)", 211 | inet_ntoa(remote_addr.sin_addr), port); 212 | return TC_OK; 213 | } 214 | 215 | } 216 | 217 | 218 | int 219 | tc_socket_cmb_recv(int fd, int *num, char *buffer) 220 | { 221 | int read_num = 0, cnt = 0; 222 | size_t last; 223 | ssize_t n, len; 224 | 225 | last = 0; 226 | len = sizeof(uint16_t); 227 | 228 | for ( ;; ) { 229 | n = recv(fd, buffer + last, len, 0); 230 | 231 | if (n == -1) { 232 | if (errno == EAGAIN || errno == EINTR) { 233 | cnt++; 234 | if (cnt % MAX_READ_LOG_TRIES == 0) { 235 | tc_log_info(LOG_ERR, 0, "recv tries:%d,fd:%d", 236 | cnt, fd); 237 | } 238 | continue; 239 | } else { 240 | tc_log_info(LOG_NOTICE, errno, "return -1,fd:%d", fd); 241 | return TC_ERROR; 242 | } 243 | } 244 | 245 | if (n == 0) { 246 | tc_log_info(LOG_NOTICE, 0, "recv length 0,fd:%d", fd); 247 | return TC_ERROR; 248 | } 249 | 250 | last += n; 251 | 252 | tc_log_debug1(LOG_DEBUG, 0, "current len:%d", len); 253 | if ((!read_num) && last >= sizeof(uint16_t)) { 254 | *num = (int) ntohs(*(uint16_t *) buffer); 255 | if (*num > COMB_MAX_NUM) { 256 | tc_log_info(LOG_WARN, 0, "num:%d larger than threshold", *num); 257 | return TC_ERROR; 258 | } 259 | read_num = 1; 260 | len = ((*num) * MSG_SERVER_SIZE) + len; 261 | tc_log_debug2(LOG_DEBUG, 0, "all bytes needed reading:%d,num:%d", 262 | len, *num); 263 | } 264 | 265 | tc_log_debug1(LOG_DEBUG, 0, "this time reading:%d", n); 266 | if ((len -= n) == 0) { 267 | tc_log_debug1(LOG_DEBUG, 0, "remain readed:%d", len); 268 | break; 269 | } 270 | 271 | if (len < 0) { 272 | tc_log_info(LOG_WARN, 0, "read:%d,num packs:%d, remain:%d", 273 | n, *num, len); 274 | break; 275 | } 276 | tc_log_debug1(LOG_DEBUG, 0, "remain readed:%d", len); 277 | } 278 | 279 | return TC_OK; 280 | } 281 | 282 | int 283 | tc_socket_send(int fd, char *buffer, int len) 284 | { 285 | int cnt = 0; 286 | ssize_t send_len, offset = 0, num_bytes; 287 | const char *ptr; 288 | 289 | if (len <= 0) { 290 | return TC_OK; 291 | } 292 | 293 | ptr = buffer; 294 | num_bytes = len - offset; 295 | 296 | do { 297 | 298 | send_len = send(fd, ptr + offset, num_bytes, 0); 299 | 300 | if (send_len == -1) { 301 | 302 | if (cnt > MAX_WRITE_TRIES) { 303 | tc_log_info(LOG_ERR, 0, "send timeout,fd:%d", fd); 304 | return TC_ERROR; 305 | } 306 | if (errno == EINTR) { 307 | tc_log_info(LOG_NOTICE, errno, "fd:%d EINTR", fd); 308 | cnt++; 309 | } else if (errno == EAGAIN) { 310 | tc_log_debug1(LOG_NOTICE, errno, "fd:%d EAGAIN", fd); 311 | cnt++; 312 | } else { 313 | tc_log_info(LOG_ERR, errno, "fd:%d", fd); 314 | return TC_ERROR; 315 | } 316 | } else { 317 | 318 | if (send_len != num_bytes) { 319 | tc_log_info(LOG_WARN, 0, "fd:%d, slen:%ld, bsize:%ld", 320 | fd, send_len, num_bytes); 321 | } 322 | 323 | offset += send_len; 324 | num_bytes -= send_len; 325 | } 326 | } while (offset < len); 327 | 328 | return TC_OK; 329 | } 330 | 331 | -------------------------------------------------------------------------------- /src/communication/tc_socket.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_SOCKET_INCLUDED 2 | #define TC_SOCKET_INCLUDED 3 | 4 | #define TC_INVALID_SOCKET -1 5 | 6 | #include 7 | 8 | #define tc_socket_close(fd) close(fd) 9 | #define tc_socket_accept(fd) accept(fd, NULL, NULL) 10 | 11 | int tc_raw_socket_out_init(); 12 | int tc_raw_socket_send(int fd, void *buf, size_t len, uint32_t ip); 13 | 14 | #if (TC_PCAP_SEND) 15 | int tc_pcap_send_init(char *if_name, int mtu); 16 | int tc_pcap_send(unsigned char *frame, size_t len); 17 | int tc_pcap_over(); 18 | #endif 19 | 20 | int tc_socket_init(); 21 | int tc_socket_set_nonblocking(int fd); 22 | int tc_socket_set_nodelay(int fd); 23 | int tc_socket_connect(int fd, uint32_t ip, uint16_t port); 24 | int tc_socket_cmb_recv(int fd, int *num, char *buffer); 25 | int tc_socket_send(int fd, char *buffer, int len); 26 | 27 | #endif /* TC_SOCKET_INCLUDED */ 28 | 29 | -------------------------------------------------------------------------------- /src/core/tc_alloc.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | tc_uint_t tc_pagesize; 5 | 6 | void * 7 | tc_alloc(size_t size) 8 | { 9 | void *p; 10 | 11 | p = malloc(size); 12 | if (p == NULL) { 13 | tc_log_info(LOG_EMERG, errno, 14 | "malloc(%uz) failed", size); 15 | } 16 | 17 | return p; 18 | } 19 | 20 | 21 | #if (TC_HAVE_POSIX_MEMALIGN) 22 | 23 | void * 24 | tc_memalign(size_t alignment, size_t size) 25 | { 26 | void *p; 27 | int err; 28 | 29 | err = posix_memalign(&p, alignment, size); 30 | 31 | if (err) { 32 | p = NULL; 33 | } 34 | 35 | return p; 36 | } 37 | 38 | #elif (TC_HAVE_MEMALIGN) 39 | 40 | void * 41 | tc_memalign(size_t alignment, size_t size) 42 | { 43 | void *p; 44 | 45 | p = memalign(alignment, size); 46 | if (p == NULL) { 47 | tc_log_info(LOG_EMERG, tc_errno, 48 | "memalign(%uz, %uz) failed", alignment, size); 49 | } 50 | 51 | return p; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/core/tc_alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _TC_ALLOC_H_INCLUDED_ 2 | #define _TC_ALLOC_H_INCLUDED_ 3 | 4 | 5 | #include 6 | 7 | 8 | void *tc_alloc(size_t size); 9 | 10 | #define tc_free free 11 | 12 | 13 | #if (TC_HAVE_POSIX_MEMALIGN || TC_HAVE_MEMALIGN) 14 | 15 | void *tc_memalign(size_t alignment, size_t size); 16 | 17 | #else 18 | 19 | #define tc_memalign(alignment, size) tc_alloc(size) 20 | 21 | #endif 22 | 23 | 24 | extern tc_uint_t tc_pagesize; 25 | 26 | 27 | #endif /* _TC_ALLOC_H_INCLUDED_ */ 28 | -------------------------------------------------------------------------------- /src/core/tc_common.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | int before(uint32_t seq1, uint32_t seq2) 5 | { 6 | return (int) ((uint32_t) (seq1-seq2)) < 0; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/core/tc_config.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _TC_CONFIG_H_INCLUDED_ 3 | #define _TC_CONFIG_H_INCLUDED_ 4 | 5 | 6 | #include 7 | 8 | 9 | 10 | typedef intptr_t tc_int_t; 11 | typedef uintptr_t tc_uint_t; 12 | typedef intptr_t tc_flag_t; 13 | 14 | 15 | #define TC_INT32_LEN sizeof("-2147483648") - 1 16 | #define TC_INT64_LEN sizeof("-9223372036854775808") - 1 17 | 18 | #if (TC_PTR_SIZE == 4) 19 | #define TC_INT_T_LEN TC_INT32_LEN 20 | #else 21 | #define TC_INT_T_LEN TC_INT64_LEN 22 | #endif 23 | 24 | 25 | #ifndef TC_ALIGNMENT 26 | #define TC_ALIGNMENT sizeof(unsigned long) /* platform word */ 27 | #endif 28 | 29 | #define tc_align(d, a) (((d) + (a - 1)) & ~(a - 1)) 30 | #define tc_align_ptr(p, a) \ 31 | (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1)) 32 | 33 | 34 | #if ((__GNU__ == 2) && (__GNUC_MINOR__ < 8)) 35 | #define TC_MAX_UINT32_VALUE (uint32_t) 0xffffffffLL 36 | #else 37 | #define TC_MAX_UINT32_VALUE (uint32_t) 0xffffffff 38 | #endif 39 | 40 | #define TC_MAX_INT32_VALUE (uint32_t) 0x7fffffff 41 | 42 | 43 | #endif /* _TC_CONFIG_H_INCLUDED_ */ 44 | -------------------------------------------------------------------------------- /src/core/tc_daemon.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | int 5 | daemonize() 6 | { 7 | int fd; 8 | 9 | switch (fork()) { 10 | case -1: 11 | return (-1); 12 | case 0: 13 | break; 14 | default: 15 | _exit(EXIT_SUCCESS); 16 | } 17 | if (setsid() == -1) { 18 | return (-1); 19 | } 20 | 21 | if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { 22 | if (dup2(fd, STDIN_FILENO) < 0) { 23 | perror("dup2 stdin"); 24 | return (-1); 25 | } 26 | if (dup2(fd, STDOUT_FILENO) < 0) { 27 | perror("dup2 stdout"); 28 | return (-1); 29 | } 30 | if (dup2(fd, STDERR_FILENO) < 0) { 31 | perror("dup2 stderr"); 32 | return (-1); 33 | } 34 | 35 | if (fd > STDERR_FILENO) { 36 | if (close(fd) < 0) { 37 | perror("close"); 38 | return (-1); 39 | } 40 | } 41 | } 42 | return (0); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/core/tc_link_list.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | p_link_node 5 | link_node_malloc(tc_pool_t *pool, void *data) 6 | { 7 | p_link_node p; 8 | 9 | p = (p_link_node) tc_pcalloc(pool, sizeof(link_node)); 10 | 11 | if (p != NULL) { 12 | p->data = data; 13 | } 14 | 15 | return p; 16 | } 17 | 18 | 19 | link_list * 20 | link_list_create(tc_pool_t *pool) 21 | { 22 | link_list *l = (link_list *) tc_pcalloc(pool, sizeof(link_list)); 23 | 24 | if (l != NULL) { 25 | l->size = 0; 26 | l->head.next = &(l->head); 27 | l->head.prev = &(l->head); 28 | } 29 | 30 | return l; 31 | } 32 | 33 | 34 | void 35 | link_list_append_by_order(link_list *l, p_link_node p) 36 | { 37 | p_link_node node, next; 38 | 39 | if (l->size > 0) { 40 | node = l->head.prev; 41 | next = node->next; 42 | while (node->data != NULL && after(node->key, p->key)) { 43 | next = node; 44 | node = node->prev; 45 | } 46 | node->next = p; 47 | p->prev = node; 48 | next->prev = p; 49 | p->next = next; 50 | l->size++; 51 | } else { 52 | link_list_append(l, p); 53 | } 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/core/tc_link_list.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_LINK_LIST_INCLUDED 2 | #define TC_LINK_LIST_INCLUDED 3 | 4 | #include 5 | 6 | typedef struct link_node_s 7 | { 8 | struct link_node_s *prev; 9 | struct link_node_s *next; 10 | void *data; 11 | uint32_t key; 12 | }link_node_t, link_node, *p_link_node; 13 | 14 | typedef struct link_list_s{ 15 | link_node head; 16 | int size; 17 | }link_list_t, link_list; 18 | 19 | 20 | p_link_node link_node_malloc(tc_pool_t *pool, void *data); 21 | link_list *link_list_create(tc_pool_t *pool); 22 | void link_list_append_by_order(link_list *l, p_link_node); 23 | 24 | 25 | static inline void 26 | link_list_append(link_list *l, p_link_node p) 27 | { 28 | p_link_node node; 29 | 30 | node = l->head.prev; 31 | node->next = p; 32 | p->prev = node; 33 | l->head.prev = p; 34 | p->next = &(l->head); 35 | l->size++; 36 | } 37 | 38 | 39 | static inline p_link_node 40 | link_list_remove(link_list *l, p_link_node node) 41 | { 42 | p_link_node next, prev; 43 | 44 | next = node->next; 45 | prev = node->prev; 46 | next->prev = prev; 47 | prev->next = next; 48 | l->size--; 49 | return node; 50 | } 51 | 52 | 53 | static inline p_link_node 54 | link_list_first(link_list *l) 55 | { 56 | if (l == NULL || l->head.next == &(l->head)) { 57 | return NULL; 58 | } 59 | 60 | return l->head.next; 61 | } 62 | 63 | 64 | static inline p_link_node 65 | link_list_get_next(link_list *l, p_link_node p) 66 | { 67 | if (p->next == &(l->head)) { 68 | return NULL; 69 | } 70 | 71 | return p->next; 72 | } 73 | 74 | #endif /* TC_LINK_LIST_INCLUDED */ 75 | 76 | -------------------------------------------------------------------------------- /src/core/tc_log.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | static int log_fd = -1; 5 | 6 | typedef struct { 7 | char *level; 8 | int len; 9 | } tc_log_level_t; 10 | 11 | static tc_log_level_t tc_log_levels[] = { 12 | { "[unknown]", 9 }, 13 | { "[emerg]", 7 }, 14 | { "[alert]", 7 }, 15 | { "[crit]", 6 }, 16 | { "[error]", 7 }, 17 | { "[warn]", 6 }, 18 | { "[notice]", 8}, 19 | { "[info]", 6}, 20 | { "[debug]", 7 } 21 | }; 22 | 23 | int 24 | tc_vscnprintf(char *buf, size_t size, const char *fmt, va_list args) 25 | { 26 | int i; 27 | 28 | /* 29 | * Attention for vsnprintf: http://lwn.net/Articles/69419/ 30 | */ 31 | i = vsnprintf(buf, size, fmt, args); 32 | 33 | if (i < (int) size) { 34 | return i; 35 | } 36 | 37 | if (size >= 1) { 38 | return size - 1; 39 | } else { 40 | return 0; 41 | } 42 | } 43 | 44 | int 45 | tc_scnprintf(char *buf, size_t size, const char *fmt, ...) 46 | { 47 | int i; 48 | va_list args; 49 | 50 | va_start(args, fmt); 51 | i = tc_vscnprintf(buf, size, fmt, args); 52 | va_end(args); 53 | 54 | return i; 55 | } 56 | 57 | int 58 | tc_log_init(const char *file) 59 | { 60 | int len; 61 | char default_file_path[256], *p; 62 | 63 | if (file == NULL) { 64 | len = strlen(TC_PREFIX); 65 | if (len >= 256) { 66 | fprintf(stderr, "file prefix too long: %s\n", TC_PREFIX); 67 | return -1; 68 | } 69 | strncpy(default_file_path, TC_PREFIX, len); 70 | p = default_file_path + len; 71 | len += strlen(TC_ERROR_LOG_PATH); 72 | if (len >= 256) { 73 | fprintf(stderr, "file path too long: %s\n", TC_PREFIX); 74 | return -1; 75 | } 76 | strcpy(p, TC_ERROR_LOG_PATH); 77 | file = default_file_path; 78 | } 79 | 80 | log_fd = open(file, O_RDWR|O_CREAT|O_APPEND, 0644); 81 | 82 | if (log_fd == -1) { 83 | fprintf(stderr, "Open log file:%s error: %s\n", file, strerror(errno)); 84 | } 85 | 86 | return log_fd; 87 | } 88 | 89 | void 90 | tc_log_end() 91 | { 92 | if (log_fd != -1) { 93 | close(log_fd); 94 | } 95 | 96 | log_fd = -1; 97 | } 98 | 99 | void 100 | tc_log_info(int level, int err, const char *fmt, ...) 101 | { 102 | int n, len; 103 | char buffer[LOG_MAX_LEN], *p; 104 | va_list args; 105 | tc_log_level_t *ll; 106 | 107 | if (log_fd == -1) { 108 | return; 109 | } 110 | 111 | #if (TC_DEBUG) 112 | tc_time_update(); 113 | #endif 114 | 115 | ll = &tc_log_levels[level]; 116 | 117 | p = buffer; 118 | 119 | p = tc_cpymem(p, tc_error_log_time, TC_ERR_LOG_TIME_LEN); 120 | *p++ = ' '; 121 | 122 | p = tc_cpymem(p, ll->level, ll->len); 123 | *p++ = ' '; 124 | 125 | n = len = TC_ERR_LOG_TIME_LEN + ll->len + 2; 126 | va_start(args, fmt); 127 | len += tc_vscnprintf(p, LOG_MAX_LEN - n, fmt, args); 128 | va_end(args); 129 | 130 | if (len < n) { 131 | return; 132 | } 133 | 134 | p = buffer + len; 135 | 136 | if (err > 0) { 137 | len += tc_scnprintf(p, LOG_MAX_LEN - len, " (%s)", strerror(err)); 138 | if (len < (p - buffer)) { 139 | return; 140 | } 141 | 142 | p = buffer + len; 143 | } 144 | 145 | *p++ = '\n'; 146 | 147 | write(log_fd, buffer, p - buffer); 148 | } 149 | 150 | void 151 | tc_log_trace(int level, int err, int flag, tc_iph_t *ip, tc_tcph_t *tcp) 152 | { 153 | char *tmp_buf, src_ip[BUF_LEN] ={0}, dst_ip[BUF_LEN] = {0}; 154 | uint32_t pack_size; 155 | unsigned int seq, ack_seq; 156 | struct in_addr src_addr, dst_addr; 157 | 158 | src_addr.s_addr = ip->saddr; 159 | tmp_buf = inet_ntoa(src_addr); 160 | strncpy(src_ip, tmp_buf, BUF_LEN - 1); 161 | 162 | dst_addr.s_addr = ip->daddr; 163 | tmp_buf = inet_ntoa(dst_addr); 164 | strncpy(dst_ip, tmp_buf, BUF_LEN - 1); 165 | 166 | pack_size = ntohs(ip->tot_len); 167 | seq = ntohl(tcp->seq); 168 | ack_seq = ntohl(tcp->ack_seq); 169 | 170 | if (BACKEND_FLAG == flag) { 171 | tc_log_info(level, err, 172 | "from bak:%s:%u-->%s:%u,len %u,seq=%u,ack=%u", 173 | src_ip, ntohs(tcp->source), dst_ip, 174 | ntohs(tcp->dest), pack_size, seq, ack_seq); 175 | 176 | } else if (CLIENT_FLAG == flag) { 177 | tc_log_info(level, err, 178 | "recv clt:%s:%u-->%s:%u,len %u,seq=%u,ack=%u", 179 | src_ip, ntohs(tcp->source), dst_ip, 180 | ntohs(tcp->dest), pack_size, seq, ack_seq); 181 | 182 | } else if (TO_BAKEND_FLAG == flag) { 183 | tc_log_info(level, err, 184 | "to bak:%s:%u-->%s:%u,len %u,seq=%u,ack=%u", 185 | src_ip, ntohs(tcp->source), dst_ip, 186 | ntohs(tcp->dest), pack_size, seq, ack_seq); 187 | 188 | } else if (RESERVED_CLIENT_FLAG == flag) { 189 | tc_log_info(level, err, 190 | "reserved clt:%s:%u-->%s:%u,len %u,seq=%u,ack=%u", 191 | src_ip, ntohs(tcp->source), dst_ip, 192 | ntohs(tcp->dest), pack_size, seq, ack_seq); 193 | 194 | } else if (FAKED_CLIENT_FLAG == flag) { 195 | tc_log_info(level, err, 196 | "fake clt:%s:%u-->%s:%u,len %u,seq=%u,ack=%u", 197 | src_ip, ntohs(tcp->source), dst_ip, 198 | ntohs(tcp->dest), pack_size, seq, ack_seq); 199 | 200 | } else if (UNKNOWN_FLAG == flag) { 201 | tc_log_info(level, err, 202 | "unknown packet:%s:%u-->%s:%u,len %u,seq=%u,ack=%u", 203 | src_ip, ntohs(tcp->source), dst_ip, 204 | ntohs(tcp->dest), pack_size, seq, ack_seq); 205 | 206 | } else { 207 | tc_log_info(level, err, 208 | "strange %s:%u-->%s:%u,length %u,seq=%u,ack=%u", 209 | src_ip, ntohs(tcp->source), dst_ip, 210 | ntohs(tcp->dest), pack_size, seq, ack_seq); 211 | } 212 | } 213 | 214 | 215 | -------------------------------------------------------------------------------- /src/core/tc_log.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_LOG_INCLUDED 2 | #define TC_LOG_INCLUDED 3 | 4 | #include 5 | 6 | #define LOG_STDERR 0 7 | #define LOG_EMERG 1 8 | #define LOG_ALERT 2 9 | #define LOG_CRIT 3 10 | #define LOG_ERR 4 11 | #define LOG_WARN 5 12 | #define LOG_NOTICE 6 13 | #define LOG_INFO 7 14 | #define LOG_DEBUG 8 15 | 16 | #define LOG_MAX_LEN 512 17 | #define BUF_LEN 64 18 | 19 | int tc_log_init(); 20 | void tc_log_end(); 21 | 22 | void tc_log_info(int level, int err, const char *fmt, ...); 23 | void tc_log_trace(int level, int err, int flag, tc_iph_t *ip, 24 | tc_tcph_t *tcp); 25 | 26 | #if (TC_DEBUG) 27 | 28 | #define tc_log_debug0(level, err, fmt) \ 29 | tc_log_info(level, err, (const char *) fmt) 30 | 31 | #define tc_log_debug1(level, err, fmt, a1) \ 32 | tc_log_info(level, err, (const char *) fmt, a1) 33 | 34 | #define tc_log_debug2(level, err, fmt, a1, a2) \ 35 | tc_log_info(level, err, (const char *) fmt, a1, a2) 36 | 37 | #define tc_log_debug3(level, err, fmt, a1, a2, a3) \ 38 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3) 39 | 40 | #define tc_log_debug4(level, err, fmt, a1, a2, a3, a4) \ 41 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3, a4) 42 | 43 | #define tc_log_debug5(level, err, fmt, a1, a2, a3, a4, a5) \ 44 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3, a4, a5) 45 | 46 | #define tc_log_debug6(level, err, fmt, a1, a2, a3, a4, a5, a6) \ 47 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3, a4, a5, a6) 48 | 49 | #define tc_log_debug7(level, err, fmt, a1, a2, a3, a4, a5, a6, a7) \ 50 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3, a4, a5, a6, a7) 51 | 52 | #define tc_log_debug8(level, err, fmt, a1, a2, a3, a4, a5, a6, a7, a8) \ 53 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3, a4, a5, a6, a7, a8) 54 | 55 | #define tc_log_debug_trace(level, err, flag, ip, tcp) \ 56 | tc_log_trace(level, err, flag, ip, tcp) 57 | 58 | #else 59 | 60 | #define tc_log_debug0(level, err, fmt) 61 | #define tc_log_debug1(level, err, fmt, a1) 62 | #define tc_log_debug2(level, err, fmt, a1, a2) 63 | #define tc_log_debug3(level, err, fmt, a1, a2, a3) 64 | #define tc_log_debug4(level, err, fmt, a1, a2, a3, a4) 65 | #define tc_log_debug5(level, err, fmt, a1, a2, a3, a4, a5) 66 | #define tc_log_debug6(level, err, fmt, a1, a2, a3, a4, a5, a6) 67 | #define tc_log_debug7(level, err, fmt, a1, a2, a3, a4, a5, a6, a7) 68 | #define tc_log_debug8(level, err, fmt, a1, a2, a3, a4, a5, a6, a7, a8) 69 | #define tc_log_debug_trace(level, err, flag, ip, tcp) 70 | 71 | #endif /* TC_DEBUG */ 72 | 73 | #endif /* TC_LOG_INCLUDED */ 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/core/tc_palloc.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | static void *tc_palloc_block(tc_pool_t *pool, size_t size); 5 | static void *tc_palloc_large(tc_pool_t *pool, size_t size); 6 | 7 | 8 | tc_pool_t * 9 | tc_create_pool(size_t size, size_t pool_max) 10 | { 11 | tc_pool_t *p; 12 | 13 | if (size < TC_MIN_POOL_SIZE) { 14 | size = TC_MIN_POOL_SIZE; 15 | } 16 | 17 | p = tc_memalign(TC_POOL_ALIGNMENT, size); 18 | if (p != NULL) { 19 | p->d.last = (u_char *) p + sizeof(tc_pool_t); 20 | p->d.end = (u_char *) p + size; 21 | p->d.next = NULL; 22 | p->d.failed = 0; 23 | 24 | size = size - sizeof(tc_pool_t); 25 | 26 | if (pool_max && size >= pool_max) { 27 | p->max = pool_max; 28 | } else { 29 | p->max = (size < TC_MAX_ALLOC_FROM_POOL) ? 30 | size : TC_MAX_ALLOC_FROM_POOL; 31 | } 32 | 33 | p->current = p; 34 | p->large = NULL; 35 | } 36 | 37 | return p; 38 | } 39 | 40 | 41 | void 42 | tc_destroy_pool(tc_pool_t *pool) 43 | { 44 | tc_pool_t *p, *n; 45 | tc_pool_large_t *l; 46 | 47 | for (l = pool->large; l; l = l->next) { 48 | 49 | if (l->alloc) { 50 | tc_free(l->alloc); 51 | } 52 | } 53 | 54 | for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { 55 | tc_free(p); 56 | 57 | if (n == NULL) { 58 | break; 59 | } 60 | } 61 | } 62 | 63 | 64 | void * 65 | tc_palloc(tc_pool_t *pool, size_t size) 66 | { 67 | u_char *m; 68 | tc_pool_t *p; 69 | 70 | if (size <= pool->max) { 71 | 72 | p = pool->current; 73 | 74 | do { 75 | m = tc_align_ptr(p->d.last, TC_ALIGNMENT); 76 | 77 | if ((size_t) (p->d.end - m) >= size) { 78 | p->d.last = m + size; 79 | 80 | return m; 81 | } 82 | 83 | p = p->d.next; 84 | 85 | } while (p); 86 | 87 | return tc_palloc_block(pool, size); 88 | } 89 | 90 | return tc_palloc_large(pool, size); 91 | } 92 | 93 | 94 | static void * 95 | tc_palloc_block(tc_pool_t *pool, size_t size) 96 | { 97 | u_char *m; 98 | size_t psize; 99 | tc_pool_t *p, *new, *current; 100 | 101 | psize = (size_t) (pool->d.end - (u_char *) pool); 102 | 103 | m = tc_memalign(TC_POOL_ALIGNMENT, psize); 104 | if (m != NULL) { 105 | new = (tc_pool_t *) m; 106 | 107 | new->d.end = m + psize; 108 | new->d.next = NULL; 109 | new->d.failed = 0; 110 | 111 | m += sizeof(tc_pool_data_t); 112 | m = tc_align_ptr(m, TC_ALIGNMENT); 113 | new->d.last = m + size; 114 | 115 | current = pool->current; 116 | 117 | if (current) { 118 | for (p = current; p->d.next; p = p->d.next) { 119 | if (p->d.failed++ > 4) { 120 | current = p->d.next; 121 | } 122 | } 123 | 124 | p->d.next = new; 125 | } 126 | 127 | pool->current = current ? current : new; 128 | } 129 | 130 | return m; 131 | } 132 | 133 | 134 | static void * 135 | tc_palloc_large(tc_pool_t *pool, size_t size) 136 | { 137 | void *p; 138 | tc_uint_t n; 139 | tc_pool_large_t *large; 140 | 141 | p = tc_alloc(size); 142 | if (p != NULL) { 143 | 144 | n = 0; 145 | 146 | for (large = pool->large; large; large = large->next) { 147 | if (large->alloc == NULL) { 148 | large->alloc = p; 149 | return p; 150 | } 151 | 152 | if (n++ > 3) { 153 | break; 154 | } 155 | } 156 | 157 | large = tc_palloc(pool, sizeof(tc_pool_large_t)); 158 | if (large == NULL) { 159 | tc_free(p); 160 | return NULL; 161 | } 162 | 163 | large->alloc = p; 164 | large->next = pool->large; 165 | pool->large = large; 166 | } 167 | 168 | return p; 169 | } 170 | 171 | 172 | tc_int_t 173 | tc_pfree(tc_pool_t *pool, void *p) 174 | { 175 | tc_pool_large_t *l; 176 | 177 | for (l = pool->large; l; l = l->next) { 178 | if (p == l->alloc) { 179 | tc_free(l->alloc); 180 | l->alloc = NULL; 181 | 182 | return TC_OK; 183 | } 184 | } 185 | 186 | return TC_DECLINED; 187 | } 188 | 189 | 190 | void * 191 | tc_pcalloc(tc_pool_t *pool, size_t size) 192 | { 193 | void *p; 194 | 195 | p = tc_palloc(pool, size); 196 | if (p) { 197 | tc_memzero(p, size); 198 | } 199 | 200 | return p; 201 | } 202 | 203 | 204 | -------------------------------------------------------------------------------- /src/core/tc_palloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _TC_PALLOC_H_INCLUDED_ 2 | #define _TC_PALLOC_H_INCLUDED_ 3 | 4 | 5 | #include 6 | 7 | typedef struct tc_pool_large_s tc_pool_large_t; 8 | 9 | struct tc_pool_large_s { 10 | tc_pool_large_t *next; 11 | void *alloc; 12 | }; 13 | 14 | 15 | typedef struct { 16 | u_char *last; 17 | u_char *end; 18 | tc_pool_t *next; 19 | tc_uint_t failed; 20 | } tc_pool_data_t; 21 | 22 | 23 | struct tc_pool_s { 24 | tc_pool_data_t d; 25 | size_t max; 26 | tc_pool_t *current; 27 | tc_pool_large_t *large; 28 | }; 29 | 30 | 31 | tc_pool_t *tc_create_pool(size_t size, size_t pool_max); 32 | void tc_destroy_pool(tc_pool_t *pool); 33 | 34 | void *tc_palloc(tc_pool_t *pool, size_t size); 35 | void *tc_pcalloc(tc_pool_t *pool, size_t size); 36 | tc_int_t tc_pfree(tc_pool_t *pool, void *p); 37 | 38 | 39 | #endif /* _TC_PALLOC_H_INCLUDED_ */ 40 | -------------------------------------------------------------------------------- /src/core/tc_rbtree.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | 5 | static inline void tc_rbtree_left_rotate(tc_rbtree_node_t **root, 6 | tc_rbtree_node_t *sentinel, tc_rbtree_node_t *node); 7 | static inline void tc_rbtree_right_rotate(tc_rbtree_node_t **root, 8 | tc_rbtree_node_t *sentinel, tc_rbtree_node_t *node); 9 | 10 | 11 | void 12 | tc_rbtree_insert(tc_rbtree_t *tree, 13 | tc_rbtree_node_t *node) 14 | { 15 | tc_rbtree_node_t **root, *temp, *sentinel; 16 | 17 | 18 | root = (tc_rbtree_node_t **) &tree->root; 19 | sentinel = tree->sentinel; 20 | 21 | if (*root != sentinel) { 22 | tree->insert(*root, node, sentinel); 23 | 24 | while (node != *root && tc_rbt_is_red(node->parent)) { 25 | 26 | if (node->parent == node->parent->parent->left) { 27 | temp = node->parent->parent->right; 28 | 29 | if (tc_rbt_is_red(temp)) { 30 | tc_rbt_black(node->parent); 31 | tc_rbt_black(temp); 32 | tc_rbt_red(node->parent->parent); 33 | node = node->parent->parent; 34 | 35 | } else { 36 | if (node == node->parent->right) { 37 | node = node->parent; 38 | tc_rbtree_left_rotate(root, sentinel, node); 39 | } 40 | 41 | tc_rbt_black(node->parent); 42 | tc_rbt_red(node->parent->parent); 43 | tc_rbtree_right_rotate(root, sentinel, 44 | node->parent->parent); 45 | } 46 | 47 | } else { 48 | temp = node->parent->parent->left; 49 | 50 | if (tc_rbt_is_red(temp)) { 51 | tc_rbt_black(node->parent); 52 | tc_rbt_black(temp); 53 | tc_rbt_red(node->parent->parent); 54 | node = node->parent->parent; 55 | 56 | } else { 57 | if (node == node->parent->left) { 58 | node = node->parent; 59 | tc_rbtree_right_rotate(root, sentinel, node); 60 | } 61 | 62 | tc_rbt_black(node->parent); 63 | tc_rbt_red(node->parent->parent); 64 | tc_rbtree_left_rotate(root, sentinel, node->parent->parent); 65 | } 66 | } 67 | } 68 | 69 | tc_rbt_black(*root); 70 | 71 | } else { 72 | node->parent = NULL; 73 | node->left = sentinel; 74 | node->right = sentinel; 75 | tc_rbt_black(node); 76 | *root = node; 77 | } 78 | 79 | } 80 | 81 | 82 | void 83 | tc_rbtree_insert_value(tc_rbtree_node_t *temp, tc_rbtree_node_t *node, 84 | tc_rbtree_node_t *sentinel) 85 | { 86 | tc_rbtree_node_t **p; 87 | 88 | for ( ;; ) { 89 | 90 | p = (node->key < temp->key) ? &temp->left : &temp->right; 91 | 92 | if (*p == sentinel) { 93 | break; 94 | } 95 | 96 | temp = *p; 97 | } 98 | 99 | *p = node; 100 | node->parent = temp; 101 | node->left = sentinel; 102 | node->right = sentinel; 103 | tc_rbt_red(node); 104 | } 105 | 106 | 107 | void 108 | tc_rbtree_insert_timer_value(tc_rbtree_node_t *temp, tc_rbtree_node_t *node, 109 | tc_rbtree_node_t *sentinel) 110 | { 111 | tc_rbtree_node_t **p; 112 | 113 | for ( ;; ) { 114 | 115 | /* 116 | * Timer values 117 | * 1) are spread in small range, usually several minutes, 118 | * 2) and overflow each 49 days, if milliseconds are stored in 32 bits. 119 | * The comparison takes into account that overflow. 120 | */ 121 | 122 | /* node->key < temp->key */ 123 | 124 | p = ((tc_rbtree_key_int_t) (node->key - temp->key) < 0) 125 | ? &temp->left : &temp->right; 126 | 127 | if (*p == sentinel) { 128 | break; 129 | } 130 | 131 | temp = *p; 132 | } 133 | 134 | *p = node; 135 | node->parent = temp; 136 | node->left = sentinel; 137 | node->right = sentinel; 138 | tc_rbt_red(node); 139 | } 140 | 141 | 142 | void 143 | tc_rbtree_delete(tc_rbtree_t *tree, 144 | tc_rbtree_node_t *node) 145 | { 146 | tc_uint_t red; 147 | tc_rbtree_node_t **root, *sentinel, *subst, *temp, *w; 148 | 149 | 150 | root = (tc_rbtree_node_t **) &tree->root; 151 | sentinel = tree->sentinel; 152 | 153 | if (node->left == sentinel) { 154 | temp = node->right; 155 | subst = node; 156 | 157 | } else if (node->right == sentinel) { 158 | temp = node->left; 159 | subst = node; 160 | 161 | } else { 162 | subst = tc_rbtree_min(node->right, sentinel); 163 | 164 | if (subst->left != sentinel) { 165 | temp = subst->left; 166 | } else { 167 | temp = subst->right; 168 | } 169 | } 170 | 171 | if (subst == *root) { 172 | *root = temp; 173 | tc_rbt_black(temp); 174 | 175 | node->left = NULL; 176 | node->right = NULL; 177 | node->parent = NULL; 178 | node->key = 0; 179 | 180 | return; 181 | } 182 | 183 | red = tc_rbt_is_red(subst); 184 | 185 | if (subst == subst->parent->left) { 186 | subst->parent->left = temp; 187 | 188 | } else { 189 | subst->parent->right = temp; 190 | } 191 | 192 | if (subst == node) { 193 | 194 | temp->parent = subst->parent; 195 | 196 | } else { 197 | 198 | if (subst->parent == node) { 199 | temp->parent = subst; 200 | 201 | } else { 202 | temp->parent = subst->parent; 203 | } 204 | 205 | subst->left = node->left; 206 | subst->right = node->right; 207 | subst->parent = node->parent; 208 | tc_rbt_copy_color(subst, node); 209 | 210 | if (node == *root) { 211 | *root = subst; 212 | 213 | } else { 214 | if (node == node->parent->left) { 215 | node->parent->left = subst; 216 | } else { 217 | node->parent->right = subst; 218 | } 219 | } 220 | 221 | if (subst->left != sentinel) { 222 | subst->left->parent = subst; 223 | } 224 | 225 | if (subst->right != sentinel) { 226 | subst->right->parent = subst; 227 | } 228 | } 229 | 230 | node->left = NULL; 231 | node->right = NULL; 232 | node->parent = NULL; 233 | node->key = 0; 234 | 235 | if (red) { 236 | return; 237 | } 238 | 239 | /* a delete fixup */ 240 | 241 | while (temp != *root && tc_rbt_is_black(temp)) { 242 | 243 | if (temp == temp->parent->left) { 244 | w = temp->parent->right; 245 | 246 | if (tc_rbt_is_red(w)) { 247 | tc_rbt_black(w); 248 | tc_rbt_red(temp->parent); 249 | tc_rbtree_left_rotate(root, sentinel, temp->parent); 250 | w = temp->parent->right; 251 | } 252 | 253 | if (tc_rbt_is_black(w->left) && tc_rbt_is_black(w->right)) { 254 | tc_rbt_red(w); 255 | temp = temp->parent; 256 | 257 | } else { 258 | if (tc_rbt_is_black(w->right)) { 259 | tc_rbt_black(w->left); 260 | tc_rbt_red(w); 261 | tc_rbtree_right_rotate(root, sentinel, w); 262 | w = temp->parent->right; 263 | } 264 | 265 | tc_rbt_copy_color(w, temp->parent); 266 | tc_rbt_black(temp->parent); 267 | tc_rbt_black(w->right); 268 | tc_rbtree_left_rotate(root, sentinel, temp->parent); 269 | temp = *root; 270 | } 271 | 272 | } else { 273 | w = temp->parent->left; 274 | 275 | if (tc_rbt_is_red(w)) { 276 | tc_rbt_black(w); 277 | tc_rbt_red(temp->parent); 278 | tc_rbtree_right_rotate(root, sentinel, temp->parent); 279 | w = temp->parent->left; 280 | } 281 | 282 | if (tc_rbt_is_black(w->left) && tc_rbt_is_black(w->right)) { 283 | tc_rbt_red(w); 284 | temp = temp->parent; 285 | 286 | } else { 287 | if (tc_rbt_is_black(w->left)) { 288 | tc_rbt_black(w->right); 289 | tc_rbt_red(w); 290 | tc_rbtree_left_rotate(root, sentinel, w); 291 | w = temp->parent->left; 292 | } 293 | 294 | tc_rbt_copy_color(w, temp->parent); 295 | tc_rbt_black(temp->parent); 296 | tc_rbt_black(w->left); 297 | tc_rbtree_right_rotate(root, sentinel, temp->parent); 298 | temp = *root; 299 | } 300 | } 301 | } 302 | 303 | tc_rbt_black(temp); 304 | } 305 | 306 | 307 | static inline void 308 | tc_rbtree_left_rotate(tc_rbtree_node_t **root, tc_rbtree_node_t *sentinel, 309 | tc_rbtree_node_t *node) 310 | { 311 | tc_rbtree_node_t *temp; 312 | 313 | temp = node->right; 314 | node->right = temp->left; 315 | 316 | if (temp->left != sentinel) { 317 | temp->left->parent = node; 318 | } 319 | 320 | temp->parent = node->parent; 321 | 322 | if (node == *root) { 323 | *root = temp; 324 | 325 | } else if (node == node->parent->left) { 326 | node->parent->left = temp; 327 | 328 | } else { 329 | node->parent->right = temp; 330 | } 331 | 332 | temp->left = node; 333 | node->parent = temp; 334 | } 335 | 336 | 337 | static inline void 338 | tc_rbtree_right_rotate(tc_rbtree_node_t **root, tc_rbtree_node_t *sentinel, 339 | tc_rbtree_node_t *node) 340 | { 341 | tc_rbtree_node_t *temp; 342 | 343 | temp = node->left; 344 | node->left = temp->right; 345 | 346 | if (temp->right != sentinel) { 347 | temp->right->parent = node; 348 | } 349 | 350 | temp->parent = node->parent; 351 | 352 | if (node == *root) { 353 | *root = temp; 354 | 355 | } else if (node == node->parent->right) { 356 | node->parent->right = temp; 357 | 358 | } else { 359 | node->parent->left = temp; 360 | } 361 | 362 | temp->right = node; 363 | node->parent = temp; 364 | } 365 | -------------------------------------------------------------------------------- /src/core/tc_rbtree.h: -------------------------------------------------------------------------------- 1 | #ifndef _TC_RBTREE_H_INCLUDED_ 2 | #define _TC_RBTREE_H_INCLUDED_ 3 | 4 | 5 | #include 6 | 7 | 8 | typedef tc_uint_t tc_rbtree_key_t; 9 | typedef tc_int_t tc_rbtree_key_int_t; 10 | 11 | 12 | typedef struct tc_rbtree_node_s tc_rbtree_node_t; 13 | 14 | struct tc_rbtree_node_s { 15 | tc_rbtree_key_t key; 16 | tc_rbtree_node_t *left; 17 | tc_rbtree_node_t *right; 18 | tc_rbtree_node_t *parent; 19 | u_char color; 20 | u_char data; 21 | }; 22 | 23 | 24 | typedef struct tc_rbtree_s tc_rbtree_t; 25 | 26 | typedef void (*tc_rbtree_insert_pt) (tc_rbtree_node_t *root, 27 | tc_rbtree_node_t *node, tc_rbtree_node_t *sentinel); 28 | 29 | struct tc_rbtree_s { 30 | tc_rbtree_node_t *root; 31 | tc_rbtree_node_t *sentinel; 32 | tc_rbtree_insert_pt insert; 33 | }; 34 | 35 | 36 | #define tc_rbtree_init(tree, s, i) \ 37 | tc_rbtree_sentinel_init(s); \ 38 | (tree)->root = s; \ 39 | (tree)->sentinel = s; \ 40 | (tree)->insert = i 41 | 42 | 43 | void tc_rbtree_insert(tc_rbtree_t *tree, 44 | tc_rbtree_node_t *node); 45 | void tc_rbtree_delete(tc_rbtree_t *tree, 46 | tc_rbtree_node_t *node); 47 | void tc_rbtree_insert_value(tc_rbtree_node_t *root, tc_rbtree_node_t *node, 48 | tc_rbtree_node_t *sentinel); 49 | void tc_rbtree_insert_timer_value(tc_rbtree_node_t *root, 50 | tc_rbtree_node_t *node, tc_rbtree_node_t *sentinel); 51 | 52 | 53 | #define tc_rbt_red(node) ((node)->color = 1) 54 | #define tc_rbt_black(node) ((node)->color = 0) 55 | #define tc_rbt_is_red(node) ((node)->color) 56 | #define tc_rbt_is_black(node) (!tc_rbt_is_red(node)) 57 | #define tc_rbt_copy_color(n1, n2) (n1->color = n2->color) 58 | 59 | 60 | /* a sentinel must be black */ 61 | 62 | #define tc_rbtree_sentinel_init(node) tc_rbt_black(node) 63 | 64 | 65 | static inline tc_rbtree_node_t * 66 | tc_rbtree_min(tc_rbtree_node_t *node, tc_rbtree_node_t *sentinel) 67 | { 68 | while (node->left != sentinel) { 69 | node = node->left; 70 | } 71 | 72 | return node; 73 | } 74 | 75 | 76 | #endif /* _TC_RBTREE_H_INCLUDED_ */ 77 | -------------------------------------------------------------------------------- /src/core/tc_signal.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | int 5 | sigignore(int sig) 6 | { 7 | struct sigaction sa; 8 | 9 | sa.sa_handler = SIG_IGN; 10 | sa.sa_flags = 0; 11 | 12 | if (sigemptyset(&sa.sa_mask) == -1 || sigaction(sig, &sa, 0) == -1) { 13 | return -1; 14 | } 15 | 16 | return 0; 17 | } 18 | 19 | int 20 | set_signal_handler(signal_t *signals) 21 | { 22 | int status; 23 | signal_t *sig; 24 | struct sigaction sa; 25 | 26 | for (sig = signals; sig->signo != 0; sig++) { 27 | memset(&sa, 0, sizeof(sa)); 28 | sa.sa_handler = sig->handler; 29 | sa.sa_flags = sig->flags; 30 | sigemptyset(&sa.sa_mask); 31 | 32 | status = sigaction(sig->signo, &sa, NULL); 33 | if (status < 0) { 34 | tc_log_info(LOG_ERR, errno, "sigaction(%s) failed", sig->signame); 35 | return -1; 36 | } 37 | } 38 | 39 | return 0; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/core/tc_signal.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_SIGNAL_INCLUDED 2 | #define TC_SIGNAL_INCLUDED 3 | 4 | #include 5 | 6 | typedef struct signal_s{ 7 | int signo; 8 | char *signame; 9 | int flags; 10 | void (*handler)(int signo); 11 | }signal_t; 12 | 13 | int set_signal_handler(signal_t *signals); 14 | int sigignore(int sig); 15 | 16 | #endif /* TC_SIGNAL_INCLUDED */ 17 | 18 | -------------------------------------------------------------------------------- /src/core/tc_time.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | tc_atomic_t tc_update_time; 5 | volatile char *tc_error_log_time; 6 | volatile time_t tc_current_time_sec; 7 | volatile long tc_current_time_msec; 8 | volatile struct tm tc_current_tm; 9 | 10 | static char cache_err_log_time[TC_ERR_LOG_TIME_STR_LEN]; 11 | 12 | 13 | void 14 | tc_time_init() 15 | { 16 | tc_update_time = 0; 17 | 18 | tc_time_update(); 19 | } 20 | 21 | void 22 | tc_time_update() 23 | { 24 | long msec; 25 | time_t sec; 26 | struct tm tm; 27 | struct timeval tv; 28 | 29 | gettimeofday(&tv, NULL); 30 | 31 | sec = tv.tv_sec; 32 | msec = tv.tv_usec / 1000; 33 | 34 | tc_current_time_sec = sec; 35 | tc_current_time_msec = sec * 1000 + msec; 36 | 37 | tc_localtime(sec, &tm); 38 | 39 | snprintf(cache_err_log_time, TC_ERR_LOG_TIME_STR_LEN, 40 | "%4d/%02d/%02d %02d:%02d:%02d +%03d", 41 | tm.tm_year, tm.tm_mon, 42 | tm.tm_mday, tm.tm_hour, 43 | tm.tm_min, tm.tm_sec, 44 | (int) msec); 45 | 46 | tc_current_tm = tm; 47 | tc_error_log_time = cache_err_log_time; 48 | } 49 | 50 | void 51 | tc_localtime(time_t sec, struct tm *tm) 52 | { 53 | #if (HAVE_LOCALTIME_R) 54 | (void) localtime_r(&sec, tm); 55 | #else 56 | struct tm *t; 57 | 58 | t = localtime(&sec); 59 | *tm = *t; 60 | #endif 61 | 62 | tm->tm_mon++; 63 | tm->tm_year += 1900; 64 | } 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/core/tc_time.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_TIME_INCLUDED 2 | #define TC_TIME_INCLUDED 3 | 4 | #include 5 | 6 | #define TC_ERR_LOG_TIME_LEN (sizeof("2012-07-31 12:35:00 +999") - 1) 7 | #define TC_ERR_LOG_TIME_STR_LEN (TC_ERR_LOG_TIME_LEN + 1) 8 | 9 | #define tc_time() tc_current_time_sec 10 | #define tc_milliscond_time() tc_current_time_msec 11 | #define tc_time_diff(s1, ms1, s2, ms2) \ 12 | (((s2) * 1000 + (ms2)) - ((s1) * 1000 + (ms1))) 13 | 14 | extern volatile int tc_update_time; 15 | extern volatile char *tc_error_log_time; 16 | extern volatile long tc_current_time_msec; 17 | extern volatile time_t tc_current_time_sec; 18 | extern volatile struct tm tc_current_tm; 19 | 20 | void tc_time_init(); 21 | void tc_time_update(void); 22 | void tc_localtime(time_t sec, struct tm *tm); 23 | 24 | #endif /* TC_TIME_INCLUDED */ 25 | -------------------------------------------------------------------------------- /src/core/xcopy.h: -------------------------------------------------------------------------------- 1 | #ifndef XCOPY_H_INCLUDED 2 | #define XCOPY_H_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define VERSION "1.0.0" 34 | 35 | #define INTERNAL_VERSION 6 36 | 37 | typedef struct tc_pool_s tc_pool_t; 38 | typedef struct tc_buf_s tc_buf_t; 39 | 40 | #define TC_MAX_ALLOC_FROM_POOL (tc_pagesize - 1) 41 | #define TC_DEFAULT_POOL_SIZE (16 * 1024) 42 | #define TC_DEFAULT_LR_POOL_SIZE (4 *1024 * 1024) 43 | #define TC_POOL_ALIGNMENT 16 44 | #define TC_MIN_POOL_SIZE \ 45 | tc_align((sizeof(tc_pool_t) + 2 * sizeof(tc_pool_large_t)), \ 46 | TC_POOL_ALIGNMENT) 47 | 48 | #define ETHER_ADDR_LEN 0x6 49 | 50 | #define DEFAULT_MTU 1500 51 | #define DEFAULT_MSS 1460 52 | #define MAX_FRAME_LENGTH 65550 53 | #define SERVER_PORT 36524 54 | 55 | #define DEFAULT_CONN_INIT_SP_FACT 1024 56 | #define FIRST_PORT 32768 57 | #define LAST_PORT 61000 58 | #define VALID_PORTS_NUM (LAST_PORT - FIRST_PORT + 1) 59 | 60 | #define MAX_REAL_SERVERS 256 61 | #define MAX_PCAP_FILES 1024 62 | 63 | #define DEFAULT_SESSION_TIMEOUT 75 64 | #define DEFAULT_TIMEOUT 120 65 | #define FIN_TIMEOUT 6000 66 | 67 | #define CHECK_INTERVAL 50 68 | #define OUTPUT_INTERVAL 5000 69 | 70 | #define MAX_WRITE_TRIES 1024 71 | #define MAX_READ_LOG_TRIES 65536 72 | 73 | #define SLOT_MAX 256 74 | #define SLOT_AVG 32 75 | 76 | #define SLP_THRSH_NUM 4 77 | #define M_CLIENT_IP_NUM 65536 78 | 79 | /* max fd number for select */ 80 | #define MAX_FD_NUM 1024 81 | #define MAX_FD_VALUE (MAX_FD_NUM-1) 82 | #define MAX_CONNECTION_NUM 16 83 | 84 | #define COMB_MAX_NUM 16 85 | #define COMB_LENGTH (COMB_MAX_NUM * MSG_SERVER_SIZE) 86 | 87 | #define SRC_DIRECTION 0 88 | #define DST_DIRECTION 1 89 | 90 | #define MAX_ALLOWED_IP_NUM 32 91 | 92 | #define CLIENT_ADD 1 93 | #define CLIENT_DEL 2 94 | 95 | #define UNKNOWN 0 96 | #define REMOTE 1 97 | #define LOCAL 2 98 | 99 | #define CHECK_DEST 1 100 | #define CHECK_SRC 2 101 | 102 | #define TYPE_DEFAULT 0 103 | #define TYPE_DELAY_ACK 1 104 | #define TYPE_RTO 2 105 | #define TYPE_ACT 3 106 | #define TYPE_DELAY_IGNITE 4 107 | #define TYPE_DELAY_OVER 5 108 | 109 | #define DEF_TOPO_WAIT 10 110 | 111 | #if (TC_COMET) 112 | #define DEFAULT_RTO 1000 113 | #else 114 | #define DEFAULT_RTO 100 115 | #endif 116 | 117 | #define BREAK_NUM 20000 118 | #define HALF_MILLION 500000 119 | #define MILLION 1000000 120 | 121 | #define TCP_HEADER_DOFF_MIN_VALUE 5 122 | #define TCP_HEADER_DOFF_MSS_VALUE 6 123 | #define TCP_HEADER_DOFF_TS_VALUE 8 124 | #define TCP_HEADER_DOFF_WS_TS_VALUE 9 125 | 126 | 127 | typedef volatile sig_atomic_t tc_atomic_t; 128 | 129 | typedef struct iphdr tc_iph_t; 130 | typedef struct tcphdr tc_tcph_t; 131 | 132 | /* 133 | * the 40 bytes available for TCP options 134 | * we support 24 bytes for TCP options 135 | */ 136 | #define MAX_OPTION_LEN 24 137 | #define TCPOPT_WSCALE 3 138 | 139 | #define RESP_HEADER_SIZE (sizeof(tc_iph_t) + sizeof(tc_tcph_t) + MAX_OPTION_LEN) 140 | #define RESP_MAX_USEFUL_SIZE RESP_HEADER_SIZE 141 | 142 | /* bool constants */ 143 | #if (HAVE_STDBOOL_H) 144 | #include 145 | #else 146 | #define bool char 147 | #define false 0 148 | #define true 1 149 | #endif /* HAVE_STDBOOL_H */ 150 | 151 | enum sess_status{ 152 | CLOSED = 0, 153 | SYN_SENT = 1, 154 | SYN_CONFIRM = 2, 155 | SYN_ACK = 4, 156 | SEND_REQ = 8, 157 | RECV_RESP = 16, 158 | SERVER_FIN = 32, 159 | CLIENT_FIN = 64 160 | }; 161 | 162 | enum packet_classification{ 163 | CLIENT_FLAG, 164 | RESERVED_CLIENT_FLAG, 165 | BACKEND_FLAG, 166 | FAKED_CLIENT_FLAG, 167 | TO_BAKEND_FLAG, 168 | UNKNOWN_FLAG 169 | }; 170 | 171 | #define SESS_OVER_STATE (SERVER_FIN | CLIENT_FIN) 172 | 173 | #define ETHER_ADDR_STR_LEN 17 174 | 175 | #ifndef ETHERTYPE_VLAN 176 | #define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging */ 177 | #endif 178 | 179 | #define CISCO_HDLC_LEN 4 180 | #define SLL_HDR_LEN 16 181 | #define IP_RECV_BUF_SIZE 65536 182 | #define ETHERNET_HDR_LEN (sizeof(struct ethernet_hdr)) 183 | #define DEFAULT_DEVICE "any" 184 | 185 | #define IP_HEADER_LEN sizeof(tc_iph_t) 186 | #define TCP_HEADER_MIN_LEN sizeof(tc_tcph_t) 187 | #define FAKE_FRAME_LEN (60 + ETHERNET_HDR_LEN) 188 | #define FAKE_MIN_IP_DATAGRAM_LEN (IP_HEADER_LEN + (TCP_HEADER_DOFF_MIN_VALUE << 2)) 189 | #define FAKE_IP_TS_DATAGRAM_LEN (IP_HEADER_LEN + (TCP_HEADER_DOFF_TS_VALUE << 2)) 190 | #define FAKE_SYN_IP_DATAGRAM_LEN (IP_HEADER_LEN + (TCP_HEADER_DOFF_MSS_VALUE << 2)) 191 | #define FAKE_SYN_IP_TS_DATAGRAM_LEN (IP_HEADER_LEN + (TCP_HEADER_DOFF_WS_TS_VALUE << 2)) 192 | 193 | /* 194 | * Ethernet II header 195 | * static header size: 14 bytes 196 | */ 197 | struct ethernet_hdr { 198 | uint8_t ether_dhost[ETHER_ADDR_LEN]; 199 | uint8_t ether_shost[ETHER_ADDR_LEN]; 200 | uint16_t ether_type; 201 | }; 202 | 203 | /* receiving buffer size for response */ 204 | #define CAPTURE_RESP_HEADER_MAX_LEN 120 205 | #define CAPTURE_RESP_MAX_SIZE CAPTURE_RESP_HEADER_MAX_LEN 206 | #define RESP_RECV_BUF_SIZE (CAPTURE_RESP_MAX_SIZE) 207 | 208 | 209 | typedef struct connections_s{ 210 | int index; 211 | int num; 212 | int remained_num; 213 | int fds[MAX_CONNECTION_NUM]; 214 | }connections_t; 215 | 216 | #define TIMER_INTERVAL 1 217 | 218 | /* global functions */ 219 | int daemonize(); 220 | int before(uint32_t seq1, uint32_t seq2); 221 | 222 | #define after(seq2, seq1) before(seq1, seq2) 223 | 224 | #define TC_OK 0 225 | #define TC_ERROR -1 226 | #define TC_ERR_EXIT 1 227 | #define TC_DECLINED -2 228 | 229 | #define tc_cpymem(d, s, l) (((char *) memcpy(d, (void *) s, l)) + (l)) 230 | #define tc_memzero(d, l) (memset(d, 0, l)) 231 | #define tc_abs(value) (((value) >= 0) ? (value) : - (value)) 232 | #define tc_max(val1, val2) ((val1 < val2) ? (val2) : (val1)) 233 | #define tc_min(val1, val2) ((val1 > val2) ? (val2) : (val1)) 234 | 235 | #include 236 | #include 237 | #include 238 | #include 239 | #include 240 | #include 241 | #include 242 | #include 243 | #include 244 | #include 245 | #include 246 | #include 247 | #include 248 | 249 | 250 | #endif /* XCOPY_H_INCLUDED */ 251 | 252 | -------------------------------------------------------------------------------- /src/event/tc_event.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | tc_atomic_t tc_over = 0; 5 | 6 | static tc_event_t *ev_mark[MAX_FD_NUM]; 7 | 8 | static tc_event_actions_t tc_event_actions = { 9 | tc_select_create, 10 | tc_select_destroy, 11 | tc_select_add_event, 12 | tc_select_del_event, 13 | tc_select_polling 14 | }; 15 | 16 | 17 | int tc_event_loop_init(tc_event_loop_t *loop, int size) 18 | { 19 | tc_pool_t *pool; 20 | tc_event_actions_t *actions; 21 | 22 | pool = tc_create_pool(TC_DEFAULT_POOL_SIZE, 0); 23 | 24 | if (pool != NULL) { 25 | actions = &tc_event_actions; 26 | 27 | loop->actions = actions; 28 | loop->active_events = NULL; 29 | loop->pool = pool; 30 | loop->size = size; 31 | 32 | if (actions->create(loop) == TC_EVENT_ERROR) { 33 | return TC_EVENT_ERROR; 34 | } 35 | 36 | return TC_EVENT_OK; 37 | } else { 38 | return TC_EVENT_ERROR; 39 | } 40 | } 41 | 42 | 43 | int tc_event_loop_finish(tc_event_loop_t *loop) 44 | { 45 | tc_event_actions_t *actions; 46 | 47 | actions = loop->actions; 48 | 49 | if (actions != NULL) { 50 | /* destroy io module */ 51 | actions->destroy(loop); 52 | 53 | loop->actions = NULL; 54 | } 55 | 56 | if (loop->pool) { 57 | tc_destroy_pool(loop->pool); 58 | loop->pool = NULL; 59 | } 60 | 61 | return TC_EVENT_OK; 62 | } 63 | 64 | int tc_event_add(tc_event_loop_t *loop, tc_event_t *ev, int events) 65 | { 66 | tc_event_actions_t *actions; 67 | 68 | ev->loop = loop; 69 | actions = loop->actions; 70 | 71 | if (events == TC_EVENT_NONE) { 72 | return TC_EVENT_OK; 73 | } 74 | 75 | if (actions->add(loop, ev, events) == TC_EVENT_ERROR) { 76 | return TC_EVENT_ERROR; 77 | } 78 | 79 | if (events & TC_EVENT_READ) { 80 | ev->reg_evs |= TC_EVENT_READ; 81 | } 82 | 83 | if (events & TC_EVENT_WRITE) { 84 | ev->reg_evs |= TC_EVENT_WRITE; 85 | } 86 | 87 | return TC_EVENT_OK; 88 | } 89 | 90 | int tc_event_del(tc_event_loop_t *loop, tc_event_t *ev, int events) 91 | { 92 | tc_event_actions_t *actions; 93 | 94 | actions = loop->actions; 95 | 96 | if (events == TC_EVENT_NONE) { 97 | return TC_EVENT_OK; 98 | } 99 | 100 | if (actions->del(loop, ev, events) == TC_EVENT_ERROR) { 101 | return TC_EVENT_ERROR; 102 | } 103 | 104 | if (events & TC_EVENT_READ) { 105 | ev->reg_evs &= ~TC_EVENT_READ; 106 | } 107 | 108 | if (events & TC_EVENT_WRITE) { 109 | ev->reg_evs &= ~TC_EVENT_WRITE; 110 | } 111 | 112 | return TC_EVENT_OK; 113 | } 114 | 115 | 116 | int tc_event_proc_cycle(tc_event_loop_t *loop) 117 | { 118 | int ret; 119 | long timeout; 120 | tc_msec_t delta; 121 | tc_event_t *act_event, *act_next; 122 | tc_event_actions_t *actions; 123 | 124 | actions = loop->actions; 125 | 126 | for ( ;; ) { 127 | timeout = tc_event_find_timer(); 128 | if (timeout == 0 || timeout > 1000) { 129 | timeout = 500; 130 | } 131 | 132 | loop->active_events = NULL; 133 | 134 | delta = tc_current_time_msec; 135 | ret = actions->poll(loop, timeout); 136 | if (tc_over) { 137 | goto FINISH; 138 | } 139 | 140 | tc_time_update(); 141 | 142 | delta = tc_current_time_msec - delta; 143 | 144 | if (delta) { 145 | tc_event_expire_timers(); 146 | } 147 | 148 | if (ret == TC_EVENT_ERROR || ret == TC_EVENT_AGAIN) { 149 | continue; 150 | } 151 | 152 | for (act_event = loop->active_events; act_event; act_event = act_next) { 153 | act_next = act_event->next; 154 | 155 | if (act_event->events & TC_EVENT_READ) { 156 | if (act_event->read_handler(act_event) == TC_ERR_EXIT) { 157 | goto FINISH; 158 | } 159 | } 160 | 161 | if (act_event->events & TC_EVENT_WRITE) { 162 | if (act_event->write_handler(act_event) == TC_ERR_EXIT) { 163 | goto FINISH; 164 | } 165 | } 166 | 167 | if (act_event->reg_evs == TC_EVENT_NONE) { 168 | tc_event_destroy(act_event, 0); 169 | } 170 | } 171 | } 172 | 173 | FINISH: 174 | return TC_EVENT_OK; 175 | } 176 | 177 | 178 | tc_event_t *tc_event_create(tc_pool_t *pool, int fd, tc_event_handler_pt reader, 179 | tc_event_handler_pt writer) 180 | { 181 | tc_event_t *ev; 182 | 183 | ev = tc_palloc(pool, sizeof(tc_event_t)); 184 | 185 | if (ev != NULL) { 186 | ev->events = 0; 187 | ev->reg_evs = 0; 188 | ev->index = -1; 189 | ev->fd = fd; 190 | ev->next = NULL; 191 | ev->read_handler = reader; 192 | ev->write_handler = writer; 193 | } 194 | 195 | return ev; 196 | } 197 | 198 | static void tc_event_destroy_with_no_delay(tc_pool_t *pool, tc_event_t *ev) 199 | { 200 | tc_log_info(LOG_NOTICE, 0, "destroy event:%d", ev->fd); 201 | ev_mark[ev->fd] = NULL; 202 | ev->loop = NULL; 203 | ev->read_handler = NULL; 204 | ev->write_handler = NULL; 205 | tc_pfree(pool, ev); 206 | } 207 | 208 | void tc_event_destroy(tc_event_t *ev, int delayed) 209 | { 210 | tc_log_info(LOG_NOTICE, 0, "enter tc_event_destroy:%d", ev->fd); 211 | if (ev->fd <= 0 || ev->fd >= MAX_FD_NUM) { 212 | tc_log_info(LOG_ERR, 0, "fd is not valid"); 213 | return; 214 | } 215 | 216 | if (ev_mark[ev->fd] != NULL && ev != ev_mark[ev->fd]) { 217 | tc_log_info(LOG_NOTICE, 0, "destroy prev ev:%d", ev->fd); 218 | tc_event_destroy_with_no_delay(ev->loop->pool, ev_mark[ev->fd]); 219 | } 220 | 221 | if (delayed) { 222 | tc_log_info(LOG_NOTICE, 0, "delayed destroy ev:%d", ev->fd); 223 | ev_mark[ev->fd] = ev; 224 | } else { 225 | tc_event_destroy_with_no_delay(ev->loop->pool, ev); 226 | } 227 | } 228 | 229 | 230 | void finally_release_obsolete_events(void) 231 | { 232 | int i; 233 | 234 | for (i = 0; i < MAX_FD_NUM; i++) { 235 | if (ev_mark[i] != NULL) { 236 | tc_log_info(LOG_NOTICE, 0, "destroy prev ev:%d", ev_mark[i]->fd); 237 | tc_pfree(ev_mark[i]->loop->pool, ev_mark[i]); 238 | ev_mark[i] = NULL; 239 | } 240 | } 241 | } 242 | 243 | -------------------------------------------------------------------------------- /src/event/tc_event.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_EVENT_H 2 | #define TC_EVENT_H 3 | 4 | #include 5 | 6 | #define TC_EVENT_SELECT_OLD 0 7 | #define TC_EVENT_SELECT 1 8 | #define TC_EVENT_EPOLL 2 9 | 10 | #define TC_EVENT_OK 0 11 | #define TC_EVENT_ERROR -1 12 | #define TC_EVENT_AGAIN 1 13 | 14 | #define TC_EVENT_NONE 0 15 | #define TC_EVENT_READ 1 16 | #define TC_EVENT_WRITE 2 17 | 18 | #define tc_event_push_active_event(head, ev) \ 19 | ev->next = head; head = ev; 20 | 21 | typedef struct tc_event_loop_s tc_event_loop_t; 22 | typedef struct tc_event_s tc_event_t; 23 | typedef struct tc_event_timer_s tc_event_timer_t; 24 | 25 | typedef int (*ev_create_pt) (tc_event_loop_t *loop); 26 | typedef int (*ev_destroy_pt) (tc_event_loop_t *loop); 27 | typedef int (*ev_add_event_pt) (tc_event_loop_t *loop, tc_event_t *ev, 28 | int events); 29 | typedef int (*ev_delete_event_pt) (tc_event_loop_t *loop, tc_event_t *ev, 30 | int events); 31 | typedef int (*ev_event_poll_pt) (tc_event_loop_t *loop, long timeout); 32 | 33 | typedef int (*tc_event_handler_pt) (tc_event_t *ev); 34 | typedef void (*tc_event_timer_handler_pt) (tc_event_timer_t *evt); 35 | 36 | typedef struct { 37 | ev_create_pt create; 38 | ev_destroy_pt destroy; 39 | ev_add_event_pt add; 40 | ev_delete_event_pt del; 41 | ev_event_poll_pt poll; 42 | } tc_event_actions_t; 43 | 44 | struct tc_event_s { 45 | int fd; 46 | int events; 47 | int reg_evs; 48 | int index; 49 | tc_event_loop_t *loop; 50 | tc_event_handler_pt read_handler; 51 | tc_event_handler_pt write_handler; 52 | tc_event_t *next; 53 | }; 54 | 55 | typedef tc_rbtree_key_t tc_msec_t; 56 | typedef tc_rbtree_key_int_t tc_msec_int_t; 57 | typedef struct tm tc_tm_t; 58 | 59 | struct tc_event_timer_s { 60 | unsigned timer_set:1; 61 | void *data; 62 | tc_pool_t *pool; 63 | tc_rbtree_node_t timer; 64 | tc_event_timer_handler_pt handler; 65 | }; 66 | 67 | struct tc_event_loop_s { 68 | int size; 69 | void *io; 70 | tc_pool_t *pool; 71 | tc_event_t *active_events; 72 | tc_event_actions_t *actions; 73 | }; 74 | 75 | 76 | int tc_event_loop_init(tc_event_loop_t *loop, int size); 77 | int tc_event_loop_finish(tc_event_loop_t *loop); 78 | int tc_event_proc_cycle(tc_event_loop_t *loop); 79 | int tc_event_add(tc_event_loop_t *loop, tc_event_t *ev, int events); 80 | int tc_event_del(tc_event_loop_t *loop, tc_event_t *ev, int events); 81 | 82 | tc_event_t *tc_event_create(tc_pool_t *pool, int fd, tc_event_handler_pt reader, 83 | tc_event_handler_pt writer); 84 | void tc_event_destroy(tc_event_t *ev, int delayed); 85 | 86 | void finally_release_obsolete_events(void); 87 | 88 | extern tc_atomic_t tc_over; 89 | 90 | #endif /* TC_EVENT_H */ 91 | -------------------------------------------------------------------------------- /src/event/tc_event_timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | tc_rbtree_t tc_event_timer_rbtree; 5 | static tc_rbtree_node_t tc_event_timer_sentinel; 6 | 7 | /* 8 | * the event timer rbtree may contain the duplicate keys, however, 9 | * it should not be a problem, because we use the rbtree to find 10 | * a minimum timer value only 11 | */ 12 | 13 | tc_int_t 14 | tc_event_timer_init(void) 15 | { 16 | tc_rbtree_init(&tc_event_timer_rbtree, &tc_event_timer_sentinel, 17 | tc_rbtree_insert_timer_value); 18 | 19 | return TC_OK; 20 | } 21 | 22 | 23 | tc_msec_t 24 | tc_event_find_timer(void) 25 | { 26 | tc_msec_int_t timer; 27 | tc_rbtree_node_t *node, *root, *sentinel; 28 | 29 | if (tc_event_timer_rbtree.root == &tc_event_timer_sentinel) { 30 | return TC_TIMER_INFINITE; 31 | } 32 | 33 | root = tc_event_timer_rbtree.root; 34 | sentinel = tc_event_timer_rbtree.sentinel; 35 | 36 | node = tc_rbtree_min(root, sentinel); 37 | 38 | timer = (tc_msec_int_t) (node->key - tc_current_time_msec); 39 | 40 | return (tc_msec_t) (timer > 0 ? timer : 0); 41 | } 42 | 43 | 44 | void 45 | tc_event_expire_timers(void) 46 | { 47 | tc_event_timer_t *ev; 48 | tc_rbtree_node_t *node, *root, *sentinel; 49 | 50 | sentinel = tc_event_timer_rbtree.sentinel; 51 | 52 | for ( ;; ) { 53 | 54 | root = tc_event_timer_rbtree.root; 55 | 56 | if (root == sentinel) { 57 | return; 58 | } 59 | 60 | node = tc_rbtree_min(root, sentinel); 61 | 62 | /* node->key <= tc_current_time */ 63 | 64 | if ((tc_msec_int_t) (node->key - tc_current_time_msec) <= 0) { 65 | ev = (tc_event_timer_t *) ((char *) node - 66 | offsetof(tc_event_timer_t, timer)); 67 | 68 | #if (TC_DEBUG) 69 | tc_log_debug1(LOG_DEBUG, 0, "del timer:%llu", ev); 70 | #endif 71 | tc_rbtree_delete(&tc_event_timer_rbtree, &ev->timer); 72 | 73 | ev->timer_set = 0; 74 | 75 | ev->handler(ev); 76 | 77 | continue; 78 | } 79 | 80 | break; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/event/tc_event_timer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _TC_EVENT_TIMER_H_INCLUDED_ 3 | #define _TC_EVENT_TIMER_H_INCLUDED_ 4 | 5 | 6 | #include 7 | 8 | #define TC_TIMER_INFINITE (tc_msec_t) -1 9 | 10 | #define TC_TIMER_LAZY_DELAY 1 11 | 12 | 13 | tc_int_t tc_event_timer_init(void); 14 | tc_msec_t tc_event_find_timer(void); 15 | void tc_event_expire_timers(void); 16 | 17 | 18 | extern tc_rbtree_t tc_event_timer_rbtree; 19 | 20 | 21 | static inline void 22 | tc_event_del_timer(tc_event_timer_t *ev) 23 | { 24 | tc_log_debug2(LOG_DEBUG, 0, "pool:%llu, del timer:%llu", ev->pool, ev); 25 | tc_rbtree_delete(&tc_event_timer_rbtree, &ev->timer); 26 | ev->timer_set = 0; 27 | } 28 | 29 | static inline bool 30 | tc_event_update_timer(tc_event_timer_t *ev, tc_msec_t timer) 31 | { 32 | tc_msec_t key; 33 | tc_msec_int_t diff; 34 | 35 | if (ev != NULL) { 36 | key = ((tc_msec_t) tc_current_time_msec) + timer; 37 | 38 | if (ev->timer_set) { 39 | diff = (tc_msec_int_t) (key - ev->timer.key); 40 | if (tc_abs(diff) < TC_TIMER_LAZY_DELAY) { 41 | tc_log_debug0(LOG_DEBUG, 0, "two timers are too close"); 42 | return false; 43 | } 44 | 45 | if (diff > 0) { 46 | tc_log_debug0(LOG_DEBUG, 0, "future timer is suppressed"); 47 | return false; 48 | } 49 | tc_event_del_timer(ev); 50 | } 51 | 52 | ev->timer.key = key; 53 | 54 | tc_log_debug2(LOG_DEBUG, 0, "pool:%llu, up timer:%llu", ev->pool, ev); 55 | tc_rbtree_insert(&tc_event_timer_rbtree, &ev->timer); 56 | 57 | ev->timer_set = 1; 58 | 59 | return true; 60 | } else { 61 | tc_log_info(LOG_WARN, 0, "ev is null"); 62 | return false; 63 | } 64 | } 65 | 66 | static inline tc_event_timer_t* 67 | tc_event_add_timer(tc_pool_t *pool, tc_event_timer_t *ev, tc_msec_t timer, 68 | void *data, tc_event_timer_handler_pt handler) 69 | { 70 | tc_msec_t key; 71 | 72 | if (ev == NULL && pool != NULL) { 73 | ev = (tc_event_timer_t *) tc_palloc(pool, sizeof(tc_event_timer_t)); 74 | if (ev) { 75 | ev->pool = pool; 76 | } 77 | } 78 | 79 | if (ev != NULL) { 80 | ev->handler = handler; 81 | ev->data = data; 82 | key = ((tc_msec_t) tc_current_time_msec) + timer; 83 | ev->timer.key = key; 84 | 85 | tc_rbtree_insert(&tc_event_timer_rbtree, &ev->timer); 86 | 87 | ev->timer_set = 1; 88 | } 89 | 90 | return ev; 91 | } 92 | 93 | #endif /* _TC_EVENT_TIMER_H_INCLUDED_ */ 94 | -------------------------------------------------------------------------------- /src/event/tc_select_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int tc_select_create(tc_event_loop_t *loop) 4 | { 5 | tc_event_t **evs; 6 | tc_select_multiplex_io_t *io; 7 | 8 | evs = tc_palloc(loop->pool, loop->size * sizeof(tc_event_t *)); 9 | if (evs == NULL) { 10 | return TC_EVENT_ERROR; 11 | } 12 | 13 | io = tc_palloc(loop->pool, sizeof(tc_select_multiplex_io_t)); 14 | if (io == NULL) { 15 | return TC_EVENT_ERROR; 16 | } 17 | 18 | FD_ZERO(&io->r_set); 19 | FD_ZERO(&io->w_set); 20 | 21 | io->max_fd = -1; 22 | io->last = 0; 23 | io->evs = evs; 24 | 25 | loop->io = io; 26 | 27 | return TC_EVENT_OK; 28 | } 29 | 30 | int tc_select_destroy(tc_event_loop_t *loop) 31 | { 32 | int i; 33 | tc_event_t *event; 34 | tc_select_multiplex_io_t *io; 35 | 36 | io = loop->io; 37 | 38 | for (i = 0; i < io->last; i++) { 39 | event = io->evs[i]; 40 | if (event->fd > 0) { 41 | close(event->fd); 42 | } 43 | event->fd = -1; 44 | tc_pfree(loop->pool, event); 45 | } 46 | 47 | tc_pfree(loop->pool, io->evs); 48 | tc_pfree(loop->pool, loop->io); 49 | 50 | return TC_EVENT_OK; 51 | } 52 | 53 | int tc_select_add_event(tc_event_loop_t *loop, tc_event_t *ev, int events) 54 | { 55 | tc_select_multiplex_io_t *io; 56 | 57 | io = loop->io; 58 | 59 | if (io->last >= loop->size) { 60 | /* too many */ 61 | return TC_EVENT_ERROR; 62 | } 63 | 64 | if (events == TC_EVENT_READ && ev->read_handler 65 | && ev->write_handler == NULL) 66 | { 67 | FD_SET(ev->fd, &io->r_set); 68 | } else if (events == TC_EVENT_WRITE && ev->write_handler 69 | && ev->read_handler == NULL) 70 | { 71 | FD_SET(ev->fd, &io->w_set); 72 | } else { 73 | return TC_EVENT_ERROR; 74 | } 75 | 76 | if (io->max_fd != -1 && ev->fd > io->max_fd) { 77 | io->max_fd = ev->fd; 78 | } 79 | 80 | ev->index = io->last; 81 | io->evs[io->last++] = ev; 82 | 83 | return TC_EVENT_OK; 84 | } 85 | 86 | int tc_select_del_event(tc_event_loop_t *loop, tc_event_t *ev, int events) 87 | { 88 | tc_event_t *last_ev; 89 | tc_select_multiplex_io_t *io; 90 | 91 | io = loop->io; 92 | 93 | if (ev->index < 0 || ev->index >= io->last) { 94 | return TC_EVENT_ERROR; 95 | } 96 | 97 | if (events == TC_EVENT_READ) { 98 | FD_CLR(ev->fd, &io->r_set); 99 | } else if (events == TC_EVENT_WRITE) { 100 | FD_CLR(ev->fd, &io->w_set); 101 | } else { 102 | return TC_EVENT_ERROR; 103 | } 104 | 105 | if (ev->index < --(io->last)) { 106 | last_ev = io->evs[io->last]; 107 | io->evs[ev->index] = last_ev; 108 | last_ev->index = ev->index; 109 | } 110 | 111 | ev->index = -1; 112 | 113 | if (io->max_fd == ev->fd) { 114 | io->max_fd = -1; 115 | } 116 | 117 | return TC_EVENT_OK; 118 | } 119 | 120 | int tc_select_polling(tc_event_loop_t *loop, long to) 121 | { 122 | int i, ret; 123 | fd_set cur_read_set, cur_write_set; 124 | tc_event_t **evs; 125 | struct timeval timeout; 126 | tc_select_multiplex_io_t *io; 127 | 128 | io = loop->io; 129 | evs = io->evs; 130 | 131 | if (io->max_fd == -1) { 132 | for (i = 0; i < io->last; i++) { 133 | if (io->max_fd < evs[i]->fd) { 134 | io->max_fd = evs[i]->fd; 135 | } 136 | } 137 | } 138 | 139 | timeout.tv_sec = (long) (to / 1000); 140 | timeout.tv_usec = (long) ((to % 1000) * 1000); 141 | 142 | cur_read_set = io->r_set; 143 | cur_write_set = io->w_set; 144 | 145 | ret = select(io->max_fd + 1, &cur_read_set, &cur_write_set, NULL, 146 | &timeout); 147 | 148 | if (ret == -1) { 149 | return TC_EVENT_ERROR; 150 | } 151 | 152 | if (ret == 0) { 153 | return TC_EVENT_AGAIN; 154 | } 155 | 156 | for (i = 0; i < io->last; i++) { 157 | /* clear the active events, and reset */ 158 | evs[i]->events = TC_EVENT_NONE; 159 | 160 | if (evs[i]->read_handler) { 161 | if (FD_ISSET(evs[i]->fd, &cur_read_set)) { 162 | evs[i]->events |= TC_EVENT_READ; 163 | tc_event_push_active_event(loop->active_events, evs[i]); 164 | } 165 | } else { 166 | if (FD_ISSET(evs[i]->fd, &cur_write_set)) { 167 | evs[i]->events |= TC_EVENT_WRITE; 168 | tc_event_push_active_event(loop->active_events, evs[i]); 169 | } 170 | } 171 | } 172 | 173 | return TC_EVENT_OK; 174 | } 175 | -------------------------------------------------------------------------------- /src/event/tc_select_module.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_SELECT_MODULE_INCLUDED 2 | #define TC_SELECT_MODULE_INCLUDED 3 | 4 | #include 5 | 6 | typedef struct tc_select_multiplex_io_s tc_select_multiplex_io_t; 7 | 8 | struct tc_select_multiplex_io_s { 9 | int max_fd; 10 | int last; 11 | fd_set r_set; 12 | fd_set w_set; 13 | tc_event_t **evs; 14 | }; 15 | 16 | 17 | int tc_select_create(tc_event_loop_t *loop); 18 | int tc_select_destroy(tc_event_loop_t *loop); 19 | int tc_select_add_event(tc_event_loop_t *loop, tc_event_t *ev, int events); 20 | int tc_select_del_event(tc_event_loop_t *loop, tc_event_t *ev, int events); 21 | int tc_select_polling(tc_event_loop_t *loop, long timeout); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/util/tc_util.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | 5 | unsigned short 6 | csum(unsigned short *packet, int pack_len) 7 | { 8 | register unsigned long sum = 0; 9 | 10 | while (pack_len > 1) { 11 | sum += *(packet++); 12 | pack_len -= 2; 13 | } 14 | if (pack_len > 0) { 15 | sum += *(unsigned char *) packet; 16 | } 17 | while (sum >> 16) { 18 | sum = (sum & 0xffff) + (sum >> 16); 19 | } 20 | 21 | return (unsigned short) ~sum; 22 | } 23 | 24 | 25 | static unsigned short buf[32768]; 26 | 27 | unsigned short 28 | tcpcsum(unsigned char *iphdr, unsigned short *packet, int pack_len) 29 | { 30 | unsigned short res; 31 | 32 | memcpy(buf, iphdr + 12, 8); 33 | *(buf + 4) = htons((unsigned short) (*(iphdr + 9))); 34 | *(buf + 5) = htons((unsigned short) pack_len); 35 | memcpy(buf + 6, packet, pack_len); 36 | res = csum(buf, pack_len + 12); 37 | 38 | return res; 39 | } 40 | 41 | int 42 | get_l2_len(const unsigned char *frame, const int datalink) 43 | { 44 | struct ethernet_hdr *eth_hdr; 45 | 46 | switch (datalink) { 47 | case DLT_LINUX_SLL: 48 | return SLL_HDR_LEN; 49 | break; 50 | case DLT_RAW: 51 | return 0; 52 | break; 53 | case DLT_EN10MB: 54 | eth_hdr = (struct ethernet_hdr *) frame; 55 | switch (ntohs(eth_hdr->ether_type)) { 56 | case ETHERTYPE_VLAN: 57 | return 18; 58 | break; 59 | default: 60 | return 14; 61 | break; 62 | } 63 | break; 64 | case DLT_C_HDLC: 65 | return CISCO_HDLC_LEN; 66 | break; 67 | default: 68 | tc_log_info(LOG_ERR, 0, "unsupported DLT type: %s (0x%x)", 69 | pcap_datalink_val_to_description(datalink), datalink); 70 | break; 71 | } 72 | 73 | return -1; 74 | } 75 | 76 | #ifdef FORCE_ALIGN 77 | static unsigned char pcap_ip_buf[65536]; 78 | #endif 79 | 80 | unsigned char * 81 | get_ip_data(pcap_t *pcap, unsigned char *frame, const int pkt_len, 82 | int *p_l2_len) 83 | { 84 | int l2_len; 85 | u_char *ptr; 86 | 87 | l2_len = get_l2_len(frame, pcap_datalink(pcap)); 88 | *p_l2_len = l2_len; 89 | 90 | if (pkt_len <= l2_len) { 91 | return NULL; 92 | } 93 | #ifdef FORCE_ALIGN 94 | if (l2_len % 4 == 0) { 95 | ptr = (&(frame)[l2_len]); 96 | } else { 97 | ptr = pcap_ip_buf; 98 | memcpy(ptr, (&(frame)[l2_len]), pkt_len - l2_len); 99 | } 100 | #else 101 | ptr = (&(frame)[l2_len]); 102 | #endif 103 | 104 | return ptr; 105 | 106 | } 107 | 108 | -------------------------------------------------------------------------------- /src/util/tc_util.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_UTIL_INCLUDED 2 | #define TC_UTIL_INCLUDED 3 | 4 | #include 5 | 6 | 7 | #define TCP_HDR_LEN(tcph) (tcph->doff << 2) 8 | #define IP_HDR_LEN(iph) (iph->ihl << 2) 9 | #define EXTRACT_32BITS(p) ((uint32_t)ntohl(*(uint32_t *)(p))) 10 | 11 | #define TCP_PAYLOAD_LENGTH(iph, tcph) \ 12 | (ntohs(iph->tot_len) - IP_HDR_LEN(iph) - TCP_HDR_LEN(tcph)) 13 | 14 | unsigned short csum (unsigned short *packet, int pack_len); 15 | unsigned short tcpcsum(unsigned char *iphdr, unsigned short *packet, 16 | int pack_len); 17 | 18 | int get_l2_len(const unsigned char *frame, const int datalink); 19 | unsigned char * 20 | get_ip_data(pcap_t *pcap, unsigned char *frame, const int pkt_len, 21 | int *p_l2_len); 22 | 23 | #endif /* ----- #ifndef TC_UTIL_INCLUDED ----- */ 24 | 25 | --------------------------------------------------------------------------------