├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── LICENSE ├── NEWS ├── README ├── README.md ├── auto ├── cc │ ├── acc │ ├── clang │ ├── conf │ ├── gcc │ ├── icc │ └── name ├── define ├── feature ├── have ├── have_headers ├── headers ├── include ├── init ├── install ├── linux ├── make ├── modules ├── nohave ├── options ├── os │ ├── conf │ └── linux ├── sources ├── summary └── types │ ├── sizeof │ ├── typedef │ ├── uintptr_t │ └── value ├── conf └── plugin.conf ├── configure ├── doc ├── Architecture.md ├── Beginners.md ├── Pre-Warming.md └── Usage.md ├── images ├── example1.png ├── example2.png ├── first.png ├── pre-warming1.png ├── pre-warming2.png ├── second.png ├── tcp_state_machine.png └── tcpcopy.png └── src ├── communication ├── tc_msg.h ├── tc_socket.c └── tc_socket.h ├── core ├── tc_alloc.c ├── tc_alloc.h ├── tc_array.c ├── tc_array.h ├── tc_conf_file.c ├── tc_conf_file.h ├── tc_config.h ├── tc_daemon.c ├── tc_hash.c ├── tc_hash.h ├── 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 ├── digest ├── tc_evp.c └── tc_evp.h ├── event ├── tc_epoll_module.c ├── tc_epoll_module.h ├── tc_event.c ├── tc_event.h ├── tc_event_timer.c ├── tc_event_timer.h ├── tc_select_module.c └── tc_select_module.h ├── tcpcopy ├── 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_session.c ├── tc_session.h ├── tc_udp_session.c ├── tc_udp_session.h └── tcpcopy.h └── util ├── tc_util.c └── tc_util.h /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | cscope.* 3 | tags 4 | objs/* 5 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Bin Wang 2 | Bo Wang 3 | Yingying Jiang 4 | Xiaowei Wu (yixiao.wxw [at] taobao [dot] com) 5 | Joshua Zhu (shudu [at] taobao [dot] com) 6 | 7 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2014 NetEase, Inc. 3 | * Copyright (C) 2012-2014 Alibaba Group Holding Limited 4 | * Copyright (C) 2011-2014 ChangYou.com Limited 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | * SUCH DAMAGE. 26 | */ 27 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2014.09 v1.0 TCPCopy 1.0 series released 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2014 NetEase, Inc. 3 | * Copyright (C) 2012-2014 Alibaba Group Holding Limited 4 | * Copyright (C) 2011-2014 ChangYou.com Limited 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | * SUCH DAMAGE. 26 | */ 27 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin579/tcpcopy/21a3698adba8c350dde4d164174df9d9254ceaea/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | #[TCPCopy](https://github.com/session-replay-tools/tcpcopy) - A TCP Stream Replay Tool 2 | 3 | TCPCopy is a TCP stream replay tool to support real testing of Internet server applications. 4 | 5 | 6 | ##Description 7 | Although the real live flow is important for the test of Internet server applications, it is hard to simulate it as online environments are too complex. To support more realistic testing of Internet server applications, we propose a live flow reproduction tool – TCPCopy, which could generate the test workload that is similar to the production workload. Currently, TCPCopy has been widely used by companies in China. 8 | 9 | TCPCopy has little influence on the production system except occupying additional CPU, memory and bandwidth. Moreover, the reproduced workload is similar to the production workload in request diversity, network latency and resource occupation. 10 | 11 | 12 | ##Scenarios 13 | * Distributed stress testing 14 | - Use to copy real-world data to stress test your server software. Bugs that only can be produced in high-stress situations can be found 15 | * Live testing 16 | - Prove the new system is stable and find bugs that only occur in the real world 17 | * Regression testing 18 | * Performance comparison 19 | 20 | 21 | ##Architecture 22 | 23 | ![tcpcopy](https://raw.github.com/wangbin579/auxiliary/master/images/tcpcopy.GIF) 24 | 25 | As shown in Figure 1, TCPCopy consists of two parts: *tcpcopy* and *intercept*. While *tcpcopy* runs on the online server and captures the online requests, *intercept* runs on the assistant server and does some assistant work, such as passing response info to *tcpcopy*. 26 | 27 | *tcpcopy* utilizes raw socket input technique by default to capture the online packets at the network layer and does the necessary processing (including TCP interaction simulation, network latency control, and common upper-layer interaction simulation), and uses raw socket output technique by default to send packets to the target server(pink arrows). 28 | 29 | The only operation needed on the target server for TCPCopy is setting appropriate route commands to route response packets(green arrows) to the assistant server. 30 | 31 | *intercept* is responsible for passing the response header(by default) to *tcpcopy*. By capturing the reponse packets, *intercept* will extract response header information and send the response header to *tcpcopy* using a special channel(purple arrows). When *tcpcopy* receives the response header, it utilizes the header information to modify the attributes of online packets and continues to send another packet. It should be noticed that the responses from the target server are routed to the assistant server which should act as a black hole. 32 | 33 | 34 | ##Quick start 35 | 36 | Two quick start options are available for *intercept*: 37 | 38 | * [Download the latest intercept release](https://github.com/session-replay-tools/intercept/releases). 39 | * Clone the repo: `git clone git://github.com/session-replay-tools/intercept.git`. 40 | 41 | Two quick start options are available for *tcpcopy*: 42 | 43 | * [Download the latest tcpcopy release](https://github.com/session-replay-tools/tcpcopy/releases). 44 | * Clone the repo: `git clone git://github.com/session-replay-tools/tcpcopy.git`. 45 | 46 | 47 | ##Getting intercept installed on the assistant server 48 | 1. cd intercept 49 | 2. ./configure 50 | - choose appropriate configure options if needed 51 | 3. make 52 | 4. make install 53 | 54 | 55 | ###Configure Options for intercept 56 | --single run intercept at non-distributed mode 57 | --with-debug compile intercept with debug support (saved in a log file) 58 | 59 | 60 | ##Getting tcpcopy installed on the online server 61 | 1. cd tcpcopy 62 | 2. ./configure 63 | - choose appropriate configure options if needed 64 | 3. make 65 | 4. make install 66 | 67 | 68 | ###Configure Options for tcpcopy 69 | --offline replay TCP streams from the pcap file 70 | --pcap-capture capture packets at the data link 71 | --pcap-send send packets at the data link layer instead of the IP layer 72 | --set-protocol-module=PATH set tcpcopy to work for an external protocol module 73 | --single if intercept is configured with "--single" option, 74 | so does tcpcopy 75 | --with-debug compile tcpcopy with debug support (saved in a log file) 76 | 77 | 78 | 79 | ##Running TCPCopy 80 | Assume *tcpcopy* with "./configure" is configured and *intercept* with "configure" is configured. 81 | 82 | ###1) On the target server which runs server applications: 83 | Set route commands appropriately to route response packets to the assistant server 84 | 85 | For example: 86 | 87 | Assume 61.135.233.161 is the IP address of the assistant server. We set the 88 | following route command to route all responses to the 62.135.200.x's clients 89 | to the assistant server. 90 | 91 | route add -net 62.135.200.0 netmask 255.255.255.0 gw 65.135.233.161 92 | 93 | ###2) On the assistant server which runs intercept(root privilege is required): 94 | 95 | ./intercept -F -i 96 | 97 | Note that the filter format is the same as the pcap filter. 98 | For example: 99 | 100 | ./intercept -i eth0 -F 'tcp and src port 8080' -d 101 | 102 | intercept will capture response packets of the TCP based application which listens 103 | on port 8080 from device eth0 104 | 105 | 106 | ###3) On the online source server (root privilege is required): 107 | 108 | ./tcpcopy -x localServerPort-targetServerIP:targetServerPort -s 109 | [-c ] 110 | 111 | For example(assume 61.135.233.160 is the IP address of the target server): 112 | 113 | ./tcpcopy -x 80-61.135.233.160:8080 -s 61.135.233.161 -c 62.135.200.x 114 | 115 | tcpcopy would capture port '80' packets on current server, change client IP address 116 | to one of 62.135.200.x series, send these packets to the target port '8080' of the 117 | target server '61.135.233.160', and connect 61.135.233.161 for asking intercept to 118 | pass response packets to it. 119 | 120 | Although "-c" parameter is optional, it is set here in order to simplifying route 121 | commands. 122 | 123 | ##Note 124 | 1. It is tested on Linux only (kernal 2.6 or above) 125 | 2. TCPCopy may lose packets hence lose requests 126 | 3. Root privilege is required 127 | 4. TCPCopy does only support client-initiated connections now 128 | 5. TCPCopy does not support replay for server applications which use SSL/TLS 129 | 6. Please execute "./tcpcopy -h" or "./intercept -h" for more details. 130 | 131 | ##Influential Factors 132 | There are several factors that could influence TCPCopy, which will be introduced in detail in the following sections. 133 | 134 | ###1. Capture Interface 135 | *tcpcopy* utilizes raw socket input interface by default to capture packets at the network layer on the online server. The system kernel may lose some packets when the system is busy. 136 | 137 | If you configure *tcpcopy* with "--pcap-capture", then *tcpcopy* could capture packets at the data link layer and could also filter packets in the kernel. With PF_RING, *tcpcopy* would lose less packets when pcap capturing. 138 | 139 | Maybe the best way to capturing requests is using switch to mirror ingress packets to divide the huge traffic to several machines. 140 | 141 | ###2. Sending Interface 142 | *tcpcopy* utilizes raw socket output interface by default to send packets at the network layer to a target server. 143 | If you want to avoid ip_conntrack problems or get better performance, configure *tcpcopy* with "--pcap-send", then with appropriate parameters *tcpcopy* could send packets at the data link layer to a target server. 144 | 145 | ###3.On the Way to the Target Server 146 | When a packet is sent by *tcpcopy*, it may encounter many challenges before reaching the target server. As the source IP address in the packet is still the end-user’s IP address(by default) other than the online server’s, some security devices may take it for an invalid or forged packet and drop it. In this case, when you use tcpdump to capture packets on the target server, no packets from the expected end-users will be captured. To know whether you are under such circumstances, you can choose a target server in the same network segment to do a test. If packets could be sent to the target server successfully in the same network segment but unsuccessfully across network segments, your packets may be dropped halfway. 147 | 148 | To solve this problem, we suggest deploying *tcpcopy*, *target applications* and *intercept* on servers in the same network segment. There’s also another solution with the help of a proxy in the same network segment. *tcpcopy* could send packets to the proxy and then the proxy would send the corresponding requests to the target server in another network segment. 149 | 150 | Note that deploying the target server's application on one virtual machine in the same segment may face the above problems. 151 | 152 | ####4. OS of the Target Server 153 | The target server may set rpfilter, which would check whether the source IP address in the packet is forged. If yes, the packet will be dropped at the network layer. 154 | 155 | If the target server could not receive any requests although packets can be captured by tcpdump on the target server, you should check if you have any corresponding rpfilter settings. If set, you have to remove the related settings to let the packets pass through the network layer. 156 | 157 | There are also other reasons that cause *tcpcopy* not working, such as iptables setting problems. 158 | 159 | ###5. Applications on the Target Server 160 | It is likely that the application on the target server could not process all the requests in time. On the one hand, bugs in the application may make the request not be responded for a long time. On the other hand, some protocols above TCP layer may only process the first request in the socket buffer and leave the remaining requests in the socket buffer unprocessed. 161 | 162 | ###6. OS of the assistant Server 163 | You should not set ip_forward true or the assistant server can't act as a black hole. 164 | 165 | ##Release History 166 | + 2014.09 v1.0 TCPCopy released 167 | 168 | 169 | ##Bugs and feature requests 170 | Have a bug or a feature request? [Please open a new issue](https://github.com/session-replay-tools/tcpcopy/issues). Before opening any issue, please search for existing issues. 171 | 172 | 173 | ## Copyright and license 174 | 175 | Copyright 2014 under [the BSD license](LICENSE). 176 | 177 | 178 | -------------------------------------------------------------------------------- /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 | if [ $TC_PCAP_NEEDED = YES ]; then 9 | tc_include="pcap.h"; . auto/include 10 | fi 11 | -------------------------------------------------------------------------------- /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 | TC_MODULES_C=$TC_OBJS/tc_modules.c 7 | 8 | TC_AUTO_HEADERS_H=$TC_OBJS/tc_auto_headers.h 9 | TC_AUTO_CONFIG_H=$TC_OBJS/tc_auto_config.h 10 | 11 | TC_AUTOTEST=$TC_OBJS/autotest 12 | TC_AUTOCONF_ERR=$TC_OBJS/autoconf.err 13 | 14 | TC_ERR=$TC_OBJS/autoconf.err 15 | MAKEFILE=$TC_OBJS/Makefile 16 | 17 | 18 | TC_PCH= 19 | TC_USE_PCH= 20 | 21 | if echo "test\c" | grep c >/dev/null; then 22 | 23 | if echo -n test | grep n >/dev/null; then 24 | tc_n= 25 | tc_c= 26 | 27 | else 28 | tc_n=-n 29 | tc_c= 30 | fi 31 | 32 | else 33 | tc_n= 34 | tc_c='\c' 35 | fi 36 | 37 | 38 | # create Makefile 39 | 40 | cat << END > Makefile 41 | 42 | default: build 43 | 44 | clean: 45 | rm -rf Makefile $TC_OBJS 46 | END 47 | -------------------------------------------------------------------------------- /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/tcpcopy 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}tcpcopy 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/tcpcopy '\$(DESTDIR)$TC_SBIN_PATH' 61 | 62 | test -d '\$(DESTDIR)$TC_CONF_PREFIX' \ 63 | || mkdir -p '\$(DESTDIR)$TC_CONF_PREFIX' 64 | 65 | test -f '\$(DESTDIR)$TC_CONF_PATH' \ 66 | || cp conf/plugin.conf '\$(DESTDIR)$TC_CONF_PATH' 67 | cp conf/plugin.conf '\$(DESTDIR)$TC_CONF_PREFIX/plugin.conf.default' 68 | 69 | test -d '\$(DESTDIR)`dirname "$TC_PID_PATH"`' \ 70 | || mkdir -p '\$(DESTDIR)`dirname "$TC_PID_PATH"`' 71 | 72 | END 73 | 74 | 75 | if test -n "$TC_ERROR_LOG_PATH"; then 76 | cat << END >> $TC_MAKEFILE 77 | 78 | test -d '\$(DESTDIR)`dirname "$TC_ERROR_LOG_PATH"`' || \ 79 | mkdir -p '\$(DESTDIR)`dirname "$TC_ERROR_LOG_PATH"`' 80 | END 81 | 82 | fi 83 | 84 | 85 | # create Makefile 86 | 87 | cat << END >> Makefile 88 | 89 | build: 90 | \$(MAKE) -f $TC_MAKEFILE 91 | 92 | install: 93 | \$(MAKE) -f $TC_MAKEFILE install 94 | END 95 | 96 | -------------------------------------------------------------------------------- /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="sigaction()" 135 | tc_feature_name="TC_SIGACTION" 136 | tc_feature_run=no 137 | tc_feature_incs="#include " 138 | tc_feature_path= 139 | tc_feature_libs= 140 | tc_feature_test="struct sigaction sa; int n; sa.sa_handler=SIG_IGN; 141 | sa.sa_flags=0; n = sigemptyset(&sa.sa_mask); 142 | if (n == -1) return 1" 143 | . auto/feature 144 | 145 | 146 | tc_feature="posix_memalign()" 147 | tc_feature_name="TC_HAVE_POSIX_MEMALIGN" 148 | tc_feature_run=no 149 | tc_feature_incs="#include " 150 | tc_feature_path= 151 | tc_feature_libs= 152 | tc_feature_test="void *p; int n; n = posix_memalign(&p, 4096, 4096); 153 | if (n != 0) return 1" 154 | . auto/feature 155 | 156 | 157 | tc_feature="memalign()" 158 | tc_feature_name="TC_HAVE_MEMALIGN" 159 | tc_feature_run=no 160 | tc_feature_incs="#include 161 | #include " 162 | tc_feature_path= 163 | tc_feature_libs= 164 | tc_feature_test="void *p; p = memalign(4096, 4096); 165 | if (p == NULL) return 1" 166 | . auto/feature 167 | 168 | 169 | tc_feature="mmap(MAP_ANON|MAP_SHARED)" 170 | tc_feature_name="TC_HAVE_MAP_ANON" 171 | tc_feature_run=yes 172 | tc_feature_incs="#include " 173 | tc_feature_path= 174 | tc_feature_libs= 175 | tc_feature_test="void *p; 176 | p = mmap(NULL, 4096, PROT_READ|PROT_WRITE, 177 | MAP_ANON|MAP_SHARED, -1, 0); 178 | if (p == MAP_FAILED) return 1;" 179 | . auto/feature 180 | 181 | 182 | tc_feature='mmap("/dev/zero", MAP_SHARED)' 183 | tc_feature_name="TC_HAVE_MAP_DEVZERO" 184 | tc_feature_run=yes 185 | tc_feature_incs="#include 186 | #include 187 | #include " 188 | tc_feature_path= 189 | tc_feature_libs= 190 | tc_feature_test='void *p; int fd; 191 | fd = open("/dev/zero", O_RDWR); 192 | p = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 193 | if (p == MAP_FAILED) return 1;' 194 | . auto/feature 195 | 196 | 197 | tc_feature="openat(), fstatat()" 198 | tc_feature_name="TC_HAVE_OPENAT" 199 | tc_feature_run=no 200 | tc_feature_incs="#include 201 | #include 202 | #include " 203 | tc_feature_path= 204 | tc_feature_libs= 205 | tc_feature_test="struct stat sb; 206 | openat(AT_FDCWD, \".\", O_RDONLY|O_NOFOLLOW); 207 | fstatat(AT_FDCWD, \".\", &sb, AT_SYMLINK_NOFOLLOW);" 208 | . auto/feature 209 | 210 | 211 | tc_feature="getaddrinfo()" 212 | tc_feature_name="TC_HAVE_GETADDRINFO" 213 | tc_feature_run=no 214 | tc_feature_incs="#include 215 | #include 216 | #include " 217 | tc_feature_path= 218 | tc_feature_libs= 219 | tc_feature_test='struct addrinfo *res; 220 | if (getaddrinfo("localhost", NULL, NULL, &res) != 0) return 1; 221 | freeaddrinfo(res)' 222 | . auto/feature 223 | 224 | 225 | if [ $TC_EPOLL = YES ]; then 226 | # epoll, EPOLLET version 227 | tc_feature="epoll" 228 | tc_feature_name="TC_HAVE_EPOLL" 229 | tc_feature_run=yes 230 | tc_feature_incs="#include " 231 | tc_feature_path= 232 | tc_feature_libs= 233 | tc_feature_test="int efd = 0; 234 | struct epoll_event ee; 235 | ee.events = EPOLLIN|EPOLLOUT|EPOLLET; 236 | ee.data.ptr = NULL; 237 | efd = epoll_create(100); 238 | if (efd == -1) return 1;" 239 | . auto/feature 240 | 241 | if [ $tc_found = yes ]; then 242 | EVENT_DEPS="$EVENT_DEPS $EPOLL_DEPS" 243 | EVENT_SRCS="$EVENT_SRCS $EPOLL_SRCS" 244 | else 245 | EVENT_DEPS="$EVENT_DEPS $SELECT_DEPS" 246 | EVENT_SRCS="$EVENT_SRCS $SELECT_SRCS" 247 | fi 248 | 249 | else 250 | EVENT_DEPS="$EVENT_DEPS $SELECT_DEPS" 251 | EVENT_SRCS="$EVENT_SRCS $SELECT_SRCS" 252 | fi 253 | 254 | 255 | if [ $TC_PCAP_NEEDED = YES ]; then 256 | tc_feature="pcap_create()" 257 | tc_feature_name="HAVE_PCAP_CREATE" 258 | tc_feature_run=yes 259 | tc_feature_incs="#include " 260 | tc_feature_path= 261 | tc_feature_libs='-lpcap' 262 | tc_feature_test='char ebuf[PCAP_ERRBUF_SIZE]; 263 | if (pcap_create("lo", ebuf) == NULL) return 1;' 264 | . auto/feature 265 | 266 | if [ $tc_found = no ]; then 267 | echo "only pcap 1.0.0 or higher is supported" 268 | exit 1 269 | fi 270 | fi 271 | 272 | 273 | if [ $TC_PCAP_NEEDED = YES ]; then 274 | tc_feature="pcap_set_immediate_mode()" 275 | tc_feature_name="HAVE_SET_IMMEDIATE_MODE" 276 | tc_feature_run=yes 277 | tc_feature_incs="#include " 278 | tc_feature_path= 279 | tc_feature_libs='-lpcap' 280 | tc_feature_test='char ebuf[PCAP_ERRBUF_SIZE]; 281 | if (pcap_set_immediate_mode(pcap_create("lo", ebuf), 1) != 0) 282 | return 1;' 283 | . auto/feature 284 | fi 285 | 286 | -------------------------------------------------------------------------------- /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/digest\ 9 | $TC_OBJS/src/communication\ 10 | $TC_OBJS/src/tcpcopy 11 | 12 | tc_objs_dir=$TC_OBJS$tc_regex_dirsep 13 | 14 | 15 | cat << END > $TC_MAKEFILE 16 | 17 | CC = $CC 18 | CFLAGS = $CFLAGS 19 | CPP = $CPP 20 | LINK = $LINK 21 | 22 | END 23 | 24 | 25 | tc_incs=`echo $CORE_INCS $DIGEST_INCS $EVENT_INCS $COMMUNICATION_INCS $UTIL_INCS\ 26 | $TCPCOPY_INCS $TC_OBJS\ 27 | | sed -e "s/ *\([^ ][^ ]*\)/$tc_regex_cont$tc_include_opt\1/g" \ 28 | -e "s/\//$tc_regex_dirsep/g"` 29 | 30 | cat << END >> $TC_MAKEFILE 31 | 32 | ALL_INCS = $tc_include_opt$tc_incs 33 | 34 | END 35 | 36 | 37 | # the core dependences and include paths 38 | 39 | tc_deps=`echo $CORE_DEPS $DIGEST_DEPS $EVENT_DEPS $COMMUNICATION_DEPS $UTIL_DEPS\ 40 | $TCPCOPY_DEPS $TC_AUTO_CONFIG_H $TC_PCH \ 41 | | sed -e "s/ *\([^ ][^ ]*\)/$tc_regex_cont\1/g" \ 42 | -e "s/\//$tc_regex_dirsep/g"` 43 | 44 | tc_incs=`echo $CORE_INCS $DIGEST_INCS $EVENT_INCS $COMMUNICATION_INCS $UTIL_INCS\ 45 | $TCPCOPY_INCS $TC_OBJS\ 46 | | sed -e "s/ *\([^ ][^ ]*\)/$tc_regex_cont$tc_include_opt\1/g" \ 47 | -e "s/\//$tc_regex_dirsep/g"` 48 | 49 | cat << END >> $TC_MAKEFILE 50 | 51 | 52 | CORE_DEPS = $tc_deps 53 | 54 | 55 | CORE_INCS = $tc_include_opt$tc_incs 56 | 57 | END 58 | 59 | tc_common_srcs="$CORE_SRCS $DIGEST_SRCS $EVENT_SRCS $COMMUNICATION_SRCS $UTIL_SRCS" 60 | tc_client_srcs="$tc_common_srcs $TCPCOPY_SRCS" 61 | 62 | tc_client_with_no_plugin="$tc_client_srcs" 63 | 64 | if test -n "$TC_ADDON_SRCS"; then 65 | 66 | cat << END >> $TC_MAKEFILE 67 | 68 | ADDON_DEPS = \$(CORE_DEPS) $TC_ADDON_DEPS 69 | 70 | END 71 | 72 | fi 73 | 74 | 75 | # tcpcopy 76 | 77 | tc_client_srcs=`echo $tc_client_srcs | sed -e "s/\//$tc_regex_dirsep/g"` 78 | 79 | for tc_src in $TC_ADDON_SRCS 80 | do 81 | tc_obj="addon/`basename \`dirname $tc_src\``" 82 | 83 | test -d $TC_OBJS/$tc_obj || mkdir -p $TC_OBJS/$tc_obj 84 | 85 | tc_obj=`echo $tc_obj/\`basename $tc_src\` \ 86 | | sed -e "s/\//$tc_regex_dirsep/g"` 87 | 88 | tc_client_srcs="$tc_client_srcs $tc_obj" 89 | done 90 | 91 | tc_all_objs=`echo $tc_client_srcs \ 92 | | sed -e "s#\([^ ]*\.\)cpp#$TC_OBJS\/\1$tc_objext#g" \ 93 | -e "s#\([^ ]*\.\)cc#$TC_OBJS\/\1$tc_objext#g" \ 94 | -e "s#\([^ ]*\.\)c#$TC_OBJS\/\1$tc_objext#g" \ 95 | -e "s#\([^ ]*\.\)S#$TC_OBJS\/\1$tc_objext#g"` 96 | 97 | tc_modules_c=`echo $TC_MODULES_C | sed -e "s/\//$tc_regex_dirsep/g"` 98 | 99 | tc_modules_obj=`echo $tc_modules_c | sed -e "s/\(.*\.\)c/\1$tc_objext/"` 100 | 101 | 102 | if test -n "$TC_RES"; then 103 | tc_res=$TC_RES 104 | else 105 | tc_res="$TC_RC $TC_ICONS" 106 | tc_rcc=`echo $TC_RCC | sed -e "s/\//$tc_regex_dirsep/g"` 107 | fi 108 | 109 | tc_deps=`echo $tc_all_objs $tc_modules_obj $tc_res $LINK_DEPS \ 110 | | sed -e "s/ *\([^ ][^ ]*\)/$tc_regex_cont\1/g" \ 111 | -e "s/\//$tc_regex_dirsep/g"` 112 | 113 | tc_objs=`echo $tc_all_objs $tc_modules_obj \ 114 | | sed -e "s/ *\([^ ][^ ]*\)/$tc_long_regex_cont\1/g" \ 115 | -e "s/\//$tc_regex_dirsep/g"` 116 | 117 | if test -n "$TC_LD_OPT$CORE_LIBS"; then 118 | tc_libs=`echo $TC_LD_OPT $CORE_LIBS \ 119 | | sed -e "s/\//$tc_regex_dirsep/g" -e "s/^/$tc_long_regex_cont/"` 120 | fi 121 | 122 | tc_link=${CORE_LINK:+`echo $CORE_LINK \ 123 | | sed -e "s/\//$tc_regex_dirsep/g" -e "s/^/$tc_long_regex_cont/"`} 124 | 125 | 126 | cat << END >> $TC_MAKEFILE 127 | 128 | $TC_OBJS${tc_dirsep}tcpcopy: $tc_deps$tc_spacer 129 | \$(LINK) ${tc_long_start}${tc_binout}$TC_OBJS${tc_dirsep}tcpcopy$tc_long_cont$tc_objs$tc_libs$tc_link 130 | $tc_rcc 131 | ${tc_long_end} 132 | END 133 | 134 | # tc_modules.c 135 | 136 | tc_cc="\$(CC) $tc_compile_opt \$(CFLAGS) \$(CORE_INCS)" 137 | 138 | cat << END >> $TC_MAKEFILE 139 | 140 | $tc_modules_obj: \$(CORE_DEPS)$tc_cont$tc_modules_c 141 | $tc_cc$tc_tab$tc_objout$tc_modules_obj$tc_tab$tc_modules_c$TC_AUX 142 | 143 | END 144 | 145 | 146 | # the sources with no plugin 147 | 148 | for tc_src in $tc_client_with_no_plugin 149 | do 150 | tc_src=`echo $tc_src | sed -e "s/\//$tc_regex_dirsep/g"` 151 | tc_obj=`echo $tc_src \ 152 | | sed -e "s#^\(.*\.\)cpp\\$#$tc_objs_dir\1$tc_objext#g" \ 153 | -e "s#^\(.*\.\)cc\\$#$tc_objs_dir\1$tc_objext#g" \ 154 | -e "s#^\(.*\.\)c\\$#$tc_objs_dir\1$tc_objext#g" \ 155 | -e "s#^\(.*\.\)S\\$#$tc_objs_dir\1$tc_objext#g"` 156 | 157 | cat << END >> $TC_MAKEFILE 158 | 159 | $tc_obj: \$(CORE_DEPS)$tc_cont$tc_src 160 | $tc_cc$tc_tab$tc_objout$tc_obj$tc_tab$tc_src$TC_AUX 161 | 162 | END 163 | 164 | done 165 | 166 | 167 | # the addons sources 168 | 169 | if test -n "$TC_ADDON_SRCS"; then 170 | 171 | tc_cc="\$(CC) $tc_compile_opt \$(CFLAGS) $tc_use_pch \$(ALL_INCS)" 172 | 173 | for tc_src in $TC_ADDON_SRCS 174 | do 175 | tc_obj="addon/`basename \`dirname $tc_src\``" 176 | 177 | tc_obj=`echo $tc_obj/\`basename $tc_src\` \ 178 | | sed -e "s/\//$tc_regex_dirsep/g"` 179 | 180 | tc_obj=`echo $tc_obj \ 181 | | sed -e "s#^\(.*\.\)cpp\\$#$tc_objs_dir\1$tc_objext#g" \ 182 | -e "s#^\(.*\.\)cc\\$#$tc_objs_dir\1$tc_objext#g" \ 183 | -e "s#^\(.*\.\)c\\$#$tc_objs_dir\1$tc_objext#g" \ 184 | -e "s#^\(.*\.\)S\\$#$tc_objs_dir\1$tc_objext#g"` 185 | 186 | tc_src=`echo $tc_src | sed -e "s/\//$tc_regex_dirsep/g"` 187 | 188 | cat << END >> $TC_MAKEFILE 189 | 190 | $tc_obj: \$(ADDON_DEPS)$tc_cont$tc_src 191 | $tc_cc$tc_tab$tc_objout$tc_obj$tc_tab$tc_src$TC_AUX 192 | 193 | END 194 | done 195 | 196 | fi 197 | 198 | 199 | # the addons config.make 200 | 201 | if test -n "$TC_ADDONS"; then 202 | 203 | for tc_addon_dir in $TC_ADDONS 204 | do 205 | if test -f $tc_addon_dir/config.make; then 206 | . $tc_addon_dir/config.make 207 | fi 208 | done 209 | fi 210 | 211 | 212 | # the precompiled headers 213 | 214 | if test -n "$TC_PCH"; then 215 | echo "#include " > $TC_OBJS/tc_pch.c 216 | 217 | tc_pch="src/core/tc_config.h $OS_CONFIG $TC_OBJS/tc_auto_config.h" 218 | tc_pch=`echo "$TC_PCH: $tc_pch" | sed -e "s/\//$tc_regex_dirsep/g"` 219 | 220 | tc_src="\$(CC) \$(CFLAGS) $TC_BUILD_PCH $tc_compile_opt \$(ALL_INCS)" 221 | tc_src="$tc_src $tc_objout$TC_OBJS/tc_pch.obj $TC_OBJS/tc_pch.c" 222 | tc_src=`echo $tc_src | sed -e "s/\//$tc_regex_dirsep/g"` 223 | 224 | cat << END >> $TC_MAKEFILE 225 | 226 | $tc_pch 227 | $tc_src 228 | 229 | END 230 | 231 | fi 232 | -------------------------------------------------------------------------------- /auto/modules: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) bin wang 3 | # Copyright (C) NetEase, Inc. 4 | 5 | if test -n "$TC_ADDONS"; then 6 | 7 | echo configuring additional modules 8 | 9 | for tc_addon_dir in $TC_ADDONS 10 | do 11 | echo "adding module in $tc_addon_dir" 12 | 13 | if test -f $tc_addon_dir/config; then 14 | . $tc_addon_dir/config 15 | 16 | echo " + $tc_addon_name was configured" 17 | 18 | else 19 | echo "$0: error: no $tc_addon_dir/config was found" 20 | exit 1 21 | fi 22 | done 23 | fi 24 | 25 | 26 | modules="$PROTOCOL_MODULES" 27 | 28 | cat << END > $TC_MODULES_C 29 | 30 | #include 31 | 32 | $TC_PRAGMA 33 | 34 | END 35 | 36 | for mod in $modules 37 | do 38 | echo "extern tc_module_t $mod;" >> $TC_MODULES_C 39 | done 40 | 41 | echo >> $TC_MODULES_C 42 | echo 'tc_module_t *tc_modules[] = {' >> $TC_MODULES_C 43 | 44 | for mod in $modules 45 | do 46 | echo " &$mod," >> $TC_MODULES_C 47 | done 48 | 49 | cat << END >> $TC_MODULES_C 50 | NULL 51 | }; 52 | 53 | END 54 | -------------------------------------------------------------------------------- /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_CONF_PREFIX= 11 | TC_CONF_PATH= 12 | TC_PID_PATH= 13 | 14 | CC=${CC:-cc} 15 | TC_OBJS=objs 16 | 17 | TC_OFFLINE=NO 18 | TC_PCAP_CAPTURE=NO 19 | TC_PCAP_SEND=NO 20 | TC_MILLION_SUPPORT=NO 21 | TC_COMBINED=YES 22 | TC_SINGLE=NO 23 | TC_UDP=NO 24 | TC_PAYLOAD=NO 25 | TC_DIGEST=NO 26 | TC_DNAT=NO 27 | TC_EPOLL=YES 28 | TC_DEBUG=NO 29 | TC_PF_RING_DIR=NONE 30 | TC_DETECT_MEMORY=NO 31 | TC_PCAP_NEEDED=NO 32 | TC_TCMALLOC=NO 33 | 34 | TC_CC_OPT= 35 | TC_LD_OPT= 36 | 37 | 38 | TC_ADDONS= 39 | 40 | opt= 41 | 42 | for option 43 | do 44 | opt="$opt `echo $option | sed -e \"s/\(--[^=]*=\)\(.* .*\)/\1'\2'/\"`" 45 | 46 | case "$option" in 47 | -*=*) value=`echo "$option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; 48 | *) value="" ;; 49 | esac 50 | 51 | case "$option" in 52 | --help) help=yes ;; 53 | 54 | --prefix=) TC_PREFIX="!" ;; 55 | --prefix=*) TC_PREFIX="$value" ;; 56 | --sbin-path=*) TC_SBIN_PATH="$value" ;; 57 | --conf-path=*) TC_CONF_PATH="$value" ;; 58 | --error-log-path=*) TC_ERROR_LOG_PATH="$value";; 59 | --pid-path=*) TC_PID_PATH="$value" ;; 60 | 61 | --builddir=*) TC_OBJS="$value" ;; 62 | 63 | --set-protocol-module=*) TC_ADDONS="$TC_ADDONS $value" ;; 64 | 65 | --with-cc=*) CC="$value" ;; 66 | --with-cc-opt=*) TC_CC_OPT="$value" ;; 67 | --with-ld-opt=*) TC_LD_OPT="$value" ;; 68 | 69 | --single) TC_SINGLE=YES ;; 70 | --offline) TC_OFFLINE=YES ;; 71 | --pcap-capture) TC_PCAP_CAPTURE=YES ;; 72 | --pcap-send) TC_PCAP_SEND=YES ;; 73 | --million) TC_MILLION_SUPPORT=YES ;; 74 | --select) TC_EPOLL=NO ;; 75 | --dnat) TC_DNAT=YES ;; 76 | --disable-combined) TC_COMBINED=NO ;; 77 | --udp) TC_UDP=YES ;; 78 | 79 | --with-debug) TC_DEBUG=YES ;; 80 | --with-tcmalloc) TC_TCMALLOC=YES ;; 81 | --with-pfring=*) TC_PF_RING_DIR="$value" ;; 82 | --with-detect-memory) TC_DETECT_MEMORY=YES ;; 83 | 84 | *) 85 | echo "$0: error: invalid option \"$option\"" 86 | exit 1 87 | ;; 88 | esac 89 | done 90 | 91 | 92 | TC_CONFIGURE="$opt" 93 | 94 | 95 | if [ $help = yes ]; then 96 | 97 | cat << END 98 | 99 | --help print this message 100 | 101 | --prefix=PATH set installation prefix 102 | --sbin-path=PATH set tcpcopy binary pathname 103 | --conf-path=PATH set plugin.conf pathname 104 | --pid-path=PATH set tcpcopy.pid pathname 105 | 106 | --builddir=DIR set build directory 107 | 108 | --set-protocol-module=PATH set tcpcopy to work for an external protocol module 109 | 110 | --with-cc=PATH set C compiler pathname 111 | --with-cpp=PATH set C preprocessor pathname 112 | --with-cc-opt=OPTIONS set additional C compiler options 113 | --with-ld-opt=OPTIONS set additional linker options 114 | --with-pfring=PATH set path to PF_RING library sources 115 | --with-debug enable debug logging 116 | --with-tcmalloc use tcmalloc instead of malloc 117 | 118 | --offline run tcpcopy at offline mode 119 | --single run tcpcopy at non-distributed mode 120 | --pcap-capture capture packets at the data link 121 | --pcap-send send packets at the data link 122 | --million support comet 123 | --select use select module 124 | --dnat support dnat 125 | --disable-combined disable combined response mode 126 | --udp udpcopy 127 | 128 | END 129 | 130 | exit 1 131 | fi 132 | 133 | 134 | TC_CONF_PATH=${TC_CONF_PATH:-conf/plugin.conf} 135 | TC_CONF_PREFIX=`dirname $TC_CONF_PATH` 136 | TC_PID_PATH=${TC_PID_PATH:-logs/tcpcopy.pid} 137 | 138 | if [ ".$TC_ERROR_LOG_PATH" = ".stderr" ]; then 139 | TC_ERROR_LOG_PATH= 140 | else 141 | TC_ERROR_LOG_PATH=${TC_ERROR_LOG_PATH:-logs/error_tcpcopy.log} 142 | fi 143 | 144 | -------------------------------------------------------------------------------- /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_palloc.h \ 11 | src/core/tc_array.h \ 12 | src/core/tc_link_list.h \ 13 | src/core/tc_hash.h \ 14 | src/core/tc_conf_file.h \ 15 | src/core/tc_rbtree.h \ 16 | src/core/tc_log.h \ 17 | src/core/tc_time.h \ 18 | src/core/tc_signal.h" 19 | 20 | 21 | CORE_SRCS="src/core/tc_alloc.c \ 22 | src/core/tc_log.c \ 23 | src/core/tc_palloc.c \ 24 | src/core/tc_array.c \ 25 | src/core/tc_link_list.c \ 26 | src/core/tc_hash.c \ 27 | src/core/tc_signal.c \ 28 | src/core/tc_time.c \ 29 | src/core/tc_conf_file.c \ 30 | src/core/tc_rbtree.c \ 31 | src/core/tc_daemon.c" 32 | 33 | EVENT_INCS="src/event" 34 | 35 | EVENT_DEPS="src/event/tc_event.h \ 36 | src/event/tc_event_timer.h" 37 | 38 | EVENT_SRCS="src/event/tc_event.c \ 39 | src/event/tc_event_timer.c" 40 | 41 | SELECT_DEPS="src/event/tc_select_module.h" 42 | 43 | SELECT_SRCS="src/event/tc_select_module.c" 44 | 45 | EPOLL_DEPS="src/event/tc_epoll_module.h" 46 | 47 | EPOLL_SRCS="src/event/tc_epoll_module.c" 48 | 49 | COMMUNICATION_INCS="src/communication" 50 | 51 | COMMUNICATION_DEPS="src/communication/tc_socket.h" 52 | 53 | COMMUNICATION_SRCS="src/communication/tc_socket.c" 54 | 55 | 56 | DIGEST_INCS="src/digest" 57 | 58 | DIGEST_DEPS="src/digest/tc_evp.h" 59 | 60 | DIGEST_SRCS="src/digest/tc_evp.c" 61 | 62 | 63 | UTIL_INCS="src/util" 64 | 65 | UTIL_DEPS="src/util/tc_util.h" 66 | 67 | UTIL_SRCS="src/util/tc_util.c" 68 | 69 | TCPCOPY_INCS="src/tcpcopy" 70 | 71 | TCPCOPY_DEPS="src/tcpcopy/tcpcopy.h \ 72 | src/tcpcopy/tc_manager.h \ 73 | src/tcpcopy/tc_message_module.h \ 74 | src/tcpcopy/tc_packets_module.h \ 75 | src/tcpcopy/tc_session.h" 76 | 77 | if [ $TC_UDP = YES ]; then 78 | TCPCOPY_SRCS="src/tcpcopy/tc_manager.c \ 79 | src/tcpcopy/tc_packets_module.c \ 80 | src/tcpcopy/tc_message_module.c \ 81 | src/tcpcopy/tc_udp_session.c \ 82 | src/tcpcopy/main.c" 83 | else 84 | TCPCOPY_SRCS="src/tcpcopy/tc_manager.c \ 85 | src/tcpcopy/tc_packets_module.c \ 86 | src/tcpcopy/tc_message_module.c \ 87 | src/tcpcopy/tc_session.c \ 88 | src/tcpcopy/main.c" 89 | fi 90 | -------------------------------------------------------------------------------- /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 | tcpcopy path prefix: "$TC_PREFIX" 14 | tcpcopy binary file: "$TC_SBIN_PATH" 15 | tcpcopy configuration prefix: "$TC_CONF_PREFIX" 16 | tcpcopy configuration file: "$TC_CONF_PATH" 17 | tcpcopy pid file: "$TC_PID_PATH" 18 | END 19 | 20 | if test -n "$TC_ERROR_LOG_PATH"; then 21 | echo " tcpcopy error log file: \"$TC_ERROR_LOG_PATH\"" 22 | else 23 | echo " tcpcopy logs errors to stderr" 24 | fi 25 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /conf/plugin.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin579/tcpcopy/21a3698adba8c350dde4d164174df9d9254ceaea/conf/plugin.conf -------------------------------------------------------------------------------- /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 | 34 | case "$TC_PLATFORM" in 35 | 36 | Linux:*) 37 | . auto/os/linux 38 | ;; 39 | 40 | *) 41 | echo "error: Linux only!" 42 | exit 1 43 | esac 44 | 45 | 46 | if [ $TC_DEBUG = YES ]; then 47 | have=TC_DEBUG . auto/have 48 | have=TC_DETECT_MEMORY . auto/have 49 | else 50 | if [ $TC_DETECT_MEMORY = YES ]; then 51 | have=TC_DETECT_MEMORY . auto/have 52 | fi 53 | fi 54 | 55 | if [ $TC_SINGLE = YES ]; then 56 | have=TC_SINGLE . auto/have 57 | fi 58 | 59 | if [ $TC_OFFLINE = YES ]; then 60 | TC_PCAP_NEEDED=YES 61 | have=TC_OFFLINE . auto/have 62 | fi 63 | 64 | if [ $TC_PCAP_CAPTURE = YES ]; then 65 | TC_PCAP_NEEDED=YES 66 | have=TC_PCAP . auto/have 67 | fi 68 | 69 | if [ $TC_PCAP_SEND = YES ]; then 70 | TC_PCAP_NEEDED=YES 71 | have=TC_PCAP_SND . auto/have 72 | fi 73 | 74 | if [ $TC_PCAP_NEEDED = YES ]; then 75 | if [ $TC_PF_RING_DIR != NONE ]; then 76 | have=TC_HAVE_PF_RING . auto/have 77 | CORE_LIBS="$CORE_LIBS $TC_PF_RING_DIR/userland/libpcap/libpcap.a" 78 | CORE_LIBS="$CORE_LIBS $TC_PF_RING_DIR/userland/lib/libpfring.a" 79 | CORE_LIBS="$CORE_LIBS -lrt -lpthread -lnuma" 80 | else 81 | CORE_LIBS="$CORE_LIBS -lpcap" 82 | fi 83 | fi 84 | 85 | if [ $TC_TCMALLOC = YES ]; then 86 | CORE_LIBS="$CORE_LIBS -ltcmalloc" 87 | fi 88 | 89 | if [ $TC_MILLION_SUPPORT = YES ]; then 90 | have=TC_MILLION_SUPPORT . auto/have 91 | fi 92 | 93 | if test -n "$TC_ADDONS"; then 94 | have=TC_PLUGIN . auto/have 95 | fi 96 | 97 | if [ $TC_COMBINED = YES ]; then 98 | have=TC_COMBINED . auto/have 99 | fi 100 | 101 | if [ $TC_UDP = YES ]; then 102 | have=TC_UDP . auto/have 103 | fi 104 | 105 | if [ $TC_DNAT = YES ]; then 106 | have=TC_DNAT . auto/have 107 | fi 108 | 109 | . auto/cc/conf 110 | . auto/headers 111 | . auto/os/conf 112 | . auto/linux 113 | . auto/modules 114 | 115 | 116 | if [ $TC_PAYLOAD = YES ]; then 117 | have=TC_PAYLOAD . auto/have 118 | fi 119 | 120 | if [ $TC_DIGEST = YES ]; then 121 | tc_include="openssl/evp.h"; . auto/include 122 | have=TC_DIGEST . auto/have 123 | CORE_LIBS="$CORE_LIBS -lcrypto -lm" 124 | fi 125 | 126 | case ".$TC_PREFIX" in 127 | .) 128 | TC_PREFIX=${TC_PREFIX:-/usr/local/tcpcopy} 129 | have=TC_PREFIX value="\"$TC_PREFIX/\"" . auto/define 130 | ;; 131 | 132 | .!) 133 | TC_PREFIX= 134 | ;; 135 | 136 | *) 137 | have=TC_PREFIX value="\"$TC_PREFIX/\"" . auto/define 138 | ;; 139 | esac 140 | 141 | if [ ".$TC_CONF_PREFIX" != "." ]; then 142 | have=TC_CONF_PREFIX value="\"$TC_CONF_PREFIX/\"" . auto/define 143 | fi 144 | 145 | have=TC_SBIN_PATH value="\"$TC_SBIN_PATH\"" . auto/define 146 | have=TC_CONF_PATH value="\"$TC_CONF_PATH\"" . auto/define 147 | have=TC_PID_PATH value="\"$TC_PID_PATH\"" . auto/define 148 | have=TC_ERROR_LOG_PATH value="\"$TC_ERROR_LOG_PATH\"" . auto/define 149 | 150 | . auto/make 151 | . auto/install 152 | . auto/summary 153 | -------------------------------------------------------------------------------- /doc/Pre-Warming.md: -------------------------------------------------------------------------------- 1 | # Pre-Warming Data for a Newly Added MySQL Secondary Using TCPCopy 2 | 3 | Using TCPCopy to pre-warm data on a newly added MySQL secondary is quite practical. Many users have employed this method, especially for high-load secondaries. Adding a cold secondary directly to the cluster can lead to numerous slow queries. 4 | 5 | ## Architecture Deployment Diagram 6 | 7 | Below is the deployment architecture diagram for pre-warming. It replicates read-only requests from MySQL secondary one to MySQL secondary two to achieve the pre-warming effect. 8 | 9 | ![](../images/pre-warming1.png) 10 | 11 | ## Deploying TCPCopy 12 | 13 | ### Installing `tcpcopy` 14 | 15 | ``` 16 | git clone https://github.com/session-replay-tools/tcpcopy.git 17 | cd tcpcopy 18 | ./configure --set-protocol-module=mysql-replay-module 19 | make && make install 20 | ``` 21 | 22 | By default, it is installed in `/usr/local/tcpcopy/`. 23 | 24 | Modify `/usr/local/tcpcopy/conf/plugin.conf` and include the database username and password that will be used for future pre-warming. 25 | 26 | ``` 27 | user test@123; 28 | user app_user@456; 29 | ``` 30 | 31 | ### Install `intercept` on the Assistant Server. 32 | 33 | ``` 34 | git clone https://github.com/session-replay-tools/intercept.git 35 | cd intercept 36 | ./configure --with-resp-payload 37 | make && make install 38 | ``` 39 | 40 | By default, it is installed in `/usr/local/intercept/`. 41 | 42 | ## Running TCPCopy 43 | 44 | We assume that all MySQL nodes use port 3306. The client IP addresses accessing the online secondary server fall within the 192.168.0.0 subnet. The online secondary server is at 192.168.2.3, the target server is at 192.168.2.4, and the assistant server is at 192.168.2.5, as shown in the diagram below. 45 | 46 | ![](../images/pre-warming2.png) 47 | 48 | ### Routing Setup on the MySQL Secondary Two 49 | 50 | ``` 51 | route add -net 192.168.0.0 netmask 255.255.0.0 gw 192.168.2.5 52 | ``` 53 | 54 | ### Run `intercept` on the Assistant Server 55 | 56 | Please note that `ip_forward` is not enabled on the assistant server. 57 | 58 | ``` 59 | ./intercept -i eth0 -F 'tcp and src port 3306' -d 60 | ``` 61 | 62 | ### Run `tcpcopy` on the MySQL Secondary one 63 | 64 | ``` 65 | ./tcpcopy -x 3306-192.168.2.4:3306 -s 192.168.2.5 66 | ``` 67 | 68 | With all deployments completed, you can proceed with the pre-warming operation as expected. 69 | 70 | ## Note 71 | 72 | 1. User Accounts and Privileges: Both MySQL instances on the target and online servers must have identical user accounts and privileges, though passwords can differ. 73 | 2. Session Replay: Only complete sessions can be replayed. 74 | 3. OpenSSL Support: OpenSSL 1.1.0+ is not currently supported. 75 | 4. Password Plugin Compatibility: MySQL 8.0’s caching_sha2_password is not supported. To test MySQL 8.0 using MySQL 5.7 production flows, use mysql_native_password and ensure that all users involved in the test are configured with the mysql_native_password plugin. 76 | 5. For additional assistance, visit [tcpcopy](https://github.com/session-replay-tools/tcpcopy). 77 | -------------------------------------------------------------------------------- /doc/Usage.md: -------------------------------------------------------------------------------- 1 | # TCPCopy Examples 2 | 3 | If the reader has not yet read the two articles below, please do so first to facilitate understanding of the subsequent examples. 4 | 5 | 1. [An Overview of TCPCopy for Beginners](https://session-replay-tools.github.io/tcpcopy/doc/Beginners.html) 6 | 7 | 2. [A General Overview of TCPCopy Architecture](https://session-replay-tools.github.io/tcpcopy/doc/Architecture.html) 8 | 9 | Back to the main topic, this article will illustrate the value of TCPCopy through three examples to deepen the user's understanding of it. 10 | 11 | ## 1. Copying Private Protocols to the Test System 12 | 13 | The following example demonstrates how TCPCopy can be configured for a network application. The goal is to replicate online ad server requests to the ad server in a test environment. 14 | 15 | ![](../images/example1.png) 16 | 17 | The relevant information in the figure is described as follows: 18 | 19 | - The online ad servers have four servers called by ad clients, with client IP addresses originating from ad client machines in the same network segment. 20 | - Suppose the ad server IPs are `10.100.10.1`,`10.100.10.2` ,`10.100.10.3` and `10.100.10.4`, and ad client IPs are `10.100.10.11`, `10.100.10.12`, `10.100.10.13`,`10.100.10.14`,`10.100.10.15` and `10.100.10.16`. 21 | - The test ad server’s IP is `10.100.10.31`, and the assistent server’s IP is `10.100.10.32`. 22 | - We assume that all ad server programs are listening on port 11311. 23 | 24 | Here are the three main steps for deploying and running TCPCopy: 25 | 26 | **1. Set Up Routing on the Test AD Server** 27 | 28 | Below are the routing settings we configured on the test ad server to prevent responses from returning to the ad clients: 29 | 30 | ```shell 31 | route add -host 10.100.10.11 gw 10.100.10.32 32 | route add -host 10.100.10.12 gw 10.100.10.32 33 | route add -host 10.100.10.13 gw 10.100.10.32 34 | route add -host 10.100.10.14 gw 10.100.10.32 35 | route add -host 10.100.10.15 gw 10.100.10.32 36 | route add -host 10.100.10.16 gw 10.100.10.32 37 | ``` 38 | 39 | **2. Running intercept on the Assistent Server** 40 | 41 | `./intercept -i eth0 -F 'tcp and src port 11311' -d` 42 | 43 | Here, we assume the network card interface is set to eth0. 44 | 45 | Please note that `ip_forward` is not enabled on the assistant server. 46 | 47 | **3. Running tcpcopy on the AD Servers** 48 | 49 | `./tcpcopy -x 11311-10.100.10.31:11311 -s 10.100.10.32 -d` 50 | 51 | This completes the TCPCopy deployment, allowing us to replicate requests from four ad servers to a single test ad server for various testing purposes, such as performance testing, bug discovery, and stability assessment. 52 | 53 | This configuration is quite classic and well-suited for projects that do not directly interface with external network clients, such as those accessing application servers like Tomcat and Redis. 54 | 55 | ## 2. Copying MySQL Requests to Test Systems 56 | 57 | MySQL is a stateful protocol, so directly using TCPCopy to replicate MySQL requests will not succeed. To support MySQL request replication, we developed a TCPCopy module specifically for the MySQL protocol. For detailed information, please visit [MySQL replay](https://github.com/session-replay-tools/mysql-replay-module) 58 | 59 | To successfully conduct testing of MySQL applications, consider the following details: 60 | 61 | 1. Follow the deployment requirements in the documentation precisely. 62 | 2. Ensure the username and permissions configured on the MySQL test server match those on the MySQL online server. 63 | 3. MySQL must use native password authentication; otherwise, it will not function properly. 64 | 4. Sysbench initiates requests on the production side, and TCPCopy is started before this to capture complete session data packets. 65 | 66 | Assume the machine at 172.168.0.15 runs Sysbench, 172.168.0.16 hosts the online MySQL service, 172.168.0.17 runs the test MySQL service, and 172.168.0.18 is designated as the assistent server. 67 | 68 | ![](../images/example2.png) 69 | 70 | **Set Up Routing on the MySQL Test Server** 71 | 72 | route add -host 172.168.0.15 gw 172.168.0.18 73 | 74 | **Running intercept on the Assistent Server** 75 | 76 | `./intercept -i eth0 -F 'tcp and src port 3306' -d` 77 | 78 | Please note that `ip_forward` is not enabled on the assistant server. 79 | 80 | **Running TCPCopy on the MySQL Online Server** 81 | 82 | `./tcpcopy -x 3306-172.168.0.17:3306 -s 172.168.0.18 -d` 83 | 84 | On 172.168.0.15, the Sysbench script to simulate online requests is as follows: 85 | 86 | `sysbench --debug=off --test=oltp --mysql-table-engine=innodb --oltp-test-mode=complex --oltp-table-size=10000 --mysql-socket=/tmp/mysql.sock --num-threads=20 --max-requests=0 --mysql-user=test --mysql-password=yyyyyy --mysql-host=172.168.0.16 run` 87 | 88 | **The final results of the request replication are as follows:** 89 | 90 | ```shell 91 | MySQL access log recorded on the MySQL online server: 92 | [root@16 tmp]# ll access.log 93 | -rw-rw---- 1 mysql mysql 1160590772 Feb 14 14:34 access.log 94 | 95 | MySQL access log recorded on the MySQL test server: 96 | [root@17 tmp]# ll access.log 97 | -rw-rw---- 1 mysql mysql 1160696291 Feb 14 14:34 access.log 98 | ``` 99 | 100 | From the data above, we can see that the MySQL access logs are generally similar. 101 | 102 | ## 3. Packet Capture and Transmission via the pcap Interface 103 | 104 | In an online system, `tcpcopy` can be configured with the following command: 105 | 106 | ```shell 107 | ./configure --pcap-send --pcap-capture 108 | ``` 109 | 110 | This configuration allows `tcpcopy` to leverage the `pcap` mechanism to capture and transmit packets directly at the data link layer, effectively bypassing the IP layer. 111 | 112 | ### Example of Web Request Replication 113 | 114 | The command below demonstrates how to run `tcpcopy` to replicate application requests from an online port to a testing environment: 115 | 116 | ```shell 117 | ./tcpcopy -x @-:@ -s -o -i 118 | ``` 119 | 120 | We assume that the target server and the online server are on the same network segment. The following command demonstrates how to use tcpcopy to capture and send requests. 121 | 122 | ```shell 123 | sudo ./tcpcopy -x 80@00:13:21:B2:5E:42-121.55.111.148:18080@00:0F:1F:03:F2:E6 -s 10.110.12.162 -o eth1 -i eth0 124 | ``` 125 | 126 | This command captures requests to port 80 on the online server and forwards them to port 18080 on the target server (IP `121.55.111.148`). Specifically: 127 | 128 | - `tcpcopy` captures packets on interface `eth0`. 129 | - Packets are sent from MAC address `00:13:21:B2:5E:42` (associated with `eth1`) and forwarded to the target machine's MAC address `00:0F:1F:03:F2:E6`. Since both are in the same network segment, the next hop MAC is the target machine's MAC. 130 | - `intercept` runs on `10.110.12.162` to capture response packets routed back to the `tcpcopy` system. 131 | 132 | ### Key Considerations 133 | 134 | 1. **Matching Network Interface and MAC Address**: The output network interface specified with `-o` must match the MAC address of the outgoing network adapter, and ideally align with the network interface needed to reach the target machine's IP. 135 | 2. **MAC Address Alignment**: In the same network segment, the destination MAC should match the target machine’s IP; in different segments, use the next hop's MAC address. `tcpdump` can help identify the MAC address if necessary. 136 | 3. **Routing Without IP Layer**: As `tcpcopy` sends packets from the data link layer, IP-based routing is bypassed, requiring explicit configuration of the MAC addresses to manage packet routing. 137 | 4. Since packet transmission bypasses the IP layer, it avoids various IP layer issues, including IP conntrack-related problems. 138 | 5. This setup enables large-scale replication of online requests, allowing users with the necessary resources to use switch mirroring to replicate traffic. 139 | 140 | ## Application Scope 141 | 142 | Stateless protocols are ideally suited for TCPCopy, while stateful protocols necessitate module development. Many internal protocols used for access, like those for Redis, HTTP, and Memcached, are stateless. In contrast, stateful protocols, including MySQL, WebSocket, and email protocols, require further development efforts. Protocols relying on TLS/SSL are often too complex and expensive to implement; it may be more practical to utilize hardware to offload these protocols and subsequently convert them into simpler alternatives. 143 | 144 | Finally, if users require custom development, we will offer corresponding paid services. 145 | -------------------------------------------------------------------------------- /images/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin579/tcpcopy/21a3698adba8c350dde4d164174df9d9254ceaea/images/example1.png -------------------------------------------------------------------------------- /images/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin579/tcpcopy/21a3698adba8c350dde4d164174df9d9254ceaea/images/example2.png -------------------------------------------------------------------------------- /images/first.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin579/tcpcopy/21a3698adba8c350dde4d164174df9d9254ceaea/images/first.png -------------------------------------------------------------------------------- /images/pre-warming1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin579/tcpcopy/21a3698adba8c350dde4d164174df9d9254ceaea/images/pre-warming1.png -------------------------------------------------------------------------------- /images/pre-warming2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin579/tcpcopy/21a3698adba8c350dde4d164174df9d9254ceaea/images/pre-warming2.png -------------------------------------------------------------------------------- /images/second.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin579/tcpcopy/21a3698adba8c350dde4d164174df9d9254ceaea/images/second.png -------------------------------------------------------------------------------- /images/tcp_state_machine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin579/tcpcopy/21a3698adba8c350dde4d164174df9d9254ceaea/images/tcp_state_machine.png -------------------------------------------------------------------------------- /images/tcpcopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbin579/tcpcopy/21a3698adba8c350dde4d164174df9d9254ceaea/images/tcpcopy.png -------------------------------------------------------------------------------- /src/communication/tc_msg.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_MSG_INCLUDED 2 | #define TC_MSG_INCLUDED 3 | 4 | #include 5 | 6 | typedef struct msg_clt_s msg_clt_t; 7 | typedef struct msg_server_s msg_server_t; 8 | 9 | #pragma pack(push,1) 10 | 11 | struct msg_clt_s { 12 | uint32_t clt_ip; 13 | uint16_t clt_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 | #if (TC_PAYLOAD) 23 | unsigned char extension[MAX_OPTION_LEN + MAX_PAYLOAD_LEN]; 24 | #else 25 | unsigned char extension[MAX_OPTION_LEN]; 26 | #endif 27 | }; 28 | #pragma pack(pop) 29 | 30 | #define MSG_CLT_SIZE sizeof(msg_clt_t) 31 | #define MSG_SERVER_SIZE sizeof(msg_server_t) 32 | 33 | #endif /* TC_MSG_INCLUDED */ 34 | 35 | -------------------------------------------------------------------------------- /src/communication/tc_socket.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_SOCKET_INCLUDED 2 | #define TC_SOCKET_INCLUDED 3 | 4 | #define TC_INVALID_SOCK -1 5 | 6 | #include 7 | 8 | #define tc_socket_close(fd) close(fd) 9 | 10 | #if (TC_PCAP) 11 | int tc_pcap_socket_in_init(pcap_t **pd, char *device, 12 | int snap_len, int buf_size, char *pcap_filter); 13 | #endif 14 | int tc_raw_socket_in_init(int type); 15 | 16 | int tc_raw_socket_out_init(void); 17 | int tc_raw_socket_snd(int fd, void *buf, size_t len, uint32_t ip); 18 | 19 | #if (TC_PCAP_SND) 20 | int tc_pcap_snd_init(char *if_name, int mtu); 21 | int tc_pcap_snd(unsigned char *frame, size_t len); 22 | int tc_pcap_over(void); 23 | #endif 24 | 25 | int tc_socket_init(void); 26 | int tc_socket_set_nonblocking(int fd); 27 | int tc_socket_set_nodelay(int fd); 28 | int tc_socket_connect(int fd, uint32_t ip, uint16_t port); 29 | int tc_socket_rcv(int fd, char *buffer, ssize_t len); 30 | #if (TC_COMBINED) 31 | int tc_socket_cmb_rcv(int fd, int *num, char *buffer); 32 | #endif 33 | int tc_socket_snd(int fd, char *buffer, int len); 34 | 35 | #endif /* TC_SOCKET_INCLUDED */ 36 | 37 | -------------------------------------------------------------------------------- /src/core/tc_alloc.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | tc_uint_t tc_pagesize; 5 | tc_uint_t tc_pagesize_shift; 6 | tc_uint_t tc_cacheline_size; 7 | 8 | 9 | void * 10 | tc_alloc(size_t size) 11 | { 12 | void *p; 13 | 14 | if (size > 512) { 15 | if (size < 1024) { 16 | size = 1024; 17 | } else if (size < 2048) { 18 | size = 2048; 19 | } 20 | } 21 | 22 | p = malloc(size); 23 | if (p == NULL) { 24 | tc_log_info(LOG_EMERG, errno, 25 | "malloc(%uz) failed", size); 26 | } 27 | 28 | return p; 29 | } 30 | 31 | 32 | #if (TC_HAVE_POSIX_MEMALIGN) 33 | 34 | void * 35 | tc_memalign(size_t alignment, size_t size) 36 | { 37 | void *p; 38 | int err; 39 | 40 | err = posix_memalign(&p, alignment, size); 41 | 42 | if (err) { 43 | p = NULL; 44 | } 45 | 46 | return p; 47 | } 48 | 49 | #elif (TC_HAVE_MEMALIGN) 50 | 51 | void * 52 | tc_memalign(size_t alignment, size_t size) 53 | { 54 | void *p; 55 | 56 | p = memalign(alignment, size); 57 | if (p == NULL) { 58 | tc_log_info(LOG_EMERG, tc_errno, 59 | "memalign(%uz, %uz) failed", alignment, size); 60 | } 61 | 62 | return p; 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /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 | extern tc_uint_t tc_pagesize_shift; 26 | extern tc_uint_t tc_cacheline_size; 27 | 28 | 29 | #endif /* _TC_ALLOC_H_INCLUDED_ */ 30 | -------------------------------------------------------------------------------- /src/core/tc_array.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | tc_array_t * 5 | tc_array_create(tc_pool_t *p, unsigned int n, size_t size) 6 | { 7 | tc_array_t *a; 8 | 9 | a = tc_palloc(p, sizeof(tc_array_t)); 10 | if (a == NULL) { 11 | return NULL; 12 | } 13 | 14 | if (tc_array_init(a, p, n, size) != TC_OK) { 15 | return NULL; 16 | } 17 | 18 | return a; 19 | } 20 | 21 | 22 | void 23 | tc_array_destroy(tc_array_t *a) 24 | { 25 | tc_pool_t *p; 26 | 27 | p = a->pool; 28 | 29 | if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) { 30 | p->d.last -= a->size * a->nalloc; 31 | } 32 | 33 | if ((u_char *) a + sizeof(tc_array_t) == p->d.last) { 34 | p->d.last = (u_char *) a; 35 | } 36 | } 37 | 38 | 39 | void * 40 | tc_array_push(tc_array_t *a) 41 | { 42 | void *elt, *new; 43 | size_t size; 44 | tc_pool_t *p; 45 | 46 | if (a->nelts == a->nalloc) { 47 | 48 | /* The array is full */ 49 | 50 | size = a->size * a->nalloc; 51 | 52 | p = a->pool; 53 | 54 | if ((u_char *) a->elts + size == p->d.last 55 | && p->d.last + a->size <= p->d.end) 56 | { 57 | /* 58 | * The array allocation is the last in the pool 59 | * and there is space for new allocation 60 | */ 61 | 62 | p->d.last += a->size; 63 | a->nalloc++; 64 | 65 | } else { 66 | /* Allocate a new array */ 67 | 68 | new = tc_palloc(p, 2 * size); 69 | if (new == NULL) { 70 | return NULL; 71 | } 72 | 73 | memcpy(new, a->elts, size); 74 | a->elts = new; 75 | a->nalloc *= 2; 76 | } 77 | } 78 | 79 | elt = (u_char *) a->elts + a->size * a->nelts; 80 | a->nelts++; 81 | 82 | return elt; 83 | } 84 | 85 | 86 | void * 87 | tc_array_push_n(tc_array_t *a, unsigned int n) 88 | { 89 | void *elt, *new; 90 | size_t size; 91 | unsigned int nalloc; 92 | tc_pool_t *p; 93 | 94 | size = n * a->size; 95 | 96 | if (a->nelts + n > a->nalloc) { 97 | 98 | /* The array is full */ 99 | 100 | p = a->pool; 101 | 102 | if ((u_char *) a->elts + a->size * a->nalloc == p->d.last 103 | && p->d.last + size <= p->d.end) 104 | { 105 | /* 106 | * The array allocation is the last in the pool 107 | * and there is space for new allocation 108 | */ 109 | 110 | p->d.last += size; 111 | a->nalloc += n; 112 | 113 | } else { 114 | /* Allocate a new array */ 115 | 116 | nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc); 117 | 118 | new = tc_palloc(p, nalloc * a->size); 119 | if (new == NULL) { 120 | return NULL; 121 | } 122 | 123 | memcpy(new, a->elts, a->nelts * a->size); 124 | a->elts = new; 125 | a->nalloc = nalloc; 126 | } 127 | } 128 | 129 | elt = (u_char *) a->elts + a->size * a->nelts; 130 | a->nelts += n; 131 | 132 | return elt; 133 | } 134 | -------------------------------------------------------------------------------- /src/core/tc_array.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TC_ARRAY_H_INCLUDED 3 | #define TC_ARRAY_H_INCLUDED 4 | 5 | #include 6 | 7 | 8 | struct tc_array_s{ 9 | void *elts; 10 | unsigned int nelts; 11 | size_t size; 12 | unsigned int nalloc; 13 | tc_pool_t *pool; 14 | }; 15 | 16 | 17 | tc_array_t *tc_array_create(tc_pool_t *p, unsigned int n, size_t size); 18 | void tc_array_destroy(tc_array_t *a); 19 | void *tc_array_push(tc_array_t *a); 20 | void *tc_array_push_n(tc_array_t *a, unsigned int n); 21 | 22 | 23 | static inline int 24 | tc_array_init(tc_array_t *array, tc_pool_t *pool, unsigned int n, size_t size) 25 | { 26 | array->nelts = 0; 27 | array->size = size; 28 | array->nalloc = n; 29 | array->pool = pool; 30 | 31 | array->elts = tc_palloc(pool, n * size); 32 | if (array->elts == NULL) { 33 | return TC_ERR; 34 | } 35 | 36 | return TC_OK; 37 | } 38 | 39 | 40 | #endif /* TC_ARRAY_H_INCLUDED */ 41 | -------------------------------------------------------------------------------- /src/core/tc_conf_file.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_CONF_FILE_INCLUDED 2 | #define TC_CONF_FILE_INCLUDED 3 | 4 | #include 5 | 6 | #if (TC_PLUGIN) 7 | #define TC_CONF_BLOCK_START 1 8 | #define TC_CONF_BLOCK_DONE 2 9 | #define TC_CONF_FILE_DONE 3 10 | 11 | #define tc_file_size(sb) (sb)->st_size 12 | #define LF (u_char) 10 13 | #define CR (u_char) 13 14 | #define CRLF "\x0d\x0a" 15 | 16 | typedef struct { 17 | int len; 18 | unsigned char *data; 19 | } tc_str_t; 20 | 21 | struct tc_buf_s { 22 | unsigned char *pos; 23 | unsigned char *last; 24 | unsigned char *start; 25 | unsigned char *end; 26 | }; 27 | 28 | struct tc_file_s { 29 | int fd; 30 | off_t offset; 31 | struct stat info; 32 | }; 33 | 34 | typedef struct { 35 | tc_file_t file; 36 | tc_buf_t *buffer; 37 | int line; 38 | } tc_conf_file_t; 39 | 40 | struct tc_cmd_s { 41 | tc_str_t name; 42 | int conf; 43 | int offset; 44 | unsigned int type; 45 | int (*set)(tc_conf_t *cf, tc_cmd_t *cmd); 46 | void *post; 47 | }; 48 | 49 | struct tc_conf_s { 50 | tc_array_t *args; 51 | tc_pool_t *pool; 52 | tc_conf_file_t *conf_file; 53 | }; 54 | 55 | char *tc_conf_full_name(tc_pool_t *,char *, char *); 56 | int tc_conf_parse(tc_module_t *plugin, tc_pool_t *pool, tc_conf_t *cf, 57 | char *filename); 58 | #endif 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /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(void) 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_hash.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | static hash_node * 5 | hash_node_malloc(tc_pool_t *pool, uint64_t key, void *data) 6 | { 7 | hash_node *hn = (hash_node *) tc_palloc(pool, sizeof(hash_node)); 8 | 9 | if (hn != NULL) { 10 | hn->key = key; 11 | hn->data = data; 12 | hn->create_time = tc_time(); 13 | hn->access_time = tc_time(); 14 | } else { 15 | tc_log_info(LOG_ERR, errno, "can't malloc memory for hash node"); 16 | } 17 | 18 | return hn; 19 | } 20 | 21 | 22 | static p_link_node 23 | hash_find_link_node(hash_table *table, uint64_t key) 24 | { 25 | bool first = true; 26 | hash_node *hn; 27 | link_list *l = get_link_list(table, key); 28 | p_link_node ln = link_list_first(l); 29 | 30 | while (ln) { 31 | 32 | hn = (hash_node *) ln->data; 33 | if (hn->key == key) { 34 | hn->access_time = tc_time(); 35 | if (!first) { 36 | /* Put the lastest item to the head of the linked list */ 37 | link_list_remove(l, ln); 38 | link_list_push(l, ln); 39 | } 40 | return ln; 41 | } 42 | ln = link_list_get_next(l, ln); 43 | first = false; 44 | } 45 | 46 | return NULL; 47 | } 48 | 49 | 50 | hash_table * 51 | hash_create(tc_pool_t *pool, uint32_t size) 52 | { 53 | size_t i; 54 | hash_table *ht = (hash_table *) tc_pcalloc(pool, sizeof(hash_table)); 55 | 56 | if (ht != NULL) { 57 | ht->pool = pool; 58 | ht->size = size; 59 | ht->lists = (link_list **) tc_pcalloc(pool, size * sizeof(link_list *)); 60 | if (ht->lists != NULL) { 61 | for (i = 0; i < size; i++) { 62 | ht->lists[i] = link_list_create(pool); 63 | } 64 | } else { 65 | tc_log_info(LOG_ERR, errno, "can't calloc memory for hash lists"); 66 | ht = NULL; 67 | } 68 | } else { 69 | tc_log_info(LOG_ERR, errno, "can't calloc memory for hash table"); 70 | } 71 | 72 | return ht; 73 | } 74 | 75 | 76 | void * 77 | hash_find(hash_table *table, uint64_t key) 78 | { 79 | hash_node *hn; 80 | p_link_node ln = hash_find_link_node(table, key); 81 | 82 | if (ln != NULL) { 83 | hn = (hash_node *) ln->data; 84 | return hn->data; 85 | } 86 | 87 | return NULL; 88 | } 89 | 90 | 91 | hash_node * 92 | hash_find_node(hash_table *table, uint64_t key) 93 | { 94 | hash_node *hn; 95 | p_link_node ln = hash_find_link_node(table, key); 96 | 97 | if (ln != NULL) { 98 | hn = (hash_node *) ln->data; 99 | return hn; 100 | } 101 | 102 | return NULL; 103 | } 104 | 105 | 106 | bool 107 | hash_add(hash_table *table, tc_pool_t *pool, uint64_t key, void *data) 108 | { 109 | hash_node *hn, *tmp; 110 | link_list *l; 111 | p_link_node ln; 112 | 113 | ln = hash_find_link_node(table, key); 114 | if (ln == NULL) { 115 | tmp = hash_node_malloc(pool, key, data); 116 | if (tmp != NULL) { 117 | l = get_link_list(table, key); 118 | ln = link_node_malloc(pool, tmp); 119 | if (ln != NULL) { 120 | link_list_push(l, ln); 121 | table->total++; 122 | return true; 123 | } else { 124 | return false; 125 | } 126 | } else { 127 | return false; 128 | } 129 | } else { 130 | hn = (hash_node *) ln->data; 131 | hn->data = data; 132 | return false; 133 | } 134 | } 135 | 136 | 137 | bool 138 | hash_del(hash_table *table, tc_pool_t *pool, uint64_t key) 139 | { 140 | link_list *l = get_link_list(table, key); 141 | p_link_node ln = hash_find_link_node(table, key); 142 | 143 | if (ln != NULL) { 144 | table->total--; 145 | link_list_remove(l, ln); 146 | tc_pfree(pool, ln->data); 147 | tc_pfree(pool, ln); 148 | return true; 149 | } else { 150 | 151 | return false; 152 | } 153 | } 154 | 155 | 156 | -------------------------------------------------------------------------------- /src/core/tc_hash.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_HASH_INCLUDED 2 | #define TC_HASH_INCLUDED 3 | 4 | #include 5 | 6 | typedef struct hash_node_s{ 7 | uint64_t key; 8 | void *data; 9 | time_t create_time; 10 | time_t access_time; 11 | }hash_node_t, hash_node; 12 | 13 | typedef struct hash_table_s{ 14 | tc_pool_t *pool; 15 | link_list **lists; 16 | uint32_t total; 17 | uint32_t size; 18 | }hash_table_t, hash_table; 19 | 20 | hash_table *hash_create(tc_pool_t *pool, uint32_t size); 21 | 22 | static inline uint32_t 23 | get_slot(uint64_t key, uint32_t size) 24 | { 25 | uint32_t trim_key = key & (0xFFFFFFFF); 26 | 27 | return trim_key % size; 28 | } 29 | 30 | 31 | static inline link_list_t * 32 | get_link_list(hash_table *table, uint64_t key) 33 | { 34 | uint32_t slot = get_slot(key, table->size); 35 | return table->lists[slot]; 36 | } 37 | 38 | 39 | bool hash_add(hash_table*, tc_pool_t*, uint64_t, void *); 40 | void *hash_find(hash_table*, uint64_t); 41 | hash_node *hash_find_node(hash_table *, uint64_t); 42 | bool hash_del(hash_table*, tc_pool_t*, uint64_t); 43 | 44 | #endif /* TC_HASH_INCLUDED */ 45 | 46 | -------------------------------------------------------------------------------- /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 void 40 | link_list_push(link_list *l, p_link_node p) 41 | { 42 | p_link_node node; 43 | 44 | node = l->head.next; 45 | node->prev = p; 46 | p->next = node; 47 | l->head.next = p; 48 | p->prev = &(l->head); 49 | l->size++; 50 | } 51 | 52 | 53 | static inline p_link_node 54 | link_list_remove(link_list *l, p_link_node node) 55 | { 56 | p_link_node next, prev; 57 | 58 | next = node->next; 59 | prev = node->prev; 60 | next->prev = prev; 61 | prev->next = next; 62 | l->size--; 63 | return node; 64 | } 65 | 66 | 67 | static inline p_link_node 68 | link_list_first(link_list *l) 69 | { 70 | if (l == NULL || l->head.next == &(l->head)) { 71 | return NULL; 72 | } 73 | 74 | return l->head.next; 75 | } 76 | 77 | 78 | static inline p_link_node 79 | link_list_tail(link_list *l) 80 | { 81 | if (l == NULL || l->head.next == &(l->head)) { 82 | return NULL; 83 | } 84 | 85 | return l->head.prev; 86 | } 87 | 88 | 89 | static inline p_link_node 90 | link_list_get_next(link_list *l, p_link_node p) 91 | { 92 | if (p->next == &(l->head)) { 93 | return NULL; 94 | } 95 | 96 | return p->next; 97 | } 98 | 99 | #endif /* TC_LINK_LIST_INCLUDED */ 100 | 101 | -------------------------------------------------------------------------------- /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 | 24 | static int 25 | tc_vscnprintf(char *buf, size_t size, const char *fmt, va_list args) 26 | { 27 | int i; 28 | 29 | /* 30 | * Attention for vsnprintf: http://lwn.net/Articles/69419/ 31 | */ 32 | i = vsnprintf(buf, size, fmt, args); 33 | 34 | if (i < (int) size) { 35 | return i; 36 | } 37 | 38 | if (size >= 1) { 39 | return size - 1; 40 | } else { 41 | return 0; 42 | } 43 | } 44 | 45 | 46 | static int 47 | tc_scnprintf(char *buf, size_t size, const char *fmt, ...) 48 | { 49 | int i; 50 | va_list args; 51 | 52 | va_start(args, fmt); 53 | i = tc_vscnprintf(buf, size, fmt, args); 54 | va_end(args); 55 | 56 | return i; 57 | } 58 | 59 | int 60 | tc_log_init(const char *file) 61 | { 62 | int len; 63 | char default_file_path[256], *p; 64 | 65 | if (file == NULL) { 66 | len = strlen(TC_PREFIX); 67 | if (len >= 256) { 68 | fprintf(stderr, "file prefix too long: %s\n", TC_PREFIX); 69 | return -1; 70 | } 71 | strncpy(default_file_path, TC_PREFIX, len); 72 | p = default_file_path + len; 73 | len += strlen(TC_ERROR_LOG_PATH); 74 | if (len >= 256) { 75 | fprintf(stderr, "file path too long: %s\n", TC_PREFIX); 76 | return -1; 77 | } 78 | strcpy(p, TC_ERROR_LOG_PATH); 79 | file = default_file_path; 80 | } 81 | 82 | log_fd = open(file, O_RDWR|O_CREAT|O_APPEND, 0644); 83 | 84 | if (log_fd == -1) { 85 | fprintf(stderr, "Open log file:%s error: %s\n", file, strerror(errno)); 86 | } 87 | 88 | return log_fd; 89 | } 90 | 91 | 92 | void 93 | tc_log_end(void) 94 | { 95 | if (log_fd != -1) { 96 | close(log_fd); 97 | } 98 | 99 | log_fd = -1; 100 | } 101 | 102 | 103 | void 104 | tc_log_info(int level, int err, const char *fmt, ...) 105 | { 106 | int n, len; 107 | char buffer[LOG_MAX_LEN], *p; 108 | va_list args; 109 | tc_log_level_t *ll; 110 | 111 | if (log_fd == -1) { 112 | return; 113 | } 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 | if (write(log_fd, buffer, p - buffer) == -1) { 148 | fprintf(stderr, "write error: %s\n", strerror(errno)); 149 | } 150 | } 151 | 152 | 153 | void 154 | tc_log_trace(int level, int err, int flag, tc_iph_t *ip, tc_tcph_t *tcp) 155 | { 156 | char *tmp_buf, src_ip[BUF_LEN] = {0}, dst_ip[BUF_LEN] = {0}; 157 | uint32_t pack_size; 158 | unsigned int seq, ack_seq; 159 | struct in_addr src_addr, dst_addr; 160 | 161 | src_addr.s_addr = ip->saddr; 162 | tmp_buf = inet_ntoa(src_addr); 163 | strncpy(src_ip, tmp_buf, BUF_LEN - 1); 164 | 165 | dst_addr.s_addr = ip->daddr; 166 | tmp_buf = inet_ntoa(dst_addr); 167 | strncpy(dst_ip, tmp_buf, BUF_LEN - 1); 168 | 169 | pack_size = ntohs(ip->tot_len); 170 | seq = ntohl(tcp->seq); 171 | ack_seq = ntohl(tcp->ack_seq); 172 | 173 | if (flag == TC_BAK) { 174 | tc_log_info(level, err, 175 | "from bak:%s:%u-->%s:%u,len %u,seq=%u,ack=%u", 176 | src_ip, ntohs(tcp->source), dst_ip, 177 | ntohs(tcp->dest), pack_size, seq, ack_seq); 178 | 179 | } else if (flag == TC_CLT) { 180 | tc_log_info(level, err, 181 | "recv clt:%s:%u-->%s:%u,len %u,seq=%u,ack=%u", 182 | src_ip, ntohs(tcp->source), dst_ip, 183 | ntohs(tcp->dest), pack_size, seq, ack_seq); 184 | 185 | } else if (flag == TC_TO_BAK) { 186 | tc_log_info(level, err, 187 | "to bak:%s:%u-->%s:%u,len %u,seq=%u,ack=%u", 188 | src_ip, ntohs(tcp->source), dst_ip, 189 | ntohs(tcp->dest), pack_size, seq, ack_seq); 190 | 191 | } else if (flag == TC_UNKNOWN) { 192 | tc_log_info(level, err, 193 | "unknown packet:%s:%u-->%s:%u,len %u,seq=%u,ack=%u", 194 | src_ip, ntohs(tcp->source), dst_ip, 195 | ntohs(tcp->dest), pack_size, 196 | seq, ack_seq); 197 | 198 | } else { 199 | tc_log_info(level, err, 200 | "strange %s:%u-->%s:%u,length %u,seq=%u,ack=%u", 201 | src_ip, ntohs(tcp->source), dst_ip, 202 | ntohs(tcp->dest), pack_size, 203 | seq, ack_seq); 204 | } 205 | } 206 | 207 | -------------------------------------------------------------------------------- /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(const char *); 20 | void tc_log_end(void); 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, tc_tcph_t *tcp); 24 | 25 | #if (TC_DEBUG) 26 | 27 | #define tc_log_debug0(level, err, fmt) \ 28 | tc_log_info(level, err, (const char *) fmt) 29 | 30 | #define tc_log_debug1(level, err, fmt, a1) \ 31 | tc_log_info(level, err, (const char *) fmt, a1) 32 | 33 | #define tc_log_debug2(level, err, fmt, a1, a2) \ 34 | tc_log_info(level, err, (const char *) fmt, a1, a2) 35 | 36 | #define tc_log_debug3(level, err, fmt, a1, a2, a3) \ 37 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3) 38 | 39 | #define tc_log_debug4(level, err, fmt, a1, a2, a3, a4) \ 40 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3, a4) 41 | 42 | #define tc_log_debug5(level, err, fmt, a1, a2, a3, a4, a5) \ 43 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3, a4, a5) 44 | 45 | #define tc_log_debug6(level, err, fmt, a1, a2, a3, a4, a5, a6) \ 46 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3, a4, a5, a6) 47 | 48 | #define tc_log_debug7(level, err, fmt, a1, a2, a3, a4, a5, a6, a7) \ 49 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3, a4, a5, a6, a7) 50 | 51 | #define tc_log_debug8(level, err, fmt, a1, a2, a3, a4, a5, a6, a7, a8) \ 52 | tc_log_info(level, err, (const char *) fmt, a1, a2, a3, a4, a5, a6, a7, a8) 53 | 54 | #define tc_log_debug_trace(level, err, flag, ip, tcp) \ 55 | tc_log_trace(level, err, flag, ip, tcp) 56 | 57 | #else 58 | 59 | #define tc_log_debug0(level, err, fmt) 60 | #define tc_log_debug1(level, err, fmt, a1) 61 | #define tc_log_debug2(level, err, fmt, a1, a2) 62 | #define tc_log_debug3(level, err, fmt, a1, a2, a3) 63 | #define tc_log_debug4(level, err, fmt, a1, a2, a3, a4) 64 | #define tc_log_debug5(level, err, fmt, a1, a2, a3, a4, a5) 65 | #define tc_log_debug6(level, err, fmt, a1, a2, a3, a4, a5, a6) 66 | #define tc_log_debug7(level, err, fmt, a1, a2, a3, a4, a5, a6, a7) 67 | #define tc_log_debug8(level, err, fmt, a1, a2, a3, a4, a5, a6, a7, a8) 68 | #define tc_log_debug_trace(level, err, flag, ip, tcp) 69 | 70 | #endif /* TC_DEBUG */ 71 | 72 | #endif /* TC_LOG_INCLUDED */ 73 | 74 | 75 | -------------------------------------------------------------------------------- /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(int size, int sub_size, int pool_max) 10 | { 11 | tc_pool_t *p; 12 | 13 | if (size < (int) TC_MIN_POOL_SIZE) { 14 | tc_log_info(LOG_ERR, 0, "pool size must be no less than:%d", 15 | TC_MIN_POOL_SIZE); 16 | size = TC_MIN_POOL_SIZE; 17 | } 18 | 19 | p = tc_memalign(TC_POOL_ALIGNMENT, size); 20 | if (p != NULL) { 21 | p->d.last = (u_char *) p + sizeof(tc_pool_t); 22 | p->d.end = (u_char *) p + size; 23 | p->d.next = NULL; 24 | p->d.failed = 0; 25 | p->d.objs = 0; 26 | p->d.need_check = 0; 27 | p->d.cand_recycle = 0; 28 | p->d.is_traced = 0; 29 | p->main_size = size; 30 | if (sub_size > (int) TC_MIN_POOL_SIZE) { 31 | p->sub_size = sub_size; 32 | } else { 33 | p->sub_size = p->main_size; 34 | } 35 | 36 | size = size - sizeof(tc_pool_t); 37 | 38 | if (pool_max && size >= pool_max) { 39 | p->sh_num.max = pool_max; 40 | } else { 41 | p->sh_num.max = (size < (int) TC_MAX_ALLOC_FROM_POOL) ? 42 | size : (int) TC_MAX_ALLOC_FROM_POOL; 43 | } 44 | 45 | p->current = p; 46 | p->sh_pt.large = NULL; 47 | } 48 | 49 | return p; 50 | } 51 | 52 | 53 | void 54 | tc_destroy_pool(tc_pool_t *pool) 55 | { 56 | #if (TC_DEBUG) 57 | int tot_size, sub_size; 58 | #endif 59 | tc_pool_t *p, *n; 60 | tc_pool_large_t *l; 61 | 62 | for (l = pool->sh_pt.large; l; l = l->next) { 63 | 64 | if (l->alloc) { 65 | tc_free(l->alloc); 66 | } 67 | } 68 | 69 | #if (TC_DEBUG) 70 | tot_size = pool->main_size - pool->sub_size; 71 | sub_size = pool->sub_size; 72 | #endif 73 | for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { 74 | #if (TC_DEBUG) 75 | tot_size += sub_size; 76 | #endif 77 | tc_free(p); 78 | 79 | if (n == NULL) { 80 | break; 81 | } 82 | } 83 | 84 | #if (TC_DEBUG) 85 | tc_log_info(LOG_NOTICE, 0, "pool occupy:%d", tot_size); 86 | #endif 87 | 88 | } 89 | 90 | 91 | void * 92 | tc_palloc(tc_pool_t *pool, size_t size) 93 | { 94 | u_char *m; 95 | tc_pool_t *p; 96 | tc_mem_hid_info_t *hid; 97 | 98 | size = size + MEM_HID_INFO_SZ; 99 | 100 | if ((int) size <= pool->sh_num.max) { 101 | 102 | p = pool->current; 103 | 104 | do { 105 | m = tc_align_ptr(p->d.last, TC_ALIGNMENT); 106 | 107 | if ((size_t) (p->d.end - m) >= size) { 108 | #if (TC_DETECT_MEMORY) 109 | if (p->d.last >= p->d.end) { 110 | tc_log_info(LOG_WARN, 0, "pool full"); 111 | } 112 | #endif 113 | p->d.objs++; 114 | p->d.last = m + size; 115 | hid = (tc_mem_hid_info_t *) m; 116 | hid->large = 0; 117 | hid->len = size; 118 | hid->try_rel_cnt = 0; 119 | hid->released = 0; 120 | 121 | return m + MEM_HID_INFO_SZ; 122 | } 123 | 124 | p = p->d.next; 125 | 126 | } while (p); 127 | 128 | m = tc_palloc_block(pool, size); 129 | if (m != NULL) { 130 | hid = (tc_mem_hid_info_t *) m; 131 | hid->large = 0; 132 | hid->len = size; 133 | hid->try_rel_cnt = 0; 134 | hid->released = 0; 135 | return m + MEM_HID_INFO_SZ; 136 | } else { 137 | return NULL; 138 | } 139 | } 140 | 141 | m = tc_palloc_large(pool, size); 142 | if (m != NULL) { 143 | hid = (tc_mem_hid_info_t *) m; 144 | hid->large = 1; 145 | hid->len = size; 146 | hid->try_rel_cnt = 0; 147 | hid->released = 0; 148 | return m + MEM_HID_INFO_SZ; 149 | } else { 150 | return NULL; 151 | } 152 | } 153 | 154 | 155 | static bool 156 | tc_check_block_free(tc_pool_t *root, tc_pool_t *p) 157 | { 158 | int i; 159 | u_char *m; 160 | tc_mem_hid_info_t *hid; 161 | 162 | if (p->sh_pt.fp) { 163 | m = (u_char *) p->sh_pt.fp; 164 | i = p->sh_num.fn; 165 | #if (TC_DETECT_MEMORY) 166 | if (root->d.is_traced) { 167 | tc_log_info(LOG_INFO, 0, "pool:%p,block:%p,m from last:%p, i:%d", 168 | root, p, m, i); 169 | } 170 | #endif 171 | 172 | } else { 173 | m = ((u_char *) p) + sizeof(tc_pool_t); 174 | m = tc_align_ptr(m, TC_ALIGNMENT); 175 | i = 0; 176 | } 177 | 178 | while (m < p->d.end) { 179 | hid = (tc_mem_hid_info_t *) m; 180 | if (!hid->released) { 181 | p->sh_pt.fp = hid; 182 | p->sh_num.fn = i; 183 | hid->try_rel_cnt++; 184 | #if (TC_DETECT_MEMORY) 185 | if (hid->try_rel_cnt == REL_CNT_MAX_VALUE) { 186 | tc_log_info(LOG_INFO, 0, "pool:%p,block:%p,len:%u occupy", 187 | root, p, hid->len); 188 | } 189 | #endif 190 | return false; 191 | } 192 | m += hid->len; 193 | m = tc_align_ptr(m, TC_ALIGNMENT); 194 | i++; 195 | 196 | if (i == p->d.objs) { 197 | break; 198 | } 199 | } 200 | 201 | return true; 202 | } 203 | 204 | 205 | static void * 206 | tc_palloc_block(tc_pool_t *pool, size_t size) 207 | { 208 | bool reused; 209 | u_char *m; 210 | size_t psize; 211 | tc_pool_t *p, *new, *current; 212 | 213 | reused = false; 214 | 215 | p = pool->d.next; 216 | if (p && p->d.cand_recycle) { 217 | if (tc_check_block_free(pool, p)) { 218 | reused = true; 219 | m = (u_char *) p; 220 | new = p; 221 | pool->d.next = p->d.next; 222 | #if (TC_DETECT_MEMORY) 223 | if (pool->d.is_traced) { 224 | tc_log_info(LOG_INFO, 0, "pool:%p recycle:%p", pool, p); 225 | } 226 | #endif 227 | } 228 | } 229 | 230 | if (!reused) { 231 | if (pool->sub_size) { 232 | psize = pool->sub_size; 233 | } else { 234 | psize = (size_t) (pool->d.end - (u_char *) pool); 235 | } 236 | m = tc_memalign(TC_POOL_ALIGNMENT, psize); 237 | 238 | if (m == NULL) { 239 | return NULL; 240 | } 241 | 242 | #if (TC_DETECT_MEMORY) 243 | if (pool->d.is_traced) { 244 | tc_log_info(LOG_INFO, 0, "pare pool:%p, create pool:%p, size:%d", 245 | pool, m, (int) psize); 246 | } 247 | #endif 248 | 249 | new = (tc_pool_t *) m; 250 | new->d.end = m + psize; 251 | } 252 | 253 | new->d.next = NULL; 254 | new->d.failed = 0; 255 | new->d.objs = 1; 256 | new->d.need_check = 1; 257 | new->d.cand_recycle = 0; 258 | new->d.is_traced = 0; 259 | new->sh_pt.fp = NULL; 260 | new->sh_num.fn = 0; 261 | 262 | m += sizeof(tc_pool_t); 263 | m = tc_align_ptr(m, TC_ALIGNMENT); 264 | new->d.last = m + size; 265 | 266 | #if (TC_DETECT_MEMORY) 267 | if (new->d.last > new->d.end) { 268 | tc_log_info(LOG_WARN, 0, "pool overflow"); 269 | } 270 | #endif 271 | 272 | current = pool->current; 273 | 274 | if (current) { 275 | for (p = current; p->d.next; p = p->d.next) { 276 | if (p->d.failed++ > 4) { 277 | if (p->d.need_check) { 278 | p->d.cand_recycle = 1; 279 | } 280 | current = p->d.next; 281 | } 282 | } 283 | 284 | p->d.next = new; 285 | } 286 | 287 | pool->current = current ? current : new; 288 | 289 | return m; 290 | } 291 | 292 | 293 | static void * 294 | tc_palloc_large(tc_pool_t *pool, size_t size) 295 | { 296 | void *p; 297 | tc_pool_large_t *large; 298 | 299 | p = tc_alloc(size); 300 | if (p != NULL) { 301 | large = tc_palloc(pool, sizeof(tc_pool_large_t)); 302 | if (large == NULL) { 303 | tc_free(p); 304 | return NULL; 305 | } 306 | 307 | large->alloc = p; 308 | large->next = pool->sh_pt.large; 309 | pool->sh_pt.large = large; 310 | } 311 | 312 | return p; 313 | } 314 | 315 | 316 | tc_int_t 317 | tc_pfree(tc_pool_t *pool, void *p) 318 | { 319 | tc_pool_large_t *l, *prev; 320 | tc_mem_hid_info_t *act_p; 321 | 322 | if (p == NULL) 323 | return TC_OK; 324 | 325 | act_p = (tc_mem_hid_info_t *) ((u_char *) p - MEM_HID_INFO_SZ); 326 | 327 | if (act_p->large) { 328 | prev = NULL; 329 | for (l = pool->sh_pt.large; l; l = l->next) { 330 | if (act_p == l->alloc) { 331 | tc_free(l->alloc); 332 | l->alloc = NULL; 333 | 334 | if (prev) { 335 | prev->next = l->next; 336 | } else { 337 | pool->sh_pt.large = l->next; 338 | } 339 | 340 | act_p = (tc_mem_hid_info_t *) ((u_char *) l - MEM_HID_INFO_SZ); 341 | act_p->released = 1; 342 | #if (TC_DETECT_MEMORY) 343 | if (act_p->len != TC_LARGE_OBJ_INFO_SIZE) { 344 | tc_log_info(LOG_WARN, 0, "pool item wrong:%d != %d", 345 | act_p->len, TC_LARGE_OBJ_INFO_SIZE); 346 | } 347 | #endif 348 | 349 | return TC_OK; 350 | } 351 | prev = l; 352 | } 353 | 354 | #if (TC_DETECT_MEMORY) 355 | if (l == NULL) { 356 | tc_log_info(LOG_WARN, 0, "pool item not freed"); 357 | } 358 | #endif 359 | } else { 360 | act_p->released = 1; 361 | } 362 | 363 | return TC_DELAYED; 364 | } 365 | 366 | 367 | 368 | void * 369 | tc_pcalloc(tc_pool_t *pool, size_t size) 370 | { 371 | void *p; 372 | 373 | p = tc_palloc(pool, size); 374 | if (p) { 375 | tc_memzero(p, size); 376 | } 377 | 378 | return p; 379 | } 380 | 381 | 382 | -------------------------------------------------------------------------------- /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 | typedef struct tc_pool_loop_s tc_pool_loop_t; 9 | 10 | struct tc_pool_large_s { 11 | tc_pool_large_t *next; 12 | void *alloc; 13 | }; 14 | 15 | typedef struct { 16 | uint32_t len:24; 17 | uint32_t try_rel_cnt:6; 18 | uint32_t large:1; 19 | uint32_t released:1; 20 | uint32_t padding; 21 | } tc_mem_hid_info_t; 22 | 23 | typedef struct { 24 | u_char *last; 25 | u_char *end; 26 | tc_pool_t *next; 27 | uint32_t objs:16; 28 | uint32_t failed:8; 29 | uint32_t need_check:1; 30 | uint32_t cand_recycle:1; 31 | uint32_t is_traced:1; 32 | } tc_pool_data_t; 33 | 34 | 35 | struct tc_pool_s { 36 | tc_pool_data_t d; 37 | union { 38 | int max; 39 | int fn; 40 | } sh_num; 41 | int main_size; 42 | int sub_size; 43 | tc_pool_t *current; 44 | union { 45 | tc_mem_hid_info_t *fp; 46 | tc_pool_large_t *large; 47 | } sh_pt; 48 | }; 49 | 50 | 51 | tc_pool_t *tc_create_pool(int size, int sub_size, int pool_max); 52 | void tc_destroy_pool(tc_pool_t *pool); 53 | 54 | void *tc_palloc(tc_pool_t *pool, size_t size); 55 | void *tc_pcalloc(tc_pool_t *pool, size_t size); 56 | tc_int_t tc_pfree(tc_pool_t *pool, void *p); 57 | 58 | 59 | 60 | #endif /* _TC_PALLOC_H_INCLUDED_ */ 61 | -------------------------------------------------------------------------------- /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 | tc_memzero(&sa, 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 | volatile char *tc_error_log_time; 5 | volatile time_t tc_current_time_sec; 6 | volatile long tc_current_time_msec; 7 | volatile struct tm tc_current_tm; 8 | 9 | static char cache_err_log_time[TC_ERR_LOG_TIME_STR_LEN]; 10 | 11 | void 12 | tc_time_init(void) 13 | { 14 | tc_time_update(); 15 | } 16 | 17 | 18 | void 19 | tc_time_update() 20 | { 21 | int status; 22 | long msec; 23 | time_t sec; 24 | struct tm tm; 25 | struct timeval tv; 26 | 27 | status = gettimeofday(&tv, NULL); 28 | if (status >= 0) { 29 | sec = tv.tv_sec; 30 | msec = tv.tv_usec / 1000; 31 | 32 | tc_current_time_sec = sec; 33 | tc_current_time_msec = sec * 1000 + msec; 34 | 35 | tc_localtime(sec, &tm); 36 | 37 | snprintf(cache_err_log_time, TC_ERR_LOG_TIME_STR_LEN, 38 | "%4d/%02d/%02d %02d:%02d:%02d +%03d", 39 | tm.tm_year, tm.tm_mon, 40 | tm.tm_mday, tm.tm_hour, 41 | tm.tm_min, tm.tm_sec, 42 | (int) msec); 43 | 44 | tc_current_tm = tm; 45 | tc_error_log_time = cache_err_log_time; 46 | 47 | } else { 48 | tc_log_info(LOG_ERR, errno, "gettimeofday failed"); 49 | } 50 | } 51 | 52 | 53 | void 54 | tc_localtime(time_t sec, struct tm *tm) 55 | { 56 | #if (HAVE_LOCALTIME_R) 57 | (void) localtime_r(&sec, tm); 58 | #else 59 | struct tm *t; 60 | 61 | t = localtime(&sec); 62 | *tm = *t; 63 | #endif 64 | 65 | tm->tm_mon++; 66 | tm->tm_year += 1900; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /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(void); 21 | void tc_time_update(void); 22 | void tc_localtime(time_t sec, struct tm *tm); 23 | 24 | #endif /* TC_TIME_INCLUDED */ 25 | -------------------------------------------------------------------------------- /src/digest/tc_evp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if (TC_DIGEST) 4 | 5 | #include 6 | 7 | 8 | static const EVP_MD *md; 9 | static EVP_MD_CTX sha1_ctx; 10 | static int digests_init = 0; 11 | static int sha1_init = 0; 12 | 13 | int 14 | tc_init_digests() 15 | { 16 | OpenSSL_add_all_digests(); 17 | digests_init = 1; 18 | return 1; 19 | } 20 | 21 | 22 | int 23 | tc_destroy_digests() 24 | { 25 | if (digests_init) { 26 | EVP_cleanup(); 27 | digests_init = 0; 28 | } 29 | 30 | return 1; 31 | } 32 | 33 | 34 | int 35 | tc_init_sha1() 36 | { 37 | md = EVP_get_digestbyname(ALGO_SHA1); 38 | 39 | if (!md) { 40 | tc_log_info(LOG_ERR, 0, "%s is not supported", ALGO_SHA1); 41 | return 0; 42 | } 43 | 44 | sha1_init = 1; 45 | EVP_MD_CTX_init(&sha1_ctx); 46 | 47 | return 1; 48 | } 49 | 50 | 51 | int 52 | tc_destroy_sha1() 53 | { 54 | if (sha1_init) { 55 | EVP_MD_CTX_cleanup(&sha1_ctx); 56 | sha1_init = 0; 57 | } 58 | 59 | return 1; 60 | } 61 | 62 | 63 | static void 64 | tc_tailor(unsigned char *dest, unsigned int dest_len, 65 | const unsigned char *hash, unsigned int hash_len) 66 | { 67 | unsigned int i; 68 | 69 | if (dest_len > hash_len) { 70 | return; 71 | } 72 | 73 | for (i = 0; i < dest_len; i++) { 74 | dest[i] = hash[i]; 75 | } 76 | } 77 | 78 | 79 | int 80 | tc_sha1_digest_one(unsigned char *dest, unsigned int dest_len, 81 | const unsigned char *seed, unsigned int seed_len) 82 | { 83 | unsigned int sha1_value_len; 84 | unsigned char sha1_value[EVP_MAX_MD_SIZE]; 85 | 86 | if (!sha1_init) { 87 | return 0; 88 | } 89 | 90 | EVP_DigestInit_ex(&sha1_ctx, md, NULL); 91 | EVP_DigestUpdate(&sha1_ctx, seed, seed_len); 92 | EVP_DigestFinal_ex(&sha1_ctx, sha1_value, &sha1_value_len); 93 | 94 | tc_tailor(dest, dest_len, sha1_value, sha1_value_len); 95 | 96 | return 1; 97 | } 98 | 99 | 100 | int 101 | tc_sha1_digest_two(unsigned char *dest, unsigned int dest_len, 102 | const unsigned char *seed1, unsigned int seed1_len, 103 | const unsigned char *seed2, unsigned int seed2_len) 104 | { 105 | unsigned int sha1_value_len; 106 | unsigned char sha1_value[EVP_MAX_MD_SIZE]; 107 | 108 | if (!sha1_init) { 109 | tc_log_info(LOG_ERR, 0, "%s not init", ALGO_SHA1); 110 | return 0; 111 | } 112 | 113 | EVP_DigestInit_ex(&sha1_ctx, md, NULL); 114 | EVP_DigestUpdate(&sha1_ctx, seed1, seed1_len); 115 | EVP_DigestUpdate(&sha1_ctx, seed2, seed2_len); 116 | EVP_DigestFinal_ex(&sha1_ctx, sha1_value, &sha1_value_len); 117 | 118 | tc_tailor(dest, dest_len, sha1_value, sha1_value_len); 119 | 120 | return 1; 121 | } 122 | 123 | #endif 124 | 125 | -------------------------------------------------------------------------------- /src/digest/tc_evp.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_EVP_INCLUDED 2 | #define TC_EVP_INCLUDED 3 | 4 | 5 | #if (TC_DIGEST) 6 | #define ALGO_SHA1 "sha1" 7 | int tc_init_digests(); 8 | int tc_destroy_digests(); 9 | int tc_init_sha1(); 10 | int tc_destroy_sha1(); 11 | int tc_sha1_digest_one(unsigned char *dest, unsigned int dest_len, 12 | const unsigned char *seed, unsigned int seed_len); 13 | int tc_sha1_digest_two(unsigned char *dest, unsigned int dest_len, 14 | const unsigned char *seed1, unsigned int seed1_len, 15 | const unsigned char *seed2, unsigned int seed2_len); 16 | #endif 17 | 18 | #endif /* ----- #ifndef TC_EVP_INCLUDED ----- */ 19 | 20 | -------------------------------------------------------------------------------- /src/event/tc_epoll_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int tc_epoll_create(tc_event_loop_t *loop) 5 | { 6 | int efd = -1; 7 | tc_event_t **evs; 8 | struct epoll_event *events = NULL; 9 | tc_epoll_multiplex_io_t *io; 10 | 11 | evs = tc_pcalloc(loop->pool, loop->size * sizeof(tc_event_t *)); 12 | if (evs == NULL) { 13 | return TC_EVENT_ERROR; 14 | } 15 | 16 | io = tc_palloc(loop->pool, sizeof(tc_epoll_multiplex_io_t)); 17 | if (io == NULL) { 18 | goto bad; 19 | } 20 | 21 | efd = epoll_create(MAX_FD_NUM); 22 | if(efd == -1) { 23 | tc_log_info(LOG_ERR, 0, "epoll_create failed!"); 24 | goto bad; 25 | } 26 | 27 | events = tc_pcalloc(loop->pool, (MAX_FD_NUM * sizeof(struct epoll_event))); 28 | if(events == NULL) { 29 | tc_log_info(LOG_ERR, 0, "tc_pcalloc struct epoll_event failed!"); 30 | goto bad; 31 | } 32 | 33 | io->max_fd = -1; 34 | io->efd = efd; 35 | io->events = events; 36 | io->evs = evs; 37 | 38 | loop->io = io; 39 | 40 | return TC_EVENT_OK; 41 | 42 | bad: 43 | tc_pfree(loop->pool, evs); 44 | tc_pfree(loop->pool, io); 45 | tc_pfree(loop->pool, events); 46 | if (efd != -1) { 47 | close(efd); 48 | } 49 | 50 | return TC_EVENT_ERROR; 51 | } 52 | 53 | 54 | int tc_epoll_destroy(tc_event_loop_t *loop) 55 | { 56 | int i; 57 | tc_event_t *event; 58 | tc_epoll_multiplex_io_t *io; 59 | 60 | io = loop->io; 61 | 62 | for (i = 0; i <= io->max_fd; i++) { 63 | event = io->evs[i]; 64 | if (event != NULL) { 65 | if (event->fd > 0) { 66 | tc_log_info(LOG_NOTICE, 0, "tc_epoll_destroy, close fd:%d", 67 | event->fd); 68 | tc_socket_close(event->fd); 69 | event->fd = -1; 70 | tc_pfree(loop->pool, event); 71 | } else { 72 | tc_log_info(LOG_WARN, 0, "tc_epoll_destroy, fd < 0:%d", 73 | event->fd); 74 | tc_pfree(loop->pool, event); 75 | } 76 | } 77 | } 78 | 79 | if (io->efd) { 80 | close(io->efd); 81 | io->efd = -1; 82 | } 83 | io->max_fd = -1; 84 | 85 | tc_pfree(loop->pool, io->events); 86 | tc_pfree(loop->pool, io->evs); 87 | tc_pfree(loop->pool, loop->io); 88 | 89 | return TC_EVENT_OK; 90 | } 91 | 92 | 93 | int tc_epoll_add_event(tc_event_loop_t *loop, tc_event_t *ev, int events) 94 | { 95 | struct epoll_event event; 96 | tc_epoll_multiplex_io_t *io; 97 | 98 | io = loop->io; 99 | 100 | if (events == TC_EVENT_NONE) { 101 | return TC_EVENT_OK; 102 | } 103 | 104 | if (io->max_fd >= loop->size || ev->fd >= loop->size) { 105 | /* too many */ 106 | errno = ERANGE; 107 | return TC_EVENT_ERROR; 108 | } 109 | 110 | if ((events == TC_EVENT_READ && ev->read_handler 111 | && ev->write_handler == NULL)) 112 | { 113 | event.data.u64 = 0; 114 | event.data.fd = ev->fd; 115 | event.events = EPOLLIN; 116 | if(epoll_ctl(io->efd, EPOLL_CTL_ADD, ev->fd, &event) == -1) { 117 | tc_log_info(LOG_ALERT, 0, "epoll_ctl add read fd failed."); 118 | return TC_EVENT_ERROR; 119 | } 120 | } else if (events == TC_EVENT_WRITE && ev->write_handler 121 | && ev->read_handler == NULL) 122 | { 123 | event.data.u64 = 0; 124 | event.data.fd = ev->fd; 125 | event.events = EPOLLOUT; 126 | if(epoll_ctl(io->efd, EPOLL_CTL_ADD, ev->fd, &event) == -1) { 127 | tc_log_info(LOG_ALERT, 0, "epoll_ctl add write fd failed."); 128 | return TC_EVENT_ERROR; 129 | } 130 | } else { 131 | return TC_EVENT_ERROR; 132 | } 133 | 134 | io->evs[ev->fd] = ev; 135 | 136 | if(ev->fd >= io->max_fd) { 137 | io->max_fd = ev->fd; 138 | } 139 | 140 | return TC_EVENT_OK; 141 | } 142 | 143 | 144 | int tc_epoll_del_event(tc_event_loop_t *loop, tc_event_t *ev, int delevents) 145 | { 146 | int events; 147 | struct epoll_event event; 148 | tc_epoll_multiplex_io_t *io; 149 | 150 | events = ev->reg_evs & (~ delevents); 151 | 152 | io = loop->io; 153 | 154 | if (ev->fd >= loop->size || ev->fd > io->max_fd) { 155 | errno = ERANGE; 156 | return TC_EVENT_ERROR; 157 | } 158 | 159 | event.events = 0; 160 | if (events & TC_EVENT_READ) { 161 | event.events |= EPOLLIN; 162 | } 163 | 164 | if (events & TC_EVENT_WRITE) { 165 | event.events |= EPOLLOUT; 166 | } 167 | 168 | event.data.u64 = 0; 169 | event.data.fd = ev->fd; 170 | 171 | if (events != TC_EVENT_NONE) { 172 | epoll_ctl(io->efd, EPOLL_CTL_MOD, ev->fd, &event); 173 | } else { 174 | epoll_ctl(io->efd, EPOLL_CTL_DEL, ev->fd, &event); 175 | } 176 | 177 | events = ev->reg_evs & (~ delevents); 178 | if (ev->fd == io->max_fd && events == TC_EVENT_NONE) { 179 | /* Update the max_fd fd */ 180 | int j; 181 | 182 | for (j = io->max_fd - 1; j >= 0; j--) { 183 | if (io->evs[j] && (io->evs[j])->reg_evs != TC_EVENT_NONE) { 184 | break; 185 | } 186 | } 187 | io->max_fd = j; 188 | } 189 | 190 | return TC_EVENT_OK; 191 | } 192 | 193 | 194 | int tc_epoll_polling(tc_event_loop_t *loop, long to) 195 | { 196 | int i, ret; 197 | long timeout; 198 | tc_event_t **evs; 199 | struct epoll_event *events; 200 | tc_epoll_multiplex_io_t *io; 201 | 202 | io = loop->io; 203 | evs = io->evs; 204 | events = io->events; 205 | 206 | timeout = to; 207 | 208 | ret = epoll_wait(io->efd, events, MAX_FD_NUM, timeout); 209 | 210 | if (ret == -1) { 211 | if (errno == EINTR) { 212 | return TC_EVENT_AGAIN; 213 | } 214 | return TC_EVENT_ERROR; 215 | } 216 | 217 | if (ret == 0) { 218 | return TC_EVENT_AGAIN; 219 | } 220 | 221 | for (i = 0; i < ret; i++) { 222 | int mask = 0; 223 | struct epoll_event *e = events + i; 224 | int fd = e->data.fd; 225 | /* Clear the active events, and reset */ 226 | evs[fd]->events = TC_EVENT_NONE; 227 | 228 | if (e->events & EPOLLIN) { 229 | mask |= TC_EVENT_READ; 230 | } 231 | 232 | if ((e->events & EPOLLOUT) || (e->events & EPOLLERR) || 233 | (e->events & EPOLLHUP)) 234 | { 235 | mask |= TC_EVENT_WRITE; 236 | } 237 | 238 | evs[fd]->events |= mask; 239 | tc_event_push_active_event(loop->active_events, evs[fd]); 240 | } 241 | 242 | return TC_EVENT_OK; 243 | } 244 | 245 | -------------------------------------------------------------------------------- /src/event/tc_epoll_module.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_EPOLL_MODULE_INCLUDED 2 | #define TC_EPOLL_MODULE_INCLUDED 3 | 4 | #include 5 | 6 | typedef struct tc_epoll_multiplex_io_s tc_epoll_multiplex_io_t; 7 | 8 | struct tc_epoll_multiplex_io_s { 9 | int max_fd; 10 | int efd; 11 | tc_event_t **evs; 12 | struct epoll_event *events; 13 | }; 14 | 15 | int tc_epoll_create(tc_event_loop_t *loop); 16 | int tc_epoll_destroy(tc_event_loop_t *loop); 17 | int tc_epoll_add_event(tc_event_loop_t *loop, tc_event_t *ev, int events); 18 | int tc_epoll_del_event(tc_event_loop_t *loop, tc_event_t *ev, int events); 19 | int tc_epoll_polling(tc_event_loop_t *loop, long timeout); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /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 | #ifdef TC_HAVE_EPOLL 10 | tc_epoll_create, 11 | tc_epoll_destroy, 12 | tc_epoll_add_event, 13 | tc_epoll_del_event, 14 | tc_epoll_polling 15 | #else 16 | tc_select_create, 17 | tc_select_destroy, 18 | tc_select_add_event, 19 | tc_select_del_event, 20 | tc_select_polling 21 | #endif 22 | }; 23 | 24 | 25 | int tc_event_loop_init(tc_event_loop_t *loop, int size) 26 | { 27 | tc_pool_t *pool; 28 | tc_event_actions_t *actions; 29 | 30 | pool = tc_create_pool(TC_DEFAULT_POOL_SIZE, 0, 0); 31 | 32 | if (pool != NULL) { 33 | actions = &tc_event_actions; 34 | 35 | loop->actions = actions; 36 | loop->active_events = NULL; 37 | loop->pool = pool; 38 | loop->size = size; 39 | 40 | if (actions->create(loop) == TC_EVENT_ERROR) { 41 | return TC_EVENT_ERROR; 42 | } 43 | 44 | return TC_EVENT_OK; 45 | } else { 46 | return TC_EVENT_ERROR; 47 | } 48 | } 49 | 50 | 51 | int tc_event_loop_finish(tc_event_loop_t *loop) 52 | { 53 | tc_event_actions_t *actions; 54 | 55 | actions = loop->actions; 56 | 57 | if (actions != NULL) { 58 | /* destroy io module */ 59 | actions->destroy(loop); 60 | 61 | loop->actions = NULL; 62 | } 63 | 64 | if (loop->pool) { 65 | tc_destroy_pool(loop->pool); 66 | loop->pool = NULL; 67 | } 68 | 69 | return TC_EVENT_OK; 70 | } 71 | 72 | int tc_event_add(tc_event_loop_t *loop, tc_event_t *ev, int events) 73 | { 74 | tc_event_actions_t *actions; 75 | 76 | ev->loop = loop; 77 | actions = loop->actions; 78 | 79 | if (events == TC_EVENT_NONE) { 80 | return TC_EVENT_OK; 81 | } 82 | 83 | if (actions->add(loop, ev, events) == TC_EVENT_ERROR) { 84 | return TC_EVENT_ERROR; 85 | } 86 | 87 | if (events & TC_EVENT_READ) { 88 | ev->reg_evs |= TC_EVENT_READ; 89 | } 90 | 91 | if (events & TC_EVENT_WRITE) { 92 | ev->reg_evs |= TC_EVENT_WRITE; 93 | } 94 | 95 | return TC_EVENT_OK; 96 | } 97 | 98 | int tc_event_del(tc_event_loop_t *loop, tc_event_t *ev, int events) 99 | { 100 | tc_event_actions_t *actions; 101 | 102 | actions = loop->actions; 103 | 104 | if (events == TC_EVENT_NONE) { 105 | return TC_EVENT_OK; 106 | } 107 | 108 | if (actions->del(loop, ev, events) == TC_EVENT_ERROR) { 109 | return TC_EVENT_ERROR; 110 | } 111 | 112 | if (events & TC_EVENT_READ) { 113 | ev->reg_evs &= ~TC_EVENT_READ; 114 | } 115 | 116 | if (events & TC_EVENT_WRITE) { 117 | ev->reg_evs &= ~TC_EVENT_WRITE; 118 | } 119 | 120 | return TC_EVENT_OK; 121 | } 122 | 123 | 124 | int tc_event_proc_cycle(tc_event_loop_t *loop) 125 | { 126 | int ret; 127 | long timeout; 128 | tc_msec_t delta; 129 | tc_event_t *act_event, *act_next; 130 | tc_event_actions_t *actions; 131 | 132 | actions = loop->actions; 133 | 134 | for ( ;; ) { 135 | timeout = tc_event_find_timer(); 136 | if (timeout == 0 || timeout > 1000) { 137 | timeout = 500; 138 | } 139 | 140 | loop->active_events = NULL; 141 | 142 | delta = tc_current_time_msec; 143 | ret = actions->poll(loop, timeout); 144 | if (tc_over) { 145 | goto FINISH; 146 | } 147 | 148 | tc_time_update(); 149 | 150 | delta = tc_current_time_msec - delta; 151 | 152 | if (delta) { 153 | tc_event_expire_timers(); 154 | } 155 | 156 | if (ret == TC_EVENT_ERROR || ret == TC_EVENT_AGAIN) { 157 | continue; 158 | } 159 | 160 | for (act_event = loop->active_events; act_event; act_event = act_next) { 161 | act_next = act_event->next; 162 | 163 | if (act_event->events & TC_EVENT_READ) { 164 | if (act_event->read_handler && 165 | act_event->read_handler(act_event) == TC_ERR_EXIT) 166 | { 167 | goto FINISH; 168 | } 169 | } 170 | 171 | if (act_event->events & TC_EVENT_WRITE) { 172 | if (act_event->write_handler && 173 | act_event->write_handler(act_event) == TC_ERR_EXIT) 174 | { 175 | goto FINISH; 176 | } 177 | } 178 | 179 | if (act_event->reg_evs == TC_EVENT_NONE) { 180 | tc_event_destroy(act_event, 0); 181 | } 182 | } 183 | } 184 | 185 | FINISH: 186 | return TC_EVENT_OK; 187 | } 188 | 189 | 190 | tc_event_t *tc_event_create(tc_pool_t *pool, int fd, tc_event_handler_pt reader, 191 | tc_event_handler_pt writer) 192 | { 193 | tc_event_t *ev; 194 | 195 | ev = tc_palloc(pool, sizeof(tc_event_t)); 196 | 197 | if (ev != NULL) { 198 | ev->events = 0; 199 | ev->reg_evs = 0; 200 | ev->index = -1; 201 | ev->fd = fd; 202 | ev->next = NULL; 203 | ev->read_handler = reader; 204 | ev->write_handler = writer; 205 | } 206 | 207 | return ev; 208 | } 209 | 210 | static void tc_event_destroy_with_no_delay(tc_pool_t *pool, tc_event_t *ev) 211 | { 212 | tc_log_info(LOG_NOTICE, 0, "destroy event:%d", ev->fd); 213 | ev_mark[ev->fd] = NULL; 214 | ev->loop = NULL; 215 | ev->read_handler = NULL; 216 | ev->write_handler = NULL; 217 | tc_pfree(pool, ev); 218 | } 219 | 220 | void tc_event_destroy(tc_event_t *ev, int delayed) 221 | { 222 | tc_log_info(LOG_NOTICE, 0, "enter tc_event_destroy:%d", ev->fd); 223 | if (ev->fd <= 0 || ev->fd >= MAX_FD_NUM) { 224 | tc_log_info(LOG_ERR, 0, "fd is not valid"); 225 | return; 226 | } 227 | 228 | if (ev_mark[ev->fd] != NULL && ev != ev_mark[ev->fd]) { 229 | tc_log_info(LOG_NOTICE, 0, "destroy prev ev:%d", ev->fd); 230 | tc_event_destroy_with_no_delay(ev->loop->pool, ev_mark[ev->fd]); 231 | } 232 | 233 | if (delayed) { 234 | tc_log_info(LOG_NOTICE, 0, "delayed destroy ev:%d", ev->fd); 235 | ev_mark[ev->fd] = ev; 236 | } else { 237 | tc_event_destroy_with_no_delay(ev->loop->pool, ev); 238 | } 239 | } 240 | 241 | -------------------------------------------------------------------------------- /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 | extern tc_atomic_t tc_over; 87 | 88 | #endif /* TC_EVENT_H */ 89 | -------------------------------------------------------------------------------- /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:%p", 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:%p, del timer:%p", ev->pool, ev); 25 | tc_rbtree_delete(&tc_event_timer_rbtree, &ev->timer); 26 | ev->timer_set = 0; 27 | } 28 | 29 | static inline void 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 | return; 42 | } 43 | tc_event_del_timer(ev); 44 | } 45 | 46 | ev->timer.key = key; 47 | 48 | tc_log_debug2(LOG_DEBUG, 0, "pool:%p, up timer:%p", ev->pool, ev); 49 | tc_rbtree_insert(&tc_event_timer_rbtree, &ev->timer); 50 | 51 | ev->timer_set = 1; 52 | } else { 53 | tc_log_info(LOG_WARN, 0, "ev is null"); 54 | } 55 | } 56 | 57 | static inline tc_event_timer_t* 58 | tc_event_add_timer(tc_pool_t *pool, tc_msec_t timer, void *data, 59 | tc_event_timer_handler_pt handler) 60 | { 61 | tc_msec_t key; 62 | tc_event_timer_t *ev; 63 | 64 | ev = (tc_event_timer_t *) tc_palloc(pool, sizeof(tc_event_timer_t)); 65 | if (ev != NULL) { 66 | ev->pool = pool; 67 | ev->handler = handler; 68 | ev->data = data; 69 | key = ((tc_msec_t) tc_current_time_msec) + timer; 70 | ev->timer.key = key; 71 | 72 | tc_rbtree_insert(&tc_event_timer_rbtree, &ev->timer); 73 | 74 | tc_log_debug2(LOG_DEBUG, 0, "pool:%p, add timer:%p", pool, 75 | &ev->timer); 76 | 77 | ev->timer_set = 1; 78 | } 79 | return ev; 80 | } 81 | 82 | 83 | #endif /* _TC_EVENT_TIMER_H_INCLUDED_ */ 84 | -------------------------------------------------------------------------------- /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 | tc_log_info(LOG_NOTICE, 0, "tc_select_destroy, close fd:%d", 42 | event->fd); 43 | tc_socket_close(event->fd); 44 | } 45 | event->fd = -1; 46 | tc_pfree(loop->pool, event); 47 | } 48 | 49 | tc_pfree(loop->pool, io->evs); 50 | tc_pfree(loop->pool, loop->io); 51 | 52 | return TC_EVENT_OK; 53 | } 54 | 55 | int tc_select_add_event(tc_event_loop_t *loop, tc_event_t *ev, int events) 56 | { 57 | tc_select_multiplex_io_t *io; 58 | 59 | io = loop->io; 60 | 61 | if (io->last >= loop->size) { 62 | /* Too many */ 63 | return TC_EVENT_ERROR; 64 | } 65 | 66 | if (events == TC_EVENT_READ && ev->read_handler 67 | && ev->write_handler == NULL) 68 | { 69 | FD_SET(ev->fd, &io->r_set); 70 | } else if (events == TC_EVENT_WRITE && ev->write_handler 71 | && ev->read_handler == NULL) 72 | { 73 | FD_SET(ev->fd, &io->w_set); 74 | } else { 75 | return TC_EVENT_ERROR; 76 | } 77 | 78 | if (io->max_fd != -1 && ev->fd > io->max_fd) { 79 | io->max_fd = ev->fd; 80 | } 81 | 82 | ev->index = io->last; 83 | io->evs[io->last++] = ev; 84 | 85 | return TC_EVENT_OK; 86 | } 87 | 88 | int tc_select_del_event(tc_event_loop_t *loop, tc_event_t *ev, int events) 89 | { 90 | tc_event_t *last_ev; 91 | tc_select_multiplex_io_t *io; 92 | 93 | io = loop->io; 94 | 95 | if (ev->index < 0 || ev->index >= io->last) { 96 | return TC_EVENT_ERROR; 97 | } 98 | 99 | if (events == TC_EVENT_READ) { 100 | FD_CLR(ev->fd, &io->r_set); 101 | } else if (events == TC_EVENT_WRITE) { 102 | FD_CLR(ev->fd, &io->w_set); 103 | } else { 104 | return TC_EVENT_ERROR; 105 | } 106 | 107 | if (ev->index < --(io->last)) { 108 | last_ev = io->evs[io->last]; 109 | io->evs[ev->index] = last_ev; 110 | last_ev->index = ev->index; 111 | } 112 | 113 | ev->index = -1; 114 | 115 | if (io->max_fd == ev->fd) { 116 | io->max_fd = -1; 117 | } 118 | 119 | return TC_EVENT_OK; 120 | } 121 | 122 | int tc_select_polling(tc_event_loop_t *loop, long to) 123 | { 124 | int i, ret; 125 | fd_set cur_read_set, cur_write_set; 126 | tc_event_t **evs; 127 | struct timeval timeout; 128 | tc_select_multiplex_io_t *io; 129 | 130 | io = loop->io; 131 | evs = io->evs; 132 | 133 | if (io->max_fd == -1) { 134 | for (i = 0; i < io->last; i++) { 135 | if (io->max_fd < evs[i]->fd) { 136 | io->max_fd = evs[i]->fd; 137 | } 138 | } 139 | } 140 | 141 | timeout.tv_sec = (long) (to / 1000); 142 | timeout.tv_usec = (long) ((to % 1000) * 1000); 143 | 144 | cur_read_set = io->r_set; 145 | cur_write_set = io->w_set; 146 | 147 | ret = select(io->max_fd + 1, &cur_read_set, &cur_write_set, NULL, 148 | &timeout); 149 | 150 | if (ret == -1) { 151 | if (errno == EINTR) { 152 | return TC_EVENT_AGAIN; 153 | } 154 | return TC_EVENT_ERROR; 155 | } 156 | 157 | if (ret == 0) { 158 | return TC_EVENT_AGAIN; 159 | } 160 | 161 | for (i = 0; i < io->last; i++) { 162 | /* Clear the active events, and reset */ 163 | evs[i]->events = TC_EVENT_NONE; 164 | 165 | if (evs[i]->read_handler) { 166 | if (FD_ISSET(evs[i]->fd, &cur_read_set)) { 167 | evs[i]->events |= TC_EVENT_READ; 168 | tc_event_push_active_event(loop->active_events, evs[i]); 169 | } 170 | } else { 171 | if (FD_ISSET(evs[i]->fd, &cur_write_set)) { 172 | evs[i]->events |= TC_EVENT_WRITE; 173 | tc_event_push_active_event(loop->active_events, evs[i]); 174 | } 175 | } 176 | } 177 | 178 | return TC_EVENT_OK; 179 | } 180 | 181 | -------------------------------------------------------------------------------- /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 | tc_event_t **evs; 12 | fd_set r_set; 13 | fd_set w_set; 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/tcpcopy/tc_manager.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #if (TC_PLUGIN) 7 | static void 8 | remove_obso_resource(tc_event_timer_t *evt) 9 | { 10 | if (clt_settings.plugin && 11 | clt_settings.plugin->remove_obsolete_resources) 12 | { 13 | clt_settings.plugin->remove_obsolete_resources(0); 14 | if (evt) { 15 | tc_event_update_timer(evt, MAX_IDLE_MS_TIME); 16 | } 17 | } 18 | } 19 | #endif 20 | 21 | 22 | /* Check resource usage, such as memory usage and cpu usage */ 23 | static void 24 | check_resource_usage(tc_event_timer_t *evt) 25 | { 26 | int ret, who; 27 | struct rusage usage; 28 | struct mallinfo m; 29 | 30 | who = RUSAGE_SELF; 31 | 32 | ret = getrusage(who, &usage); 33 | if (ret == -1) { 34 | tc_log_info(LOG_ERR, errno, "getrusage"); 35 | } 36 | 37 | /* Total amount of user time used */ 38 | tc_log_info(LOG_NOTICE, 0, "user time used:%ld", usage.ru_utime.tv_sec); 39 | 40 | /* Total amount of system time used */ 41 | tc_log_info(LOG_NOTICE, 0, "sys time used:%ld", usage.ru_stime.tv_sec); 42 | 43 | /* Maximum resident set size (in kilobytes) */ 44 | /* Only valid since Linux 2.6.32 */ 45 | tc_log_info(LOG_NOTICE, 0, "max memory size:%ld", usage.ru_maxrss); 46 | 47 | if (usage.ru_maxrss > (long int) clt_settings.max_rss) { 48 | tc_log_info(LOG_WARN, 0, "occupies too much memory, limit:%ld", 49 | clt_settings.max_rss); 50 | /* Biggest signal number + 1 */ 51 | tc_over = SIGRTMAX; 52 | } 53 | 54 | m = mallinfo(); 55 | tc_log_info(LOG_NOTICE, 0, "Total allocated space (bytes): %d", m.uordblks); 56 | tc_log_info(LOG_NOTICE, 0, "Total free space (bytes): %d", m.fordblks); 57 | tc_log_info(LOG_NOTICE, 0, "Top-most, releasable space (bytes): %d", m.keepcost); 58 | 59 | if (m.fordblks > m.uordblks) { 60 | if (usage.ru_maxrss > (long int) (clt_settings.max_rss >> 2)) { 61 | tc_log_info(LOG_NOTICE, 0, "call malloc_trim"); 62 | malloc_trim(0); 63 | m = mallinfo(); 64 | tc_log_info(LOG_NOTICE, 0, "New total free space (bytes): %d", m.fordblks); 65 | tc_log_info(LOG_NOTICE, 0, "New top-most, releasable space (bytes): %d", m.keepcost); 66 | } 67 | } 68 | 69 | if (evt) { 70 | tc_event_update_timer(evt, 60000); 71 | } 72 | } 73 | 74 | 75 | void 76 | tcp_copy_release_resources(void) 77 | { 78 | #if (TC_PCAP) 79 | int i; 80 | #endif 81 | tc_log_info(LOG_WARN, 0, "sig %d received", tc_over); 82 | 83 | tc_output_stat(); 84 | 85 | tc_dest_sess_table(); 86 | 87 | #if (TC_PLUGIN) 88 | if (clt_settings.plugin && clt_settings.plugin->exit_module) { 89 | clt_settings.plugin->exit_module(&clt_settings); 90 | } 91 | #endif 92 | 93 | tc_event_loop_finish(&event_loop); 94 | tc_log_info(LOG_NOTICE, 0, "tc_event_loop_finish over"); 95 | 96 | #if (TC_DIGEST) 97 | tc_destroy_sha1(); 98 | tc_destroy_digests(); 99 | #endif 100 | 101 | #if (TC_PCAP) 102 | for (i = 0; i < clt_settings.devices.device_num; i++) { 103 | if (clt_settings.devices.device[i].pcap != NULL) { 104 | pcap_close(clt_settings.devices.device[i].pcap); 105 | clt_settings.devices.device[i].pcap = NULL; 106 | } 107 | } 108 | #endif 109 | 110 | #if (TC_OFFLINE) 111 | if (clt_settings.pcap != NULL) { 112 | pcap_close(clt_settings.pcap); 113 | clt_settings.pcap = NULL; 114 | } 115 | #endif 116 | 117 | if (tc_raw_socket_out > 0) { 118 | tc_socket_close(tc_raw_socket_out); 119 | tc_raw_socket_out = TC_INVALID_SOCK; 120 | } 121 | 122 | #if (TC_PCAP_SND) 123 | tc_pcap_over(); 124 | #endif 125 | 126 | tc_destroy_pool(clt_settings.pool); 127 | 128 | check_resource_usage(NULL); 129 | 130 | tc_log_end(); 131 | } 132 | 133 | 134 | void 135 | tcp_copy_over(const int sig) 136 | { 137 | tc_over = sig; 138 | } 139 | 140 | 141 | static bool send_version(int fd) { 142 | msg_clt_t msg; 143 | 144 | tc_memzero(&msg, sizeof(msg_clt_t)); 145 | msg.type = htons(INTERNAL_VERSION); 146 | 147 | if (tc_socket_snd(fd, (char *) &msg, MSG_CLT_SIZE) == TC_ERR) { 148 | tc_log_info(LOG_ERR, 0, "send version error:%d", fd); 149 | return false; 150 | } 151 | 152 | return true; 153 | } 154 | 155 | 156 | static int 157 | connect_to_server(tc_event_loop_t *ev_lp) 158 | { 159 | int i, j, fd; 160 | uint32_t target_ip; 161 | conns_t *conns; 162 | uint16_t target_port; 163 | 164 | for (i = 0; i < clt_settings.real_servers.num; i++) { 165 | 166 | conns = &(clt_settings.real_servers.conns[i]); 167 | target_ip = conns->ip; 168 | target_port = conns->port; 169 | if (target_port == 0) { 170 | target_port = clt_settings.srv_port; 171 | } 172 | 173 | if (conns->active != 0) { 174 | continue; 175 | } 176 | 177 | for (j = 0; j < conns->num; j++) { 178 | fd = conns->fds[j]; 179 | if (fd > 0) { 180 | tc_log_info(LOG_NOTICE, 0, "it close socket:%d", fd); 181 | tc_socket_close(fd); 182 | tc_event_del(clt_settings.ev[fd]->loop, 183 | clt_settings.ev[fd], TC_EVENT_READ); 184 | tc_event_destroy(clt_settings.ev[fd], 0); 185 | conns->fds[j] = -1; 186 | } 187 | } 188 | 189 | conns->num = 0; 190 | conns->remained_num = 0; 191 | 192 | for (j = 0; j < clt_settings.par_conns; j++) { 193 | fd = tc_message_init(ev_lp, target_ip, target_port); 194 | if (fd == TC_INVALID_SOCK) { 195 | return TC_ERR; 196 | } 197 | 198 | if (!send_version(fd)) { 199 | return TC_ERR; 200 | } 201 | 202 | if (j == 0) { 203 | clt_settings.real_servers.active_num++; 204 | conns->active = 1; 205 | } 206 | 207 | conns->fds[j] = fd; 208 | conns->num++; 209 | conns->remained_num++; 210 | } 211 | } 212 | 213 | return TC_OK; 214 | } 215 | 216 | 217 | static void 218 | restore_work(tc_event_timer_t *evt) 219 | { 220 | connect_to_server(&event_loop); 221 | tc_event_update_timer(evt, RETRY_INTERVAL); 222 | clt_settings.tries++; 223 | } 224 | 225 | 226 | int 227 | tcp_copy_init(tc_event_loop_t *ev_lp) 228 | { 229 | tc_event_add_timer(ev_lp->pool, 60000, NULL, check_resource_usage); 230 | tc_event_add_timer(ev_lp->pool, OUTPUT_INTERVAL, NULL, tc_interval_disp); 231 | 232 | if (clt_settings.lonely) { 233 | tc_event_add_timer(ev_lp->pool, RETRY_INTERVAL, NULL, restore_work); 234 | } 235 | 236 | if (tc_init_sess_table() == TC_ERR) { 237 | return TC_ERR; 238 | } 239 | 240 | if (connect_to_server(ev_lp) == TC_ERR) { 241 | return TC_ERR; 242 | } 243 | 244 | #if (TC_PLUGIN) 245 | if (clt_settings.plugin && clt_settings.plugin->init_module) { 246 | clt_settings.plugin->init_module(&clt_settings); 247 | } 248 | if (clt_settings.plugin && clt_settings.plugin->remove_obsolete_resources) { 249 | tc_event_add_timer(ev_lp->pool, MAX_IDLE_MS_TIME, 250 | NULL, remove_obso_resource); 251 | } 252 | #endif 253 | 254 | #if (TC_OFFLINE) 255 | if (tc_offline_init(ev_lp, clt_settings.pcap_file) == TC_ERR) { 256 | return TC_ERR; 257 | } 258 | #else 259 | if (tc_packets_init(ev_lp) == TC_ERR) { 260 | return TC_ERR; 261 | } 262 | #endif 263 | 264 | return TC_OK; 265 | } 266 | 267 | -------------------------------------------------------------------------------- /src/tcpcopy/tc_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_MANAGER_INCLUDED 2 | #define TC_MANAGER_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | int tcp_copy_init(tc_event_loop_t *event_loop); 8 | void tcp_copy_over(const int sig); 9 | void tcp_copy_release_resources(void); 10 | 11 | #endif /* ----- #ifndef TC_MANAGER_INCLUDED ----- */ 12 | 13 | -------------------------------------------------------------------------------- /src/tcpcopy/tc_message_module.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | static int tc_proc_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 | socklen_t len; 13 | struct timeval timeout = {3,0}; 14 | 15 | if ((fd = tc_socket_init()) == TC_INVALID_SOCK) { 16 | return TC_INVALID_SOCK; 17 | } 18 | 19 | if (tc_socket_connect(fd, ip, port) == TC_ERR) { 20 | tc_socket_close(fd); 21 | return TC_INVALID_SOCK; 22 | } 23 | 24 | if (tc_socket_set_nodelay(fd) == TC_ERR) { 25 | tc_socket_close(fd); 26 | return TC_INVALID_SOCK; 27 | } 28 | 29 | if (tc_socket_set_nonblocking(fd) == TC_ERR) { 30 | tc_socket_close(fd); 31 | return TC_INVALID_SOCK; 32 | } 33 | 34 | len = (socklen_t) sizeof(struct timeval); 35 | if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, len) == -1) { 36 | tc_log_info(LOG_ERR, errno, "Set timeout failed"); 37 | tc_socket_close(fd); 38 | return TC_INVALID_SOCK; 39 | } 40 | 41 | ev = tc_event_create(event_loop->pool, fd, tc_proc_server_msg, NULL); 42 | if (ev == NULL) { 43 | tc_socket_close(fd); 44 | return TC_INVALID_SOCK; 45 | } 46 | 47 | clt_settings.ev[fd] = ev; 48 | 49 | if (tc_event_add(event_loop, ev, TC_EVENT_READ) == TC_EVENT_ERROR) { 50 | tc_socket_close(fd); 51 | return TC_INVALID_SOCK; 52 | } 53 | 54 | 55 | return fd; 56 | } 57 | 58 | static int 59 | tc_proc_server_msg(tc_event_t *rev) 60 | { 61 | int i, j; 62 | conns_t *conns; 63 | #if (!TC_COMBINED) 64 | int len; 65 | msg_server_t msg; 66 | #else 67 | int num = 0, k; 68 | unsigned char *p, resp[COMB_LENGTH + sizeof(uint16_t)] = {0}; 69 | #endif 70 | 71 | 72 | #if (!TC_COMBINED) 73 | len = MSG_SERVER_SIZE; 74 | if (tc_socket_rcv(rev->fd, (char *) &msg, len) != TC_ERR) 75 | #else 76 | if (tc_socket_cmb_rcv(rev->fd, &num, (char *) resp) != TC_ERR) 77 | #endif 78 | { 79 | #if (!TC_COMBINED) 80 | tc_proc_outgress((unsigned char *) &msg); 81 | #else 82 | tc_log_debug1(LOG_DEBUG, 0, "resp packets:%d", num); 83 | p = resp + sizeof(uint16_t); 84 | for (k = 0; k < num; k++) { 85 | tc_proc_outgress(p); 86 | p = p + MSG_SERVER_SIZE; 87 | } 88 | #endif 89 | return TC_OK; 90 | 91 | } else { 92 | 93 | tc_log_info(LOG_ERR, 0, "Recv socket(%d)error", rev->fd); 94 | for (i = 0; i < clt_settings.real_servers.num; i++) { 95 | 96 | conns = &(clt_settings.real_servers.conns[i]); 97 | for (j = 0; j < conns->num; j++) { 98 | if (conns->fds[j] == rev->fd) { 99 | if (conns->fds[j] > 0) { 100 | tc_socket_close(conns->fds[j]); 101 | tc_log_info(LOG_NOTICE, 0, "close sock:%d", 102 | conns->fds[j]); 103 | tc_event_del(rev->loop, rev, TC_EVENT_READ); 104 | conns->fds[j] = -1; 105 | conns->remained_num--; 106 | } 107 | if (conns->remained_num == 0 && conns[i].active) { 108 | conns[i].active = 0; 109 | clt_settings.real_servers.active_num--; 110 | } 111 | 112 | break; 113 | } 114 | } 115 | } 116 | 117 | if (clt_settings.real_servers.active_num == 0) { 118 | if (!clt_settings.lonely) { 119 | tc_log_info(LOG_WARN, 0, "active num is zero"); 120 | tc_over = SIGRTMAX; 121 | } 122 | } 123 | return TC_OK; 124 | } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /src/tcpcopy/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/tcpcopy/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_packets_init(tc_event_loop_t *event_loop); 8 | #if (TC_OFFLINE) 9 | int tc_offline_init(tc_event_loop_t *event_loop, char *pcap_file); 10 | #endif 11 | 12 | #endif /* TC_PACKETS_MODULE_INCLUDED */ 13 | -------------------------------------------------------------------------------- /src/tcpcopy/tc_session.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_SESSION_INCLUDED 2 | #define TC_SESSION_INCLUDED 3 | 4 | #include 5 | #include 6 | 7 | #define FFRAME_LEN (60 + ETHERNET_HDR_LEN) 8 | #define FMIN_IP_LEN (IPH_MIN_LEN + (TCPH_DOFF_MIN_VALUE << 2)) 9 | #define FIP_TS_LEN (IPH_MIN_LEN + (TCPH_DOFF_TS_VALUE << 2)) 10 | #define FSYN_IP_LEN (IPH_MIN_LEN + (TCPH_DOFF_MSS_VALUE << 2)) 11 | #define FSYN_IP_TS_LEN (IPH_MIN_LEN + (TCPH_DOFF_WS_TS_VALUE << 2)) 12 | 13 | 14 | /* Global functions */ 15 | int tc_init_sess_table(void); 16 | void tc_dest_sess_table(void); 17 | void tc_save_pack(tc_sess_t *, link_list *, tc_iph_t *, tc_tcph_t *); 18 | bool tc_proc_ingress(tc_iph_t *, tc_tcph_t *); 19 | bool tc_proc_outgress(unsigned char *); 20 | uint32_t get_tf_ip(uint16_t key); 21 | bool tc_check_ingress_pack_needed(tc_iph_t *); 22 | void tc_interval_disp(tc_event_timer_t *); 23 | void tc_output_stat(void); 24 | 25 | 26 | typedef struct sess_state_machine_s{ 27 | uint32_t state:10; 28 | uint32_t rcv_nxt_sess:1; 29 | uint32_t candidate_rep_wait:1; 30 | uint32_t pack_lost:1; 31 | uint32_t conflict:1; 32 | uint32_t record_req_hop_seq:1; 33 | uint32_t recheck_hop:1; 34 | 35 | uint32_t renew_hop:1; 36 | uint32_t rcv_rep_af_hop:1; 37 | uint32_t recon:1; 38 | uint32_t record_mcon_seq:1; 39 | uint32_t rcv_rep_greet:1; 40 | uint32_t window_full:1; 41 | uint32_t internal_usage:1; 42 | uint32_t timeout:1; 43 | 44 | uint32_t delay_snd:1; 45 | uint32_t req_ack_snd:1; 46 | uint32_t fake_syn:1; 47 | uint32_t timestamp:1; 48 | uint32_t need_rep_greet:1; 49 | uint32_t already_retrans:1; 50 | uint32_t sess_over:1; 51 | uint32_t src_closed:1; 52 | 53 | #if (TC_PLUGIN) 54 | uint32_t clt_fin_or_rst_received:1; 55 | #endif 56 | uint32_t dst_closed:1; 57 | uint32_t last_ack:1; 58 | uint32_t set_rto:1; 59 | uint32_t snd_after_set_rto:1; 60 | uint32_t timer_type:3; 61 | uint32_t rtt_cal:2; 62 | uint32_t rep_payload_type:2; 63 | uint32_t rep_dup_ack_cnt:8; 64 | #if (TC_DETECT_MEMORY) 65 | uint32_t active_timer_cnt:8; 66 | uint32_t call_sess_post_cnt:8; 67 | #endif 68 | }sess_state_machine_t; 69 | 70 | typedef struct pack_info_s { 71 | uint32_t cont_len:16; 72 | uint32_t new_req_flag:1; 73 | uint32_t seq; 74 | uint32_t ack_seq; 75 | }pack_info_t; 76 | 77 | struct tc_sess_s { 78 | sess_state_machine_t sm; 79 | 80 | pack_info_t cur_pack; 81 | 82 | /* ack sequence that is sent to backend (host byte order) */ 83 | uint32_t target_ack_seq; 84 | /* next sequence that is sent to backend (host byte order) */ 85 | uint32_t target_nxt_seq; 86 | 87 | /* max payload packet sequence (host byte order) */ 88 | uint32_t max_con_seq; 89 | 90 | /* src or client ip address(network byte order) */ 91 | uint32_t src_addr; 92 | /* dst or backend ip address(network byte order) */ 93 | uint32_t dst_addr; 94 | /* online ip address(network byte order) */ 95 | uint32_t online_addr; 96 | /* src or client port(network byte order) */ 97 | uint16_t src_port; 98 | /* dst or backend port(network byte order) */ 99 | uint16_t dst_port; 100 | /* online port(network byte order) */ 101 | uint16_t online_port; 102 | uint16_t req_ip_id; 103 | uint16_t wscale; 104 | 105 | uint32_t peer_window; 106 | uint32_t ts_ec_r; 107 | uint32_t ts_value; 108 | 109 | /* captured variables(host byte order) */ 110 | /* only refer to online values */ 111 | /***********************begin************************/ 112 | /* last sequence of client content packet which has been sent */ 113 | uint32_t req_con_snd_seq; 114 | uint32_t req_exp_seq; 115 | /* last ack sequence of client packet which is sent to bakend */ 116 | uint32_t req_ack_snd_seq; 117 | /* last client content packet's ack sequence which is captured */ 118 | uint32_t req_con_ack_seq; 119 | uint32_t req_con_cur_ack_seq; 120 | /* last syn sequence of client packet */ 121 | uint32_t req_syn_seq; 122 | uint32_t req_hop_seq; 123 | /***********************end***************************/ 124 | 125 | /* response variables */ 126 | /* last acknowledgement seq from backend response (host byte order) */ 127 | uint32_t rep_ack_seq; 128 | /* last seq from backend response (host byte order) */ 129 | uint32_t rep_seq; 130 | #if (TC_DEBUG) 131 | uint32_t rep_ack_seq_bf_fin; 132 | #endif 133 | 134 | /* hash key for this session */ 135 | uint64_t hash_key; 136 | 137 | long rtt; 138 | time_t create_time; 139 | /* time of sending the last content packet */ 140 | time_t req_snd_con_time; 141 | time_t pack_lost_time; 142 | /* time of last receiving backend packet */ 143 | time_t rep_rcv_time; 144 | 145 | unsigned char *frame; 146 | unsigned char *src_mac; 147 | unsigned char *dst_mac; 148 | 149 | link_list *slide_win_packs; 150 | link_node *prev_snd_node; 151 | 152 | #if (TC_PLUGIN) 153 | void *data; 154 | #endif 155 | tc_event_timer_t *ev; 156 | tc_event_timer_t *gc_ev; 157 | tc_pool_t *pool; 158 | }; 159 | 160 | 161 | #endif /* ----- #ifndef TC_SESSION_INCLUDED ----- */ 162 | 163 | -------------------------------------------------------------------------------- /src/tcpcopy/tc_udp_session.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | 6 | static uint64_t clt_udp_cnt = 0; 7 | static uint64_t clt_udp_send_cnt = 0; 8 | 9 | 10 | int 11 | tc_init_sess_table(void) 12 | { 13 | return TC_OK; 14 | } 15 | 16 | void 17 | tc_dest_sess_table(void) 18 | { 19 | } 20 | 21 | /* 22 | * filter udp packets 23 | */ 24 | bool 25 | tc_check_ingress_pack_needed(tc_iph_t *ip) 26 | { 27 | bool is_needed = false; 28 | uint16_t size_ip, size_udp, tot_len; 29 | tc_udpt_t *udp; 30 | 31 | if (ip->version != 4 || ip->protocol != IPPROTO_UDP) { 32 | return is_needed; 33 | } 34 | 35 | size_ip = ip->ihl << 2; 36 | tot_len = ntohs(ip->tot_len); 37 | if (size_ip < IPH_MIN_LEN) { 38 | tc_log_info(LOG_WARN, 0, "Invalid IP header length: %d", size_ip); 39 | return is_needed; 40 | } 41 | 42 | udp = (tc_udpt_t *) ((char *) ip + size_ip); 43 | size_udp = ntohs(udp->len); 44 | if (size_udp < sizeof(tc_udpt_t)) { 45 | tc_log_info(LOG_WARN, 0, "Invalid udp header len: %d,pack len:%d", 46 | size_udp, tot_len); 47 | return is_needed; 48 | } 49 | 50 | /* filter the packets we do care about */ 51 | if (TC_CLT == check_pack_src(&(clt_settings.transfer), 52 | ip->daddr, udp->dest, CHECK_DEST)) 53 | { 54 | is_needed = true; 55 | clt_udp_cnt++; 56 | } 57 | 58 | return is_needed; 59 | 60 | } 61 | 62 | 63 | void 64 | tc_output_stat() 65 | { 66 | tc_log_info(LOG_INFO, 0, 67 | "udp packets captured:%llu,packets sent:%llu", 68 | clt_udp_cnt, clt_udp_send_cnt); 69 | } 70 | 71 | 72 | void 73 | tc_interval_disp(tc_event_timer_t *evt) 74 | { 75 | tc_output_stat(); 76 | tc_event_update_timer(evt, OUTPUT_INTERVAL); 77 | } 78 | 79 | 80 | static unsigned char buf[IP_RCV_BUF_SIZE]; 81 | void 82 | ip_fragmentation(tc_iph_t *ip) 83 | { 84 | int ret, max_pack_no, index, i; 85 | tc_iph_t *tmp_ip; 86 | uint16_t offset, size_ip, tot_len, 87 | remainder, payload_len; 88 | unsigned char *p; 89 | 90 | size_ip = ip->ihl << 2; 91 | tot_len = ntohs(ip->tot_len); 92 | 93 | p = buf; 94 | /* dispose the first packet here */ 95 | memcpy(p, ip, size_ip); 96 | p = p + ETHERNET_HDR_LEN; 97 | offset = clt_settings.mtu - size_ip; 98 | if (offset % 8 != 0) { 99 | offset = offset / 8; 100 | offset = offset * 8; 101 | } 102 | payload_len = offset; 103 | 104 | tmp_ip = (tc_iph_t *) p; 105 | tmp_ip->frag_off = htons(IP_MF); 106 | 107 | index = size_ip; 108 | p += size_ip; 109 | memcpy(p, ((unsigned char *) ip) + index, payload_len); 110 | index = index + payload_len; 111 | remainder = tot_len - size_ip - payload_len; 112 | ret = tc_raw_socket_snd(tc_raw_socket_out, tmp_ip, 113 | size_ip + payload_len, tmp_ip->daddr); 114 | 115 | if (ret == TC_ERR) { 116 | tc_log_info(LOG_ERR, 0, "send to back error,packet size:%d", 117 | size_ip + payload_len); 118 | return; 119 | } 120 | 121 | clt_udp_send_cnt++; 122 | 123 | max_pack_no = (offset + remainder - 1) / offset - 1; 124 | 125 | for (i = 0; i <= max_pack_no; i++) { 126 | 127 | p = buf; 128 | memcpy(p, (char *) ip, size_ip); 129 | 130 | tmp_ip = (tc_iph_t *) p; 131 | tmp_ip->frag_off = htons(offset >> 3); 132 | 133 | if (i == max_pack_no) { 134 | payload_len = remainder; 135 | } else { 136 | tmp_ip->frag_off |= htons(IP_MF); 137 | remainder = remainder - payload_len; 138 | } 139 | 140 | p += size_ip; 141 | memcpy(p, ((char *) ip) + index, payload_len); 142 | index = index + payload_len; 143 | offset = offset + payload_len; 144 | ret = tc_raw_socket_snd(tc_raw_socket_out, tmp_ip, 145 | size_ip + payload_len, tmp_ip->daddr); 146 | if (ret == TC_ERR) { 147 | tc_log_info(LOG_ERR, 0, "send to back error,packet size:%d", 148 | size_ip + payload_len); 149 | return; 150 | } 151 | clt_udp_send_cnt++; 152 | } 153 | } 154 | 155 | bool tc_proc_outgress(unsigned char *packet) 156 | { 157 | return true; 158 | } 159 | 160 | /* 161 | * the main procedure for processing udp packets 162 | */ 163 | bool tc_proc_ingress(tc_iph_t *ip, tc_udpt_t *udp) 164 | { 165 | int ret; 166 | uint16_t tot_len; 167 | transfer_map_t *test; 168 | 169 | tot_len = ntohs(ip->tot_len); 170 | 171 | test = get_test_pair(&(clt_settings.transfer), ip->daddr, udp->dest); 172 | if (test == NULL) { 173 | tc_log_info(LOG_ERR, 0, "retrieve test pair error"); 174 | return false; 175 | } 176 | 177 | ip->daddr = test->target_ip; 178 | udp->dest = test->target_port; 179 | udpcsum(ip, udp); 180 | 181 | /* check if it needs fragmentation */ 182 | if (tot_len > clt_settings.mtu) { 183 | 184 | ip_fragmentation(ip); 185 | } else { 186 | 187 | ret = tc_raw_socket_snd(tc_raw_socket_out, ip, 188 | tot_len, ip->daddr); 189 | if (ret == TC_ERR) { 190 | tc_log_info(LOG_ERR, 0, "send to back error,tot_len:%d", tot_len); 191 | } 192 | clt_udp_send_cnt++; 193 | } 194 | 195 | return true; 196 | } 197 | 198 | -------------------------------------------------------------------------------- /src/tcpcopy/tc_udp_session.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UDP_SESSION_H_INC 3 | #define _UDP_SESSION_H_INC 4 | 5 | 6 | /* global functions */ 7 | int tc_init_sess_table(); 8 | void tc_dest_sess_table(); 9 | bool tc_proc_ingress(tc_iph_t *ip, tc_udpt_t *udp); 10 | bool tc_proc_outgress(unsigned char *packet); 11 | bool tc_check_ingress_pack_needed(tc_iph_t *ip); 12 | void tc_interval_disp(tc_event_timer_t *evt); 13 | void tc_output_stat(); 14 | 15 | #endif /* ----- #ifndef _UDP_SESSION_H_INC ----- */ 16 | 17 | -------------------------------------------------------------------------------- /src/tcpcopy/tcpcopy.h: -------------------------------------------------------------------------------- 1 | #ifndef TC_INCLUDED 2 | #define TC_INCLUDED 3 | #include 4 | 5 | #define LOCALHOST (inet_addr("127.0.0.1")) 6 | 7 | typedef struct { 8 | /* Online ip from the client perspective */ 9 | uint32_t online_ip; 10 | uint32_t target_ip; 11 | uint16_t online_port; 12 | uint16_t target_port; 13 | unsigned char src_mac[ETHER_ADDR_LEN]; 14 | unsigned char dst_mac[ETHER_ADDR_LEN]; 15 | } transfer_map_t; 16 | 17 | 18 | typedef struct { 19 | int num; 20 | transfer_map_t **map; 21 | } transfer_maps_t; 22 | 23 | typedef struct real_ip_addr_s { 24 | int num; 25 | int active_num; 26 | conns_t conns[MAX_REAL_SERVERS]; 27 | } real_ip_addr_t; 28 | 29 | static inline transfer_map_t * 30 | get_test_pair(transfer_maps_t *tf, uint32_t ip, uint16_t port) 31 | { 32 | int i; 33 | transfer_map_t *pair, **map; 34 | 35 | pair = NULL; 36 | map = tf->map; 37 | for (i = 0; i < tf->num; i++) { 38 | pair = map[i]; 39 | if (pair->online_ip == 0 && port == pair->online_port) { 40 | return pair; 41 | } else if (ip == pair->online_ip && port == pair->online_port) { 42 | return pair; 43 | } 44 | } 45 | return NULL; 46 | } 47 | 48 | static inline int 49 | check_pack_src(transfer_maps_t *tf, uint32_t ip, uint16_t port, int src_flag) 50 | { 51 | int i, ret; 52 | transfer_map_t *pair, **map; 53 | 54 | ret = TC_UNKNOWN; 55 | map = tf->map; 56 | 57 | for (i = 0; i < tf->num; i++) { 58 | 59 | pair = map[i]; 60 | if (src_flag == CHECK_DEST) { 61 | if (ip == pair->online_ip && port == pair->online_port) { 62 | ret = TC_CLT; 63 | break; 64 | } else if (0 == pair->online_ip && port == pair->online_port) { 65 | ret = TC_CLT; 66 | break; 67 | } 68 | } else if (src_flag == CHECK_SRC) { 69 | if (ip == pair->target_ip && port == pair->target_port) { 70 | ret = TC_BAK; 71 | break; 72 | } 73 | } 74 | } 75 | 76 | return ret; 77 | } 78 | 79 | 80 | 81 | typedef struct xcopy_clt_settings { 82 | unsigned int mtu:16; /* MTU sent to backend */ 83 | unsigned int mss:16; /* MSS sent to backend */ 84 | unsigned int default_rtt:16; 85 | unsigned int s_pool_size:16; 86 | unsigned int par_conns:8; /* parallel connections */ 87 | unsigned int factor:8; /* port shift factor */ 88 | unsigned int replica_num:10; /* replicated number of each request */ 89 | unsigned int only_replay_full:1; 90 | unsigned int lonely:1; /* Lonely for tcpcopy */ 91 | unsigned int gradully:1; 92 | unsigned int target_localhost:1; 93 | unsigned int not_wait_resp:1; 94 | unsigned int do_daemonize:1; /* daemon flag */ 95 | unsigned int percentage:7; /* percentage of the full flow that 96 | will be tranfered to the backend */ 97 | 98 | int sess_timeout; /* max value for session timeout. 99 | If reaching this value, the session 100 | will be removed */ 101 | int sess_keepalive_timeout; 102 | 103 | #if (TC_OFFLINE) 104 | int accelerated_times; /* accelerated times */ 105 | int replay_times; 106 | pcap_t *pcap; 107 | long pcap_time; 108 | uint64_t interval; 109 | #endif 110 | 111 | #if (TC_PCAP) 112 | int buffer_size; 113 | int snaplen; 114 | char *raw_device; 115 | devices_t devices; 116 | #endif 117 | tc_pool_t *pool; 118 | 119 | transfer_maps_t transfer; 120 | 121 | char *raw_rs_list; /* raw real server list */ 122 | uint64_t tries; 123 | char *user_filter; 124 | #if (TC_PCAP_SND) 125 | char *output_if_name; 126 | #endif 127 | #if (TC_OFFLINE) 128 | char *pcap_file; /* pcap file */ 129 | #endif 130 | char *raw_clt_tf_ip; 131 | char *pid_file; /* pid file */ 132 | char *log_path; /* error log path */ 133 | char *raw_tf; /* online_ip online_port target_ip 134 | target_port string */ 135 | #if (TC_PLUGIN) 136 | char *conf_file; 137 | tc_conf_t *cf; 138 | tc_module_t *plugin; 139 | #endif 140 | 141 | int sig; 142 | int multiplex_io; 143 | uint32_t localhost_tf_ip; 144 | uint32_t max_rss; /* max memory allowed for tcpcopy */ 145 | uint16_t srv_port; /* server listening port */ 146 | uint16_t rand_port_shifted; /* random port shifted */ 147 | uint16_t clt_tf_ip_num; 148 | uint16_t ip_tf_cnt; 149 | 150 | real_ip_addr_t real_servers; /* the intercept servers */ 151 | tc_event_t *ev[MAX_FD_NUM]; 152 | uint32_t ip_tf[65536]; 153 | uint32_t clt_tf_ip[M_IP_NUM]; /* ip addr from clt to target ip */ 154 | unsigned char candidate_mtu[256]; 155 | char filter[MAX_FILTER_LENGH]; 156 | } xcopy_clt_settings; 157 | 158 | 159 | typedef struct tc_stat_s { 160 | uint64_t leave_cnt; 161 | uint64_t time_wait_cnt; 162 | uint64_t obs_cnt; 163 | uint64_t clt_syn_cnt; 164 | uint64_t captured_cnt; 165 | uint64_t clt_cont_cnt; 166 | uint64_t clt_packs_cnt; 167 | uint64_t packs_sent_cnt; 168 | uint64_t fin_sent_cnt; 169 | uint64_t rst_sent_cnt; 170 | uint64_t con_packs_sent_cnt; 171 | uint64_t resp_rst_cnt; 172 | uint64_t resp_fin_cnt; 173 | uint64_t resp_cnt; 174 | uint64_t resp_cont_cnt; 175 | uint64_t conn_cnt; 176 | uint64_t conn_try_cnt; 177 | uint64_t retrans_succ_cnt; 178 | uint64_t retrans_cnt; 179 | uint64_t frag_cnt; 180 | uint64_t clt_con_retrans_cnt; 181 | uint64_t recon_for_closed_cnt; 182 | uint64_t recon_for_no_syn_cnt; 183 | time_t start_pt; 184 | }tc_stat_t; 185 | 186 | extern int tc_raw_socket_out; 187 | extern tc_event_loop_t event_loop; 188 | extern xcopy_clt_settings clt_settings; 189 | extern tc_stat_t tc_stat; 190 | extern hash_table *sess_table; 191 | #if (TC_PLUGIN) 192 | extern tc_module_t *tc_modules[]; 193 | #endif 194 | 195 | #include 196 | 197 | #include 198 | # if(TC_UDP) 199 | #include 200 | #else 201 | #include 202 | #endif 203 | #include 204 | #include 205 | 206 | #endif /* TC_INCLUDED */ 207 | -------------------------------------------------------------------------------- /src/util/tc_util.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | unsigned char * 5 | cp_fr_ip_pack(tc_pool_t *pool, tc_iph_t *ip) 6 | { 7 | int frame_len; 8 | uint16_t tot_len; 9 | unsigned char *frame; 10 | 11 | tot_len = ntohs(ip->tot_len); 12 | frame_len = ETHERNET_HDR_LEN + tot_len; 13 | 14 | frame = (unsigned char *) tc_palloc(pool, frame_len); 15 | 16 | if (frame != NULL) { 17 | memcpy(frame + ETHERNET_HDR_LEN, ip, tot_len); 18 | } 19 | 20 | return frame; 21 | } 22 | 23 | 24 | unsigned short 25 | csum(unsigned short *pack, int len) 26 | { 27 | register unsigned long sum = 0; 28 | 29 | while (len > 1) { 30 | sum += *(pack++); 31 | len -= 2; 32 | } 33 | if (len > 0) { 34 | sum += *(unsigned char *) pack; 35 | } 36 | while (sum >> 16) { 37 | sum = (sum & 0xffff) + (sum >> 16); 38 | } 39 | 40 | return (unsigned short) ~sum; 41 | } 42 | 43 | 44 | static unsigned short buf[32768]; 45 | 46 | 47 | unsigned short 48 | tcpcsum(unsigned char *iphdr, unsigned short *pack, int len) 49 | { 50 | unsigned short res; 51 | 52 | memcpy(buf, iphdr + 12, 8); 53 | *(buf + 4) = htons((unsigned short) (*(iphdr + 9))); 54 | *(buf + 5) = htons((unsigned short) len); 55 | memcpy(buf + 6, pack, len); 56 | res = csum(buf, len + 12); 57 | 58 | return res; 59 | } 60 | 61 | 62 | #if (TC_UDP) 63 | static int 64 | do_checksum_math(u_int16_t *data, int len) 65 | { 66 | int sum = 0; 67 | union { 68 | u_int16_t s; 69 | u_int8_t b[2]; 70 | } pad; 71 | 72 | while (len > 1) { 73 | sum += *data++; 74 | len -= 2; 75 | } 76 | 77 | if (len == 1) { 78 | pad.b[0] = *(u_int8_t *)data; 79 | pad.b[1] = 0; 80 | sum += pad.s; 81 | } 82 | 83 | return (sum); 84 | } 85 | 86 | 87 | void udpcsum(tc_iph_t *ip, tc_udpt_t *udp) 88 | { 89 | int sum; 90 | uint16_t len; 91 | unsigned char *ip_src; 92 | 93 | udp->check = 0; 94 | 95 | len = ntohs(udp->len); 96 | ip_src = (unsigned char *) (&ip->saddr); 97 | sum = do_checksum_math((u_int16_t *) ip_src, 8); 98 | sum += ntohs(IPPROTO_UDP + len); 99 | sum += do_checksum_math((u_int16_t *) udp, len); 100 | udp->check = CHECKSUM_CARRY(sum); 101 | 102 | } 103 | #endif 104 | 105 | #if (TC_PCAP) 106 | int 107 | retrieve_devices(char *raw_device, devices_t *devices) 108 | { 109 | int count = 0; 110 | size_t len; 111 | const char *split, *p; 112 | 113 | p = raw_device; 114 | 115 | while (true) { 116 | split = strchr(p, ','); 117 | if (split != NULL) { 118 | len = (size_t) (split - p); 119 | } else { 120 | len = strlen(p); 121 | } 122 | 123 | strncpy(devices->device[count++].name, p, len); 124 | 125 | if (count == MAX_DEVICE_NUM) { 126 | tc_log_info(LOG_WARN, 0, "reach the limit for devices"); 127 | break; 128 | } 129 | 130 | if (split == NULL) { 131 | break; 132 | } else { 133 | p = split + 1; 134 | } 135 | } 136 | 137 | devices->device_num = count; 138 | 139 | return 1; 140 | } 141 | 142 | 143 | char * 144 | construct_filter(int flag, uint32_t ip, uint16_t port, char *filter) 145 | { 146 | char *pt, direction[16]; 147 | struct in_addr net_address; 148 | 149 | tc_memzero(direction, 16); 150 | if (flag == SRC_DIRECTION) { 151 | strcpy(direction, "src"); 152 | } else if (flag == DST_DIRECTION) { 153 | strcpy(direction, "dst"); 154 | } 155 | pt = filter; 156 | strcpy(pt, "("); 157 | pt = pt + strlen(pt); 158 | 159 | if (port > 0) { 160 | sprintf(pt, "%s port %d", direction, ntohs(port)); 161 | pt = pt + strlen(pt); 162 | } 163 | 164 | if (ip > 0) { 165 | net_address.s_addr = ip; 166 | if (port == 0) { 167 | sprintf(pt, "%s host %s", direction, inet_ntoa(net_address)); 168 | } else { 169 | sprintf(pt, " and %s host %s", direction, inet_ntoa(net_address)); 170 | } 171 | pt = pt + strlen(pt); 172 | } 173 | 174 | strcpy(pt, ")"); 175 | pt = pt + strlen(pt); 176 | 177 | return pt; 178 | } 179 | #endif 180 | 181 | #if (TC_PCAP || TC_OFFLINE) 182 | int 183 | get_l2_len(const unsigned char *frame, const int datalink) 184 | { 185 | struct ethernet_hdr *eth_hdr; 186 | 187 | switch (datalink) { 188 | case DLT_RAW: 189 | return 0; 190 | break; 191 | case DLT_EN10MB: 192 | eth_hdr = (struct ethernet_hdr *) frame; 193 | switch (ntohs(eth_hdr->ether_type)) { 194 | case ETHERTYPE_VLAN: 195 | return 18; 196 | break; 197 | default: 198 | return 14; 199 | break; 200 | } 201 | break; 202 | case DLT_C_HDLC: 203 | return CISCO_HDLC_LEN; 204 | break; 205 | case DLT_LINUX_SLL: 206 | return SLL_HDR_LEN; 207 | break; 208 | default: 209 | tc_log_info(LOG_ERR, 0, "unsupported DLT type: %s (0x%x)", 210 | pcap_datalink_val_to_description(datalink), datalink); 211 | break; 212 | } 213 | 214 | return -1; 215 | } 216 | 217 | 218 | #ifdef FORCE_ALIGN 219 | static unsigned char pcap_ip_buf[65536]; 220 | #endif 221 | 222 | unsigned char * 223 | get_ip_data(pcap_t *pcap, unsigned char *frame, const int pkt_len, int *pl2_len) 224 | { 225 | int l2_len; 226 | u_char *ptr; 227 | 228 | l2_len = get_l2_len(frame, pcap_datalink(pcap)); 229 | *pl2_len = l2_len; 230 | 231 | if (pkt_len <= l2_len) { 232 | return NULL; 233 | } 234 | #ifdef FORCE_ALIGN 235 | if (l2_len % 4 == 0) { 236 | ptr = (&(frame)[l2_len]); 237 | } else { 238 | ptr = pcap_ip_buf; 239 | memcpy(ptr, (&(frame)[l2_len]), pkt_len - l2_len); 240 | } 241 | #else 242 | ptr = (&(frame)[l2_len]); 243 | #endif 244 | 245 | return ptr; 246 | 247 | } 248 | #endif 249 | 250 | -------------------------------------------------------------------------------- /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 | #if (TC_UDP) 15 | #define CHECKSUM_CARRY(x) \ 16 | (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff)) 17 | #endif 18 | 19 | unsigned char *cp_fr_ip_pack(tc_pool_t *pool, tc_iph_t *ip); 20 | unsigned short csum (unsigned short *pack, int len); 21 | unsigned short tcpcsum(unsigned char *iphdr, unsigned short *pack, int len); 22 | #if (TC_UDP) 23 | void udpcsum(tc_iph_t *ip, tc_udpt_t *udp); 24 | #endif 25 | #if (TC_PCAP) 26 | int retrieve_devices(char *raw_device, devices_t *devices); 27 | char *construct_filter(int flag, uint32_t ip, uint16_t port, char *filter); 28 | #endif 29 | 30 | #if (TC_PCAP || TC_OFFLINE) 31 | int get_l2_len(const unsigned char *, const int); 32 | unsigned char *get_ip_data(pcap_t *, unsigned char *, const int, int *); 33 | #endif 34 | 35 | 36 | #if (TC_PCAP_SND) 37 | static inline void 38 | fill_frame(struct ethernet_hdr *hdr, unsigned char *smac, unsigned char *dmac) 39 | { 40 | memcpy(hdr->ether_shost, smac, ETHER_ADDR_LEN); 41 | memcpy(hdr->ether_dhost, dmac, ETHER_ADDR_LEN); 42 | hdr->ether_type = htons(ETH_P_IP); 43 | } 44 | #endif 45 | 46 | static inline uint64_t 47 | get_key(uint32_t ip, uint16_t port) 48 | { 49 | uint64_t value = ((uint64_t) ip ) << 16; 50 | 51 | value += port; 52 | 53 | return value; 54 | } 55 | 56 | 57 | static inline uint16_t 58 | get_appropriate_port(int orig_port, int add) 59 | { 60 | int dest_port = orig_port + add; 61 | 62 | if (dest_port >= 65536) { 63 | dest_port = 1024 + add; 64 | } 65 | 66 | return (uint16_t) dest_port; 67 | } 68 | 69 | 70 | static inline uint16_t 71 | get_port_from_shift(int orig_port, int rand_port, int shift_factor) 72 | { 73 | int port_add; 74 | 75 | port_add = (shift_factor << 11) + rand_port; 76 | 77 | return get_appropriate_port(ntohs(orig_port), port_add); 78 | } 79 | 80 | 81 | static inline uint16_t 82 | get_ip_key(uint32_t ip) 83 | { 84 | uint32_t value = (ip >> 16) + ip; 85 | return (uint16_t) value; 86 | } 87 | 88 | 89 | #endif /* ----- #ifndef TC_UTIL_INCLUDED ----- */ 90 | 91 | --------------------------------------------------------------------------------