aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcharan makkina <charan795m@gmail.com>2019-01-22 14:18:33 +0530
committercharan makkina <charan795m@gmail.com>2019-01-25 14:19:58 +0530
commit840dc98676773c027e699bd6efc3793118a5f1ef (patch)
tree57f85aa706f3de7033aaf66e84c989cab859ee88
parent82b8efb032cffb13e92d5f7f3d30d53ec1c93663 (diff)
Test: Testcases for bps, cps, ip6, lp and te.
Change-Id: I17ad8a915c4a9332c11797e7f02c82abbfadfbbc Signed-off-by: charan makkina <charan795m@gmail.com>
-rw-r--r--thirdparty/apps/CMakeLists.txt1
-rw-r--r--thirdparty/apps/testapp/CMakeLists.txt56
-rw-r--r--thirdparty/apps/testapp/README.md212
-rw-r--r--thirdparty/apps/testapp/bps/bps.c775
-rw-r--r--thirdparty/apps/testapp/bps/bps.h112
-rw-r--r--thirdparty/apps/testapp/cps/cps.c833
-rw-r--r--thirdparty/apps/testapp/cps/cps.h283
-rw-r--r--thirdparty/apps/testapp/cps/cps_c.c394
-rw-r--r--thirdparty/apps/testapp/cps/cps_s.c320
-rw-r--r--thirdparty/apps/testapp/ft.c74
-rw-r--r--thirdparty/apps/testapp/ip6/ip6.c739
-rw-r--r--thirdparty/apps/testapp/lb/api.h169
-rw-r--r--thirdparty/apps/testapp/lb/lb.c1290
-rw-r--r--thirdparty/apps/testapp/lb/lb.h731
-rw-r--r--thirdparty/apps/testapp/lp/lp.c1138
-rw-r--r--thirdparty/apps/testapp/lp/lp.h615
-rw-r--r--thirdparty/apps/testapp/lp/lpc.c669
-rw-r--r--thirdparty/apps/testapp/lp/lps.c372
-rw-r--r--thirdparty/apps/testapp/te/te.c782
19 files changed, 9565 insertions, 0 deletions
diff --git a/thirdparty/apps/CMakeLists.txt b/thirdparty/apps/CMakeLists.txt
index 0fffccd..f4f1cbe 100644
--- a/thirdparty/apps/CMakeLists.txt
+++ b/thirdparty/apps/CMakeLists.txt
@@ -77,3 +77,4 @@ ExternalProject_Add(
)
set_target_properties(NETPERF PROPERTIES EXCLUDE_FROM_ALL TRUE)
+ADD_SUBDIRECTORY(testapp)
diff --git a/thirdparty/apps/testapp/CMakeLists.txt b/thirdparty/apps/testapp/CMakeLists.txt
new file mode 100644
index 0000000..b4c56df
--- /dev/null
+++ b/thirdparty/apps/testapp/CMakeLists.txt
@@ -0,0 +1,56 @@
+#########################################################################
+#
+# Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#########################################################################
+
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11)
+#PROJECT(leibniz)
+
+#SET(CMAKE_C_COMPILER "gcc")
+INCLUDE_DIRECTORIES(lb)
+ADD_DEFINITIONS(-O2 -g -fPIC -m64 -pthread -Werror)
+ADD_DEFINITIONS(-D_GNU_SOURCE -U_FORTIFY_SOURCE -DDEBUG)
+LINK_LIBRARIES(-pthread -lrt -g -m64)
+LINK_LIBRARIES(-L../../../../build -llb)
+LINK_LIBRARIES(-L../../../../release/lib64 -lnStackAPI)
+
+FILE(GLOB lb_src lb/*.c)
+ADD_LIBRARY(lb STATIC ${lb_src})
+
+#SET(BINS lp bps cps ip6 te)
+LIST(APPEND BINS "lp")
+LIST(APPEND BINS "bps")
+LIST(APPEND BINS "cps")
+LIST(APPEND BINS "ip6")
+LIST(APPEND BINS "te")
+MESSAGE(STATUS "" ${BINS})
+FOREACH(one ${BINS})
+ FILE(GLOB ${one}_src ${one}/*.c)
+ ADD_EXECUTABLE(${one} ${${one}_src})
+ ADD_DEPENDENCIES(${one} lb)
+ ADD_DEPENDENCIES(${one} nStackAPI)
+ENDFOREACH(one)
+
+ADD_EXECUTABLE(ft ft.c)
+ADD_DEPENDENCIES(ft lb)
+ADD_DEPENDENCIES(ft nStackAPI)
+IF(EXISTS ${nslib})
+ MESSAGE(STATUS "! set nstack lib directory ${NSLIb}")
+ LINK_LIBRARIES(-Wl, --whole-archive -L${NSLIB} -lnStackAPI -lrtp_mem -lsecurec -Wl,--no-whole-archive)
+ FOREACH(one ${BINS})
+ ADD_EXECUTABLE(ns${one} ${${one}_src})
+ ADD_DEPENDENCIES(ns${one} lb)
+ ENDFOREACH(one)
+ENDIF()
diff --git a/thirdparty/apps/testapp/README.md b/thirdparty/apps/testapp/README.md
new file mode 100644
index 0000000..83bc121
--- /dev/null
+++ b/thirdparty/apps/testapp/README.md
@@ -0,0 +1,212 @@
+# 1. BPS
+**NAME**
+bps
+
+**SYNOPSIS**
+bps [OPTIONS] [SERVER-ADDRESS]
+
+**DESCRIPTION**
+bps is used to test throughput.
+```
+ -h, --help help
+ -v, --verbose show more statistics
+ -e, --exact show exact value
+ -i, --interval=SECONDS report time(default:1s)
+ -l, --length=LENGTH message length(default:458 max:1024)
+ -B, --buffer=BUFFER recv buffer size(default:LENGTH max:1024)
+ -C, --core=COREMASK bound core mask HEX(default:0(no bind core))
+ -S, --send-only only send
+ -R, --recv-only only receive
+ -c, --client client mode
+ Client mode options:
+ -t, --time=SECOND test time(default:30s)
+ -b, --bind=ADDRESS bind address
+ -p, --parallel=# parallel number(default:1 max:128)
+ -D, --debug show debug information
+ ADDRESS: X.X.X.X:PORT default port:58177
+```
+**EXAMPLE**
+Server:
+```
+$./bps 192.168.1.1:6666 -l 1000
+```
+
+Client:
+```
+$./bps -c 192.168.1.1:6666 -l 1000
+```
+
+#2. CPS
+**NAME**
+cps
+
+**SYNOPSIS**
+cps [OPTIONS] [SERVER-ADDRESS]
+
+**DESCRIPTION**
+cps is used to test the connection rate.
+```
+ -i, --interval=# report time(default: 10s max:3600s)
+ -c, --client server address list for one thread
+ -e, --evnum epoll event number(default:256 max:1024)
+ -T, --time=# C test time(default: 300s max:604800s)
+ -d, --data=#[:#] C request and response data length(default:1:1 max:4096)
+ -r, --rate=#[k|m|w] C global connect rate per each thread(CPS, default: 10000 max:100000000)
+ -t, --thread=CONFIG set one net and thread(max: 128)
+ server=X.X.X.X:P server address set(max: 32)
+ core=# bind to core
+ client=X.X.X.X C client ip address set(max: 32 max ip: 256)
+ rate=# C set connect rate for this thread(default: use global set)
+ cf C client loop first(default: both)
+ sf C server loop first(default: both)
+ -D, --debug show debug information
+ -m, --more show more statistics
+ -v, --verbose show thread statistics
+ -h, --help help
+ IMPORTANT:
+ socket() EMFILE(24) error: ulimit -n 1048576
+ bind() EADDRINUSE(98) error: echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
+ connect() EADDRNOTAVAIL(99) error: echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
+ echo "3000 65534" > /proc/sys/net/ipv4/ip_local_port_range
+```
+
+**EXAMPLE**
+Server:
+```
+$./cps -t "server=192.168.1.1:8888"
+```
+Client:
+```
+$./cps -c -t "server=192.168.1.1:8888,rate=10"
+```
+
+# 3. LP
+**NAME**
+lp
+
+**SYNOPSIS**
+lp [OPTIONS] TEST-SET...
+
+**DESCRIPTION**
+lp test multiple connections, connect rate and close rate.
+```
+ -s, --server LIST set one server address list
+ X.Y.Z.M-N:P1-P2,...
+ -c, --client LIST set one client address list
+ CLIENT*SERVER: R.S.T.K-J:Pa-Pb,...*X.Y.Z.M-N:P1-P2,...
+ A,B,C,D*1,2 random link
+ A,B,C,D=1,2 A1B2C1D2
+ A,B,C,D}1,2 A1B1C1D1 A2B2C2D2
+ A,B,C,D{1,2 A1A2 B1B2 C1C2 D1D2
+ -b, --block set block mode for connecting(client only)
+ -n, --nodelay set nodelay
+ -i, --interval # report time(default:1s max:60s)
+ -m, --core #HEX set bind cpu core mask(hex mode)
+ -D, --debug show debug information
+ -w, --watch show watch time statistic
+ -e, --no-error #-# skip error
+ -E, --error-msg show error message
+ -C, --no-color no color
+ -v, --verbose show worker statistics
+ -h, --help help
+ TEST-SET for client
+ TARGET@TIME+UP-DOWN=QUERY:REPLY*TIMES-/PERIOD%WAIT (client only)
+ TARGET max connection(default: INFINITE)
+ @TIME max time(0 or default:INFINITE)
+ +UP connect rate(default: 0 no connnect; *: INFINITE)
+ -DOWN close rate(default: 0 no close; *: INFINITE)
+ =... IO set(default: no IO)
+ QUERY send query data len(8-65536)
+ :REPLY receive response data len(0-10485760; default: same with QUERY)
+ *TIMES- IO times(0 or default: INFINITE; suffix-: IO then close)
+ /PERIOD IO period time(0-3600s; default: one by one)
+ %WAIT first IO wait time(0-3600s; default: 0 no wait)
+ UNITS:
+ k=1000 m=1000k g=1000m w=10000 K=1024 M=1024K G=1024M
+ s=Seconds m=Minutes h=Hours
+
+ =QUERY:REPLY*TIMES-/PERIOD%WAIT
+This section set the send/recv action
+
+```
+**EXAMPLE**
+Server:
+```
+$./lp -s 192.168.1.1:1000-1999 -s 182.168.1.1:2000-2999
+ #each -s start 1 thread, open 1000 fd to listen
+```
+
+Client:
+```
+$./lp -c 192.168.1.100:10000-19999*192.168.1.1:1000-1999 TEST-SET
+ #each -c start 1 thread
+ #192.168.1.100:10000-19999 is client addresses
+ #192.168.1.1:1000-1999 are server addresses
+ #TEST-SET is client only, you can set some test case, see options
+```
+
+**TEST-SET EXAMPLES**
+
+```
+1. $./lp -c 192.168.1.100:10000-19999*192.168.1.1:1000-1999 1m+10k @10s 0-1k
+```
+
+Step1: target 1000000 connection, connect rate is 10k/s
+Step2: no target, sleep 10 seconds
+Step3: target 0 connection, close rate is 1k/s
+
+```
+2. $./lp -c 192.168.1.100:10000-19999*192.168.1.1:1000-1999 100000+10k-5k @10s 0-1k
+```
+Step1: target 100000 connection, both connect and close are execute, connect rate 10k/s, close rate 5k/s
+
+# 4. TE
+**NAME**
+te
+
+**SYNOPSIS**
+te [OPTIONS]
+
+**DESCRIPTION**
+te is used to test the test the basic functions of IPv6
+```
+l : v6_tcp_server_listen ( X::X PORT )
+L : v6_tcp_server_listen ( X::X PORT )
+
+c : v6_tcp_client_s ( X::X PORT )
+s : v6_tcp_server_shutdown_rd ( X::X PORT )
+d : v6_tcp_server_shutdown_wr ( X::X PORT )
+f : v6_tcp_server_shutdown_rdwr ( X::X PORT )
+
+1 : v4_tcp_client_s ( X.X.X.X PORT )
+2 : v4_tcp_server_shutdown_rd ( X.X.X.X PORT )
+3 : v4_tcp_server_shutdown_wr ( X.X.X.X PORT )
+
+U : test_v6_udp ( X::X )
+u : test_v4_udp ( X.X.X.X )
+t : test_v4_tcp ( X.X.X.X )
+
+b : v6_udp_close_select ( X::X PORT )
+```
+
+# 5. IP6
+**NAME**
+ip6
+
+**SYNOPSIS**
+ip6 [OPTIONS] SERVER-ADDRESS
+
+**DESCRIPTION**
+ip6 is used to test the test the basic functions of IPv6
+```
+ -b, --bind IP.PORT bind address
+ -c, --client client mode
+ -u, --udp udp mode
+ -n, --number # C packet number(default:LOOP)
+ -d, --delay # C seconds wait send next packet(default:1, 0: no delay)
+ -l, --length # C data length(default:100)
+ -o, --output # show received data(default:16)
+ -D, --debug show debug information
+ -v, --verbose show thread statistics
+ -h, --help help
+```
diff --git a/thirdparty/apps/testapp/bps/bps.c b/thirdparty/apps/testapp/bps/bps.c
new file mode 100644
index 0000000..a3e9bdf
--- /dev/null
+++ b/thirdparty/apps/testapp/bps/bps.c
@@ -0,0 +1,775 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+#include "bps.h"
+
+struct bps_var bps = { 0 };
+
+/********************/
+
+inline static int
+bps_cpu ()
+{
+ int i;
+
+ if (bps.bind_core == 0)
+ return -1;
+
+ for (i = 0; i < 64; ++i)
+ {
+ if (bps.bind_core & (1ul << i))
+ {
+ bps.bind_core &= ~(1ul << i);
+ out ("mask:0x%lx cps:%d\n", bps.bind_core, i);
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void *
+bps_send (void *arg)
+{
+ static char bps_send_buf[BPS_MAX_LEN];
+
+ struct bps_sess *sess = (struct bps_sess *) arg;
+ const int sid = BPS_SESS_ID (sess);
+ int fd, sent = 0;
+ char *buf = malloc (bps.msg_len);
+
+ out ("client send\n");
+
+ if (!buf)
+ buf = bps_send_buf;
+
+ futex_wait (&sess->fd, -1);
+ __sync_synchronize ();
+
+ fd = sess->fd;
+
+ while (sess->state == BPS_RUNNING)
+ {
+ int ret = _send (fd, buf + sent, bps.msg_len - sent, 0);
+ if (ret > 0)
+ {
+ sent += ret;
+ bps.rec_now[sid].snd += ret;
+ if (sent >= bps.msg_len)
+ sent -= bps.msg_len;
+ }
+ else
+ {
+ if (ret < 0)
+ {
+ const int e = errno;
+ if (e == EWOULDBLOCK || e == EINTR || e == EAGAIN)
+ continue;
+ out ("send()=%d:%d\n", ret, e);
+ }
+ //sess->state = BPS_SEND_ERROR;
+ }
+ }
+
+ if (buf != bps_send_buf)
+ free (buf);
+ return NULL;
+}
+
+void *
+bps_recv (void *arg)
+{
+ static char bps_recv_buf[BPS_MAX_LEN];
+
+ struct bps_sess *sess = (struct bps_sess *) arg;
+ const int sid = BPS_SESS_ID (sess);
+ int fd, recved = 0;
+ char *buf = malloc (bps.buf_size);
+ out ("client recv\n");
+ if (!buf)
+ buf = bps_recv_buf;
+
+ futex_wait (&sess->fd, -1);
+ __sync_synchronize ();
+
+ fd = sess->fd;
+
+ while (sess->state == BPS_RUNNING)
+ {
+ int ret = _recv (fd, buf + recved, bps.buf_size - recved, 0);
+ if (ret > 0)
+ {
+ recved += ret;
+ bps.rec_now[sid].rcv += ret;
+ if (recved >= bps.msg_len)
+ recved -= bps.msg_len;
+ }
+ else
+ {
+ if (ret < 0)
+ {
+ const int e = errno;
+ if (e == EWOULDBLOCK || e == EINTR || e == EAGAIN)
+ continue;
+ out ("recv()=%d:%d\n", ret, e);
+ }
+ //sess->state = BPS_RECV_ERROR;
+ }
+ }
+
+ if (buf != bps_recv_buf)
+ free (buf);
+ return NULL;
+}
+
+void
+bps_stop (struct bps_sess *sess)
+{
+ if (sess->state == BPS_RUNNING)
+ sess->state = BPS_STOP;
+
+ if (sess->send_tid)
+ (void) pthread_join (sess->send_tid, NULL);
+ if (sess->recv_tid)
+ (void) pthread_join (sess->recv_tid, NULL);
+
+ if (sess->recv_core >= 0)
+ bps.bind_core |= (1 << sess->recv_core);
+ if (sess->send_core >= 0)
+ bps.bind_core |= (1 << sess->send_core);
+
+ if (sess->fd >= 0)
+ {
+ _close (sess->fd);
+ sess->fd = -1;
+ }
+
+ bps.sess_num--;
+
+ sess->head.prev->head.next = sess->head.next;
+ sess->head.next->head.prev = sess->head.prev;
+
+ sess->head.next = bps.free_sess;
+ bps.free_sess = sess;
+}
+
+struct bps_sess *
+bps_start (int fd)
+{
+ int ret;
+ struct bps_sess *sess;
+
+ if (!bps.free_sess)
+ {
+ _close (fd);
+ return NULL;
+ }
+
+ sess = bps.free_sess;
+ bps.free_sess = sess->head.next;
+
+ sess->fd = fd;
+ sess->state = BPS_RUNNING;
+ sess->index = (uint16_t) (++bps.global_index);
+ sess->recv_core = sess->send_core = -1;
+ sess->recv_tid = sess->send_tid = 0;
+
+ ++bps.sess_num;
+
+ sess->head.next = (struct bps_sess *) &bps.sess_head;
+ sess->head.prev = bps.sess_head.prev;
+ bps.sess_head.prev->head.next = sess;
+ bps.sess_head.prev = sess;
+
+ ret = set_nonblock (fd);
+ ERR_GOTO (ret, ERR_EXIT, "fcntl(%d, F_SETFL, O_NONBLOCK)=%d:%d\n", fd, ret,
+ errno);
+
+ if (bps.io_mode & BPS_IO_SEND)
+ {
+ sess->send_core = bps_cpu ();
+ sess->send_tid = lb_thread (bps_send, sess, "bps-send-%d", fd);
+ ERR_GOTO (sess->send_tid == 0, ERR_EXIT, "lb_thread(send:%d)=0:%d\n",
+ fd, errno);
+ if (sess->send_core >= 0)
+ {
+ lb_setcpu (sess->send_tid, sess->send_core);
+ }
+ }
+
+ if (bps.io_mode & BPS_IO_RECV)
+ {
+ sess->recv_core = bps_cpu ();
+ sess->recv_tid = lb_thread (bps_recv, sess, "bps-recv-%d", fd);
+ ERR_GOTO (sess->recv_tid == 0, ERR_EXIT, "lb_thread(recv:%d)=0:%d\n",
+ fd, errno);
+ if (sess->recv_core >= 0)
+ {
+ lb_setcpu (sess->recv_tid, sess->recv_core);
+ }
+ }
+
+ if (BPS_SESS_ID (sess) > bps.max_sess_id)
+ bps.max_sess_id = BPS_SESS_ID (sess);
+
+ return sess;
+
+ERR_EXIT:
+ bps_stop (sess);
+ return NULL;
+}
+
+void
+bps_accept ()
+{
+ while (bps.state == BPS_RUNNING)
+ {
+ int ret, fd;
+ struct bps_sess *sess;
+ struct sockaddr_in addr = { 0 }, s_addr =
+ {
+ 0};
+ socklen_t len = sizeof (addr);
+
+ fd = _accept (bps.listen_fd, (struct sockaddr *) &addr, &len);
+ if (fd < 0)
+ {
+ if (!
+ (errno == ETIMEDOUT || errno == EWOULDBLOCK || errno == EAGAIN))
+ {
+ wrn ("accept(%d)=%d:%d\n", bps.listen_fd, fd, errno);
+ }
+ return;
+ }
+
+ len = sizeof (s_addr);
+ ret = _getsockname (fd, (struct sockaddr *) &s_addr, &len);
+ if (ret)
+ {
+ _close (fd);
+ wrn ("getsockname(%d)=%d:%d\n", fd, ret, errno);
+ continue;
+ }
+
+ sess = bps_start (fd);
+ if (sess)
+ {
+ out ("[%d:%d] accepted %s --> %s\n", sess->index, fd,
+ f_inaddr (&addr), f_inaddr (&s_addr));
+ }
+ else
+ {
+ out ("[ERR:%d] accept %s --> %s FAILED\n", fd, f_inaddr (&addr),
+ f_inaddr (&s_addr));
+ }
+ }
+}
+
+void
+bps_output (uint16_t index, int fd, uint64_t nsec, struct bps_rec *rec)
+{
+ const int UBPS = bps.exact ? 1 : MB;
+ const int UPPS = bps.exact ? 1 : KB;
+ const int SBPS = bps.exact ? 14 : 6;
+ const int SPPS = bps.exact ? 10 : 5;
+
+ char buf[256];
+ char *pos = buf;
+
+ *pos++ = ' ';
+ pos += r_uint (pos, lb_gdiv ((rec->rcv + rec->snd) * 8, nsec) / UBPS, SBPS);
+ *pos++ = ' ';
+ pos +=
+ r_uint (pos, lb_gdiv ((rec->rcv + rec->snd), nsec * bps.msg_len) / UPPS,
+ SPPS);
+ *pos++ = ' ';
+ *pos++ = '|';
+ *pos++ = ' ';
+ pos += r_uint (pos, lb_gdiv (rec->snd * 8, nsec) / UBPS, SBPS);
+ *pos++ = ' ';
+ pos += r_uint (pos, lb_gdiv (rec->snd, nsec * bps.msg_len) / UPPS, SPPS);
+ *pos++ = ' ';
+ *pos++ = '|';
+ *pos++ = ' ';
+ pos += r_uint (pos, lb_gdiv (rec->rcv * 8, nsec) / UBPS, SBPS);
+ *pos++ = ' ';
+ pos += r_uint (pos, lb_gdiv (rec->rcv, nsec * bps.msg_len) / UPPS, SPPS);
+
+ if (index == 0)
+ {
+ if (fd > 60 * 60)
+ pos +=
+ sprintf (pos, " | %d:%02d:%02d", fd / 3600, fd % 3600 / 60,
+ fd % 60);
+ else
+ pos += sprintf (pos, " | %02d:%02d", fd / 60, fd % 60);
+ }
+ else
+ {
+ pos += sprintf (pos, " | %u-%d", index, fd);
+ }
+
+ *pos = 0;
+
+ out ("%s\n", buf);
+}
+
+void
+bps_report (const struct timespec *now)
+{
+ static const char *HEAD[] = {
+ " T:mbps kpps | S:mbps kpps | R:mbps kpps | info",
+ " total:bps pps | send:bps pps | recv:bps pps | info"
+ };
+ static int report_set = 0;
+
+ int i;
+ struct bps_sess *sess;
+ struct bps_rec rec, *last = bps.rec_now;
+ uint64_t nsec = LB_SUB_NS (*now, bps.last_time);
+
+ bps.rec_now = bps.rec_list[last == bps.rec_list[0] ? 1 : 0];
+
+ lb_sleep (0, BPS_EXCH_DELAY * NSOFMS); /* wait memory */
+
+ rec.rcv = rec.snd = 0;
+ for (i = 0; i <= bps.max_sess_id; ++i)
+ {
+ rec.rcv += last[i].rcv;
+ rec.snd += last[i].snd;
+ }
+
+ if (rec.rcv == 0 && rec.snd == 0)
+ {
+ if (report_set != 0)
+ {
+ out ("\n");
+ report_set = 0;
+ }
+ return;
+ }
+
+ if (report_set++ == 0)
+ out ("%s\n", HEAD[bps.exact]);
+
+ nsec = LB_SUB_NS (*now, bps.last_time);
+
+ sess = bps.sess_head.next;
+ while (sess != (struct bps_sess *) &bps.sess_head)
+ {
+ struct bps_sess *next = sess->head.next;
+
+ if (bps.verbose)
+ bps_output (sess->index, sess->fd, nsec, last + BPS_SESS_ID (sess));
+
+ if (sess->state != BPS_RUNNING)
+ bps_stop (sess);
+
+ sess = next;
+ }
+
+ bps_output (0, (int) (LB_SUB_NS (*now, bps.begin_time) / NSOFS), nsec,
+ &rec);
+
+ (void) memset (last, 0, sizeof (struct bps_rec) * (bps.max_sess_id + 1));
+}
+
+void
+bps_loop ()
+{
+ while (bps.state == BPS_RUNNING)
+ {
+ struct timespec now;
+
+ LB_TIME (now);
+
+ if (LB_CMP (now, bps.next_time) >= 0)
+ {
+ bps_report (&now);
+ bps.last_time = now;
+ bps.next_time.tv_sec += bps.report_time;
+ }
+
+ if (bps.client_mode)
+ {
+ if (LB_CMP_S (now, bps.begin_time, bps.test_time))
+ {
+ bps.state = BPS_STOP;
+ break;
+ }
+ }
+ else
+ {
+ bps_accept ();
+ }
+
+ lb_sleep (0, BPS_STAT_TIMER * NSOFMS);
+ }
+}
+
+int
+bps_server ()
+{
+ int ret;
+
+ /* server socket listen */
+
+ bps.listen_fd = _socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (bps.listen_fd < 0, 1, "socket()=%d:%d\n", bps.listen_fd, errno);
+
+ ret =
+ _bind (bps.listen_fd, (struct sockaddr *) &bps.server_addr,
+ sizeof (bps.server_addr));
+ ERR_RETURN (ret, 1, "bind(%d)=%d:%d\n", bps.listen_fd, ret, errno);
+
+ ret = _listen (bps.listen_fd, 10);
+ ERR_RETURN (ret, 1, "listen(%d)=%d:%d\n", bps.listen_fd, ret, errno);
+
+ ret = set_nonblock (bps.listen_fd);
+ ERR_RETURN (ret, 1, "set_nonblock(%d) failed\n", bps.listen_fd);
+
+ out ("[%d] listen on %s\n", bps.listen_fd, f_inaddr (&bps.server_addr));
+
+ return 0;
+}
+
+int
+bps_client ()
+{
+ int i, fd;
+
+ for (i = 0; i < bps.parallel; ++i)
+ {
+ int ret;
+ struct bps_sess *sess;
+ struct sockaddr_in addr = { 0 };
+ socklen_t len = sizeof (addr);
+
+ fd = _socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (fd < 0, 1, "socket()=%d:%d\n", fd, errno);
+
+ if (bps.client_bind)
+ {
+ ret =
+ _bind (fd, (struct sockaddr *) &bps.bind_addr,
+ sizeof (bps.bind_addr));
+ ERR_GOTO (ret, ERR_EXIT, "bind(%d, %s)=%d:%d\n", fd,
+ f_inaddr (&bps.bind_addr), ret, errno);
+ }
+
+ ret =
+ _connect (fd, (struct sockaddr *) &bps.server_addr,
+ sizeof (bps.server_addr));
+ ERR_GOTO (ret, ERR_EXIT, "connect(%d, %s)=%d:%d\n", fd,
+ f_inaddr (&bps.server_addr), ret, errno);
+
+ ret = _getsockname (fd, (struct sockaddr *) &addr, &len);
+ ERR_GOTO (ret, ERR_EXIT, "getsockname(%d)=%d:%d\n", fd, ret, errno);
+
+ sess = bps_start (fd);
+ if (ret)
+ {
+ return 1;
+ }
+
+ out ("[%d:%d] connected %s --> %s\n", sess->index, fd, f_inaddr (&addr),
+ f_inaddr (&bps.server_addr));
+ }
+
+ return 0;
+
+ERR_EXIT:
+ _close (fd);
+ return 1;
+}
+
+void
+bps_exit ()
+{
+ while (bps.sess_head.next != (struct bps_sess *) &bps.sess_head)
+ {
+ struct bps_sess *sess = bps.sess_head.next;
+
+ bps_stop (sess);
+ }
+
+ if (bps.listen_fd >= 0)
+ {
+ _close (bps.listen_fd);
+ bps.listen_fd = -1;
+ }
+}
+
+int
+bps_init ()
+{
+ int i;
+ struct bps_sess *sess;
+
+ bps.listen_fd = -1;
+ bps.rec_now = bps.rec_list[0];
+
+ if (bps.parallel == 0)
+ bps.parallel = BPS_DEF_PARALLEL;
+ if (bps.test_time == 0)
+ bps.test_time = BPS_DEF_TIME;
+ if (bps.report_time == 0)
+ bps.report_time = BPS_DEF_REPORT_TIME;
+ if (bps.io_mode == 0)
+ bps.io_mode = BPS_IO_SEND | BPS_IO_RECV;
+ if (bps.msg_len == 0)
+ bps.msg_len = BPS_DEF_LEN;
+ if (bps.buf_size < bps.msg_len)
+ bps.buf_size = bps.msg_len;
+
+ bps.free_sess = sess = bps.sess_list;
+ for (i = 0; i < BPS_MAX_SESS - 1; ++i)
+ {
+ sess->head.next = sess + 1;
+ sess++;
+ }
+ sess->head.next = NULL;
+
+ bps.sess_head.next = bps.sess_head.prev =
+ (struct bps_sess *) &bps.sess_head;
+
+ LB_TIME (bps.begin_time);
+ bps.last_time = bps.next_time = bps.begin_time;
+ bps.next_time.tv_sec += bps.report_time;
+
+ return 0;
+}
+
+#ifndef EXEC_BPS_
+#define EXEC_BPS_
+
+#define OPTIONS "i:l:B:cC:SRt:b:p:m:veh" DBGOPT
+
+static const struct option options[] = {
+ {"interval", 1, 0, 'i'},
+ {"length", 1, 0, 'l'},
+ {"buffer", 1, 0, 'B'},
+ {"client", 0, 0, 'c'},
+ {"core", 1, 0, 'C'},
+ {"time", 1, 0, 't'},
+ {"bind", 1, 0, 'b'},
+ {"parallel", 1, 0, 'p'},
+ {"send-only", 0, 0, 'S'},
+ {"recv-only", 0, 0, 'R'},
+ {"verbose", 0, 0, 'v'},
+ {"exact", 0, 0, 'e'},
+ {"help", 0, 0, 'h'},
+ DBGOPT_LONG {0, 0, 0, 0}
+};
+
+void
+bps_usage (const char *name)
+{
+ out ("USAGE: %s [OPTIONS] [SERVER-ADDRESS] # %s version\n", name,
+ VERSION_NAME);
+ out (" Options:\n");
+ out (" -h, --help help\n");
+ out (" -v, --verbose show more statistics\n");
+ out (" -e, --exact show exact value\n");
+ out (" -i, --interval=SECONDS report time(default:%ds)\n",
+ BPS_DEF_REPORT_TIME);
+ out (" -l, --length=LENGTH message length(default:%d max:%d)\n",
+ BPS_DEF_LEN, BPS_MAX_LEN);
+ out
+ (" -B, --buffer=BUFFER recv buffer size(default:LENGTH max:%d)\n",
+ BPS_MAX_LEN);
+ out
+ (" -C, --core=COREMASK bound core mask HEX(default:0(no bind core))\n");
+ out (" -S, --send-only only send\n");
+ out (" -R, --recv-only only receive\n");
+ out (" -c, --client client mode\n");
+ out (" Client mode options:\n");
+ out (" -t, --time=SECOND test time(default:%ds)\n",
+ BPS_DEF_TIME);
+ out (" -b, --bind=ADDRESS bind address\n");
+ out
+ (" -p, --parallel=# parallel number(default:%d max:%d)\n",
+ BPS_DEF_PARALLEL, BPS_MAX_PARALLEL);
+#ifdef DEBUG
+ out (" -D, --debug show debug information\n");
+#endif
+ out (" ADDRESS: X.X.X.X:PORT default port:%u\n", BPS_DEF_PORT);
+}
+
+int
+bps_args (int argc, char *argv[])
+{
+ const char *end;
+ int opt, index;
+
+ bps.bind_addr.sin_family = AF_INET;
+ bps.bind_addr.sin_addr.s_addr = INADDR_ANY;
+ bps.bind_addr.sin_port = 0;
+
+ bps.server_addr.sin_family = AF_INET;
+ bps.server_addr.sin_addr.s_addr = INADDR_ANY;
+ bps.server_addr.sin_port = htons (BPS_DEF_PORT);
+
+ while (EOF != (opt = getopt_long (argc, argv, OPTIONS, options, &index)))
+ {
+ switch (opt)
+ {
+ case 'i':
+ bps.report_time = atoi (optarg);
+ break;
+ case 'l':
+ bps.msg_len = atoi (optarg);
+ ERR_RETURN (bps.msg_len > BPS_MAX_LEN, 1,
+ "Message len must between 1 and %d\n", BPS_MAX_LEN);
+ break;
+ case 'B':
+ bps.buf_size = atoi (optarg);
+ break;
+ case 'c':
+ bps.client_mode = 1;
+ break;
+ case 'C':
+ bps.bind_core = p_hex (optarg, &end);
+ ERR_RETURN (!end
+ || *end, 1, "Invalid bind core mask '%s'\n", optarg);
+ break;
+ case 't':
+ bps.test_time = atoi (optarg);
+ break;
+ case 'b':
+ ERR_RETURN (p_addr (optarg, &bps.bind_addr), 1,
+ "Invalid bind address '%s'\n", optarg);
+ bps.client_bind = 1;
+ break;
+ case 'p':
+ bps.parallel = atoi (optarg);
+ ERR_RETURN (bps.parallel > BPS_MAX_PARALLEL || bps.parallel <= 0, 1,
+ "Parallel must between 1 and %d\n", BPS_MAX_PARALLEL);
+ break;
+ case 'S':
+ bps.io_mode = BPS_IO_SEND;
+ break;
+ case 'R':
+ bps.io_mode = BPS_IO_RECV;
+ break;
+ case 'v':
+ bps.verbose = 1;
+ break;
+ case 'e':
+ bps.exact = 1;
+ break;
+#ifdef DEBUG
+ case 'D':
+ enable_debug = 1;
+ break;
+#endif
+ case 'h':
+ bps_usage (argv[0]);
+ exit (0);
+ case '?':
+ err ("Invalid arguments\n");
+ return 1;
+ default:
+ err ("Unknown option '%c'.\n", opt);
+ return 1;
+ }
+ }
+
+ if (optind == argc - 1)
+ {
+ ERR_RETURN (p_addr (argv[optind], &bps.server_addr), 1,
+ "Invalid server address '%s'\n", argv[optind]);
+ }
+ else if (optind < argc)
+ {
+ while (optind < argc)
+ err ("Unknown argument '%s'\n", argv[optind++]);
+ return 1;
+ }
+ else if (bps.client_mode)
+ {
+ bps.server_addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
+ }
+
+ printf
+ ("bps param: verbose %d\n exact %d\n client_mode %d\n client_bind %d\n io_mode %d\n parallel %d\n \
+ buf_size %d\n msg_len %d\n bind_core %lu\n report_time %d\n test_time %d\n bind_addr %x\n server_addr %x\n",
+ bps.verbose, bps.exact, bps.client_mode, bps.client_bind, bps.io_mode, bps.parallel, bps.buf_size, bps.msg_len, bps.bind_core, bps.report_time, bps.test_time,
+ bps.bind_addr.sin_addr.s_addr, bps.server_addr.sin_addr.s_addr);
+ return 0;
+}
+
+void
+bps_break (int s)
+{
+ if (bps.state < 0)
+ exit (1);
+
+ out ("\n");
+
+ bps.state = BPS_BREAK;
+}
+
+void
+bps_sigpipe (int s)
+{
+ DBG ("SIGPIPE\n");
+}
+
+void
+bps_set_sig ()
+{
+ struct sigaction s = { 0 };
+
+ (void) sigemptyset (&s.sa_mask);
+
+ s.sa_flags = SA_NODEFER;
+ s.sa_handler = (void *) bps_break;
+ (void) sigaction (SIGINT, &s, NULL);
+ (void) sigaction (SIGQUIT, &s, NULL);
+
+ s.sa_handler = bps_sigpipe;
+ (void) sigaction (SIGPIPE, &s, NULL);
+}
+
+#endif /* #ifndef EXEC_BPS_ */
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+ enable_debug = 1;
+ if (bps_args (argc, argv))
+ return 1;
+
+ if (bps_init ())
+ return 1;
+
+ bps_set_sig ();
+
+ if (bps.client_mode)
+ ret = bps_client ();
+ else
+ ret = bps_server ();
+
+ if (!ret)
+ bps_loop ();
+
+ bps_exit ();
+
+ return ret;
+}
diff --git a/thirdparty/apps/testapp/bps/bps.h b/thirdparty/apps/testapp/bps/bps.h
new file mode 100644
index 0000000..b91bd8d
--- /dev/null
+++ b/thirdparty/apps/testapp/bps/bps.h
@@ -0,0 +1,112 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef _BPS_H_
+#define _BPS_H_
+
+#define BPS_EXCH_DELAY 10 /* ms */
+#define BPS_STAT_TIMER 49 /* ms */
+
+#define BPS_MAX_PARALLEL 128
+#define BPS_MAX_SESS 1024
+
+#define BPS_MAX_LEN (1 * 1024)
+
+#define BPS_DEF_PORT 58177
+#define BPS_DEF_LEN 458
+#define BPS_DEF_PARALLEL 1
+#define BPS_DEF_TIME 30
+#define BPS_DEF_REPORT_TIME 1
+
+#define BPS_IO_SEND 0x1
+#define BPS_IO_RECV 0x2
+
+#define BPS_BREAK (-1)
+#define BPS_RUNNING 0
+#define BPS_STOP 1
+
+#define BPS_ERROR 64
+#define BPS_SEND_ERROR (BPS_ERROR | 1)
+#define BPS_RECV_ERROR (BPS_ERROR | 2)
+
+struct bps_rec
+{
+ uint64_t rcv;
+ uint64_t snd;
+};
+
+struct bps_sess_head
+{
+ struct bps_sess *next;
+ struct bps_sess *prev;
+};
+
+struct bps_sess
+{
+ struct bps_sess_head head; //must be first
+
+ int fd;
+ uint16_t index;
+ volatile short state;
+
+ int recv_core;
+ int send_core;
+ pthread_t recv_tid;
+ pthread_t send_tid;
+};
+
+struct bps_var
+{
+ /* begin config */
+ int verbose;
+ int exact;
+ int client_mode;
+ int client_bind;
+
+ int io_mode;
+ int parallel;
+ int buf_size;
+ int msg_len;
+
+ uint64_t bind_core;
+ int report_time;
+ int test_time;
+ struct sockaddr_in bind_addr;
+ struct sockaddr_in server_addr;
+
+ /* end config */
+
+ uint16_t global_index;
+ short state;
+ int listen_fd;
+
+ struct bps_rec rec_list[2][BPS_MAX_SESS];
+ struct bps_rec *rec_now;
+
+ struct timespec begin_time;
+ struct timespec last_time;
+ struct timespec next_time;
+
+ struct bps_sess sess_list[BPS_MAX_SESS];
+ struct bps_sess *free_sess;
+ struct bps_sess_head sess_head;
+ int sess_num;
+ int max_sess_id;
+};
+
+#define BPS_SESS_ID(sess) ((sess) - &bps.sess_list[0])
+
+#endif /* #ifndef _BPS_H_ */
diff --git a/thirdparty/apps/testapp/cps/cps.c b/thirdparty/apps/testapp/cps/cps.c
new file mode 100644
index 0000000..377d0de
--- /dev/null
+++ b/thirdparty/apps/testapp/cps/cps.c
@@ -0,0 +1,833 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+#include "cps.h"
+
+void *cps_s_thread (void *arg);
+void *cps_c_thread (void *arg);
+
+static const char *const cps_stat_name[CPS_CNT_NUM] = {
+ [CPS_CNT_CONN_MAX] = "max",
+ [CPS_CNT_CONN_NUM] = "conn",
+
+ [CPS_CNT_GTFD] = "GREATER-THAN-MAX-FD",
+ [CPS_CNT_SOCKET_ERR] = "socket-err",
+ [CPS_CNT_BIND_ERR] = "bind-err",
+ [CPS_CNT_CONNECT_ERR] = "connect-err",
+ [CPS_CNT_REUSEADDR_ERR] = "reuseaddr-err",
+ [CPS_CNT_NODELAY_ERR] = "nodelay-err",
+ [CPS_CNT_NONBLOCK_ERR] = "nonblock-err",
+ [CPS_CNT_ACCEPT_ERR] = "accept-err",
+ [CPS_CNT_SEND_ERR] = "send-err",
+ [CPS_CNT_RECV_ERR] = "recv-err",
+ [CPS_CNT_EPOLL_ERR] = "epoll-err",
+ [CPS_CNT_ERR_EVENT] = "err-event",
+ [CPS_CNT_FD_ERR] = "cid-err",
+};
+
+struct cps_var cps = { 0 };
+
+void
+cps_title ()
+{
+ out ("------------------------------------------------------------\n");
+ out (" cps test %s\n", cps.client ? "client" : "server");
+ out
+ (" total server: %d total thread: %d report interval: %ds request:%d response: %d CPU NUM: %d\n",
+ cps.server_num, cps.thread_num, cps.interval, cps.req_len, cps.res_len,
+ cps.CPU_NUM);
+ if (cps.client)
+ {
+ out (" total client: %d test time: %ds defalut rate:%lu\n",
+ cps.client_num, cps.test_time, cps.rate);
+ }
+ else
+ {
+ }
+ out ("------------------------------------------------------------\n");
+}
+
+inline static char *
+cps_tip (char *pos, char tip)
+{
+ *pos++ = '|';
+ *pos++ = tip;
+ *pos++ = ':';
+ *pos++ = ' ';
+ return pos;
+}
+
+inline static char *
+cps_fmt (char *pos, uint64_t val, int *size)
+{
+ int s = r_uint (pos, val, *size);
+ pos += s;
+ *pos++ = ' ';
+ if (s > *size)
+ *size = s;
+ return pos;
+}
+
+inline static char *
+cps_format (char *pos, char tip, uint64_t val, uint64_t nsec, int *size)
+{
+ pos = cps_tip (pos, tip);
+
+ if (cps.more)
+ pos = cps_fmt (pos, val, size);
+
+ pos = cps_fmt (pos, lb_gdiv (val, nsec), size + 1);
+
+ return pos;
+}
+
+void
+cps_output (int index, struct cps_stat *stat, uint64_t nsec)
+{
+ struct fmtsize
+ {
+ int s_init[2];
+ int s_conn[3];
+ int s_recv[3];
+ int s_send[3];
+ int s_fail[2];
+ };
+ static struct fmtsize size = { 0 };
+ static int space_line = 0;
+ static char buf[512];
+
+ char *pos = buf;
+ int i, cnt_num = 0;
+
+ if (!stat->rec[CPS_REC_INIT] && !stat->rec[CPS_REC_CONN] &&
+ !stat->rec[CPS_REC_RECV] && !stat->rec[CPS_REC_SEND]
+ && !stat->rec[CPS_REC_FAIL])
+ {
+ for (i = 0; i < CPS_CNT_NUM; ++i)
+ {
+ if (stat->cnt[i])
+ break;
+ }
+ if (i >= CPS_CNT_NUM)
+ {
+ if (index < 0 && space_line++ == 0)
+ {
+ out ("\n");
+ memset (&size, 0, sizeof (size));
+ }
+ return;
+ }
+ }
+
+ space_line = 0;
+
+ if (index < 0)
+ pos += sprintf (pos, " sum ");
+ else
+ pos += sprintf (pos, " %3d ", index);
+
+ pos =
+ cps_format (pos, (cps.client ? 'C' : 'A'), stat->rec[CPS_REC_INIT], nsec,
+ size.s_init);
+ pos = cps_format (pos, 'E', stat->rec[CPS_REC_CONN], nsec, size.s_conn);
+ if (cps.client)
+ {
+ pos = cps_format (pos, 'S', stat->rec[CPS_REC_SEND], nsec, size.s_send);
+ pos = cps_format (pos, 'R', stat->rec[CPS_REC_RECV], nsec, size.s_recv);
+ }
+ else
+ {
+ pos = cps_format (pos, 'R', stat->rec[CPS_REC_RECV], nsec, size.s_recv);
+ pos = cps_format (pos, 'S', stat->rec[CPS_REC_SEND], nsec, size.s_send);
+ }
+ pos = cps_format (pos, 'F', stat->rec[CPS_REC_FAIL], nsec, size.s_fail);
+
+ pos = cps_tip (pos, 'T');
+ pos =
+ cps_fmt (pos,
+ lb_sdiv (stat->rec[CPS_REC_CONN_TIME], stat->rec[CPS_REC_CONN]),
+ &size.s_conn[2]);
+ if (cps.client)
+ {
+ pos =
+ cps_fmt (pos,
+ lb_sdiv (stat->rec[CPS_REC_SEND_TIME],
+ stat->rec[CPS_REC_SEND]), &size.s_send[2]);
+ pos =
+ cps_fmt (pos,
+ lb_sdiv (stat->rec[CPS_REC_RECV_TIME],
+ stat->rec[CPS_REC_RECV]), &size.s_recv[2]);
+ }
+ else
+ {
+ pos =
+ cps_fmt (pos,
+ lb_sdiv (stat->rec[CPS_REC_RECV_TIME],
+ stat->rec[CPS_REC_RECV]), &size.s_recv[2]);
+ pos =
+ cps_fmt (pos,
+ lb_sdiv (stat->rec[CPS_REC_SEND_TIME],
+ stat->rec[CPS_REC_SEND]), &size.s_send[2]);
+ }
+
+ *pos++ = '|';
+ *pos = 0;
+
+ out ("%s", buf);
+
+ for (i = 0; i < CPS_CNT_NUM; ++i)
+ {
+ if (stat->cnt[i])
+ {
+ if (cnt_num++ == 0)
+ out (" { %s:%s", cps_stat_name[i], f_uint (stat->cnt[i]));
+ else
+ out (" %s:%s", cps_stat_name[i], f_uint (stat->cnt[i]));
+ }
+ }
+
+ if (cnt_num)
+ out (" }\n");
+ else
+ out ("\n");
+
+ for (i = 1; i < CPS_ERR_NUM; ++i)
+ {
+ if (stat->err[i])
+ out ("<E%d:%s> %s\n", i, f_uint (stat->err[i]), strerror (i));
+ }
+ if (stat->err[0])
+ out ("<E-:%s> Other error\n", f_uint (stat->err[0]));
+}
+
+void
+cps_close ()
+{
+ cps.run_state = CPS_CLOSING;
+}
+
+void
+cps_timer (uint64_t nsec)
+{
+ const static struct timespec delay = {.tv_sec = 0,.tv_nsec =
+ CPS_DELAY_MS * 1000 * 1000
+ };
+
+ int i, j;
+ struct cps_stat sum = { 0 };
+ struct cps_stat *curr = cps.curr;
+
+ cps.curr = cps.next;
+ cps.next = curr;
+
+ /*wait for cps.curr use */
+ (void) nanosleep (&delay, NULL);
+
+ for (i = 0; i < cps.thread_num; ++i, ++curr)
+ {
+ struct cps_thread *thread = cps.thread[i];
+
+ curr->cnt[CPS_CNT_CONN_NUM] = thread->conn_num;
+ if (cps.verbose)
+ cps_output (thread->index, curr, nsec);
+
+ for (j = 0; j < CPS_REC_NUM; ++j)
+ {
+ sum.rec[j] += curr->rec[j];
+ curr->rec[j] = 0;
+ }
+
+ for (j = 0; j < CPS_CNT_NUM; ++j)
+ {
+ sum.cnt[j] += curr->cnt[j];
+ curr->cnt[j] = 0;
+ }
+
+ for (j = 0; j < CPS_ERR_NUM; ++j)
+ {
+ sum.err[j] += curr->err[j];
+ curr->err[j] = 0;
+ }
+ }
+
+ cps_output (-1, &sum, nsec);
+}
+
+int
+cps_loop ()
+{
+ const static struct timespec timeout = {.tv_sec = 0,.tv_nsec =
+ CPS_TIMER_MS * 1000 * 1000
+ };
+
+ struct timespec begin, from;
+ time_t next_time = cps.interval;
+
+ LB_TIME (begin);
+ from = begin;
+
+ while (cps.run_state == CPS_RUNNING)
+ {
+ struct timespec now;
+
+ (void) nanosleep (&timeout, NULL);
+
+ LB_TIME (now);
+
+ if (cps.client)
+ {
+ if (LB_CMP_S (now, begin, cps.test_time))
+ cps_close ();
+ }
+
+ if (!LB_CMP_S (now, begin, next_time))
+ continue;
+
+ cps_timer (LB_SUB_NS (now, from));
+
+ from = now;
+ next_time += cps.interval;
+ }
+
+ while (cps.run_state == CPS_CLOSING && cps.active_thread)
+ {
+ (void) nanosleep (&timeout, NULL);
+ }
+
+ return 0;
+}
+
+int
+cps_start ()
+{
+ int i;
+ void *(*proc) (void *);
+ const char *name;
+
+ cps.conn =
+ (struct cps_conn *) malloc (sizeof (struct cps_conn) * CPS_MAX_FD);
+ ERR_RETURN (!cps.conn, -1, "Out of memory\n");
+
+ if (cps.thread_num <= 0)
+ {
+ struct cps_thread *thread = cps_new_thread ();
+ ERR_RETURN (!thread, -1, "Out of memory\n");
+
+ cps.server_num = 1;
+ thread->server_num = 1;
+ thread->s_addr[0].sin_family = AF_INET;
+ thread->s_addr[0].sin_port = htons (CPS_PORT_DEF);
+ if (cps.client)
+ {
+ cps.client_num = 1;
+ thread->client_num = 1;
+ thread->c_addr_num = 1;
+ thread->s_addr[0].sin_addr.s_addr = htonl (0x7F000001);
+ }
+ else
+ {
+ thread->s_addr[0].sin_addr.s_addr = INADDR_ANY;
+ }
+ }
+ else if (cps.client)
+ {
+ for (i = 0; i < cps.thread_num; ++i)
+ {
+ if (cps.thread[i]->client_num)
+ continue;
+ cps.thread[i]->client_num = 1;
+ cps.thread[i]->c_addr[0].ip = INADDR_ANY;
+ cps.thread[i]->c_addr[0].ip_num = 1;
+ cps.client_num++;
+ }
+ }
+
+ if (cps.req_len <= 0)
+ cps.req_len = CPS_REQ_DEF;
+ if (cps.res_len <= 0)
+ cps.res_len = CPS_RES_DEF;
+ if (cps.evnum <= 0)
+ cps.evnum = CPS_EVNUM_DEF;
+ if (cps.interval <= 0)
+ cps.interval = CPS_INTERVAL_DEF;
+ if (cps.test_time <= 0)
+ cps.test_time = CPS_TIME_DEF;
+ if (cps.rate == 0)
+ cps.rate = CPS_RATE_DEF;
+
+ cps.curr = cps.records[0];
+ cps.next = cps.records[1];
+
+ if (cps.client)
+ {
+ proc = cps_c_thread;
+ name = "client";
+ }
+ else
+ {
+ proc = cps_s_thread;
+ name = "server";
+ }
+
+ cps_title ();
+
+ for (i = 0; i < cps.thread_num; ++i)
+ {
+ if (cps.thread[i]->rate == 0)
+ cps.thread[i]->rate = cps.rate;
+
+ cps.thread[i]->epfd = _epoll_create (CPS_EPSIZE);
+ ERR_RETURN (cps.thread[i]->epfd < 0, -1, "epoll_create(%d)=%d:%d\n",
+ CPS_EPSIZE, cps.thread[i]->epfd, errno);
+
+ cps.thread[i]->tid =
+ lb_thread (proc, cps.thread[i], "cps-%s-%d", name, i);
+ ERR_RETURN (cps.thread[i]->tid == 0, -1, "Create thread %s-%d failed",
+ name, i);
+
+ if (cps.thread[i]->core >= 0)
+ {
+ int ret = lb_setcpu (cps.thread[i]->tid, cps.thread[i]->core);
+ WRN (ret != 0, "Bind core error thread:%d\n", i);
+ }
+
+ __sync_fetch_and_add (&cps.active_thread, 1);
+ }
+
+ cps.run_state = CPS_RUNNING;
+ futex_wake (&cps.run_state, cps.thread_num);
+
+ return 0;
+}
+
+void
+cps_exit ()
+{
+ int i;
+
+ cps.run_state = CPS_EXIT;
+
+ for (i = 0; i < cps.thread_num; ++i)
+ {
+ int fd;
+ struct cps_thread *thread = cps.thread[i];
+
+ if (!thread)
+ continue;
+
+ if (thread->tid)
+ pthread_join (thread->tid, NULL);
+
+ if (thread->epfd >= 0)
+ _close (thread->epfd);
+
+ for (fd = thread->server; fd >= 0; fd = CPS_CONN (fd)->next)
+ _close (fd);
+
+ for (fd = thread->conn; fd >= 0; fd = CPS_CONN (fd)->next)
+ _close (fd);
+
+ cps.thread[i] = NULL;
+ free (thread);
+ }
+
+ if (cps.conn)
+ free (cps.conn);
+}
+
+void
+cps_break (int s)
+{
+ DBG (" SIGNALED %d running:%d\n", s, cps.run_state);
+ out ("\n");
+
+ if (cps.run_state == CPS_INIT || cps.run_state == CPS_RUNNING)
+ cps_close ();
+ else if (cps.run_state != CPS_EXIT)
+ cps_exit ();
+ else
+ exit (1);
+}
+
+void
+cps_sigpipe (int s)
+{
+ DBG ("SIGPIPE\n");
+}
+
+int
+cps_init ()
+{
+ struct sigaction s = { 0 };
+
+ (void) sigemptyset (&s.sa_mask);
+
+ s.sa_flags = SA_NODEFER;
+ s.sa_handler = (void *) cps_break;
+ (void) sigaction (SIGINT, &s, NULL);
+ (void) sigaction (SIGQUIT, &s, NULL);
+
+ s.sa_handler = cps_sigpipe;
+ (void) sigaction (SIGPIPE, &s, NULL);
+
+// lb_sigsegv_setup();
+
+ cps.CPU_NUM = get_nprocs ();
+
+ if (cps.CPU_NUM <= 0)
+ cps.CPU_NUM = 1;
+
+ return 0;
+}
+
+#ifndef EXEC_CPS_C_
+#define EXEC_CPS_C_
+
+#define CPS_OPTIONS "d:e:T:t:r:ci:" DBGOPT "mvh"
+
+static const struct option cps_options[] = {
+ {"data", 1, 0, 'd'},
+ {"interval", 1, 0, 'i'},
+ {"evnum", 1, 0, 'e'},
+ {"client", 0, 0, 'c'},
+ {"thread", 1, 0, 't'},
+ {"rate", 1, 0, 'r'},
+ {"time", 1, 0, 'T'},
+ DBGOPT_LONG {"more", 0, 0, 'm'},
+ {"verbose", 0, 0, 'v'},
+ {"help", 0, 0, 'h'},
+ {0, 0, 0, 0}
+};
+
+enum
+{
+ CPSOPT_SERVER = 0,
+ CPSOPT_S,
+ CPSOPT_CLIENT,
+ CPSOPT_C,
+ CPSOPT_RATE,
+ CPSOPT_CORE,
+ CPSOPT_CF,
+ CPSOPT_SF,
+};
+
+char *const cps_tokens[] = {
+ [CPSOPT_SERVER] = "server",
+ [CPSOPT_S] = "s",
+ [CPSOPT_CLIENT] = "client",
+ [CPSOPT_C] = "c",
+ [CPSOPT_RATE] = "rate",
+ [CPSOPT_CORE] = "core",
+ [CPSOPT_CF] = "cf",
+ [CPSOPT_SF] = "sf",
+ NULL
+};
+
+void
+cps_usage (const char *name)
+{
+ out ("USAGE: %s [OPTIONS] [SERVER-ADDRESS] # %s version\n", name,
+ VERSION_NAME);
+ out (" Options:\n");
+ out
+ (" -i, --interval=# report time(default: %ds max:%ds)\n",
+ CPS_INTERVAL_DEF, CPS_INTERVAL_MAX);
+ out
+ (" -c, --client server address list for one thread\n");
+ out
+ (" -e, --evnum epoll event number(default:%d max:%d)\n",
+ CPS_EVNUM_DEF, CPS_EVNUM_MAX);
+ out
+ (" -T, --time=# C test time(default: %ds max:%ds)\n",
+ CPS_TIME_DEF, CPS_TIME_MAX);
+ out
+ (" -d, --data=#[:#] C request and response data length(default:%d:%d max:%d)\n",
+ CPS_REQ_DEF, CPS_RES_DEF, CPS_DATA_MAX);
+ out
+ (" -r, --rate=#[k|m|w] C global connect rate per each thread(CPS, default: %d max:%d)\n",
+ CPS_RATE_DEF, CPS_RATE_MAX);
+ out
+ (" -t, --thread=CONFIG set one net and thread(max: %d)\n",
+ CPS_THREAD_MAX);
+ out
+ (" server=X.X.X.X:P server address set(max: %d)\n",
+ CPS_SERVER_MAX);
+ out
+ (" core=# bind to core\n");
+ out
+ (" client=X.X.X.X C client ip address set(max: %d max ip: %d)\n",
+ CPS_CLIENT_IAS_MAX, CPS_CLIENT_MAX);
+ out
+ (" rate=# C set connect rate for this thread(default: use global set)\n");
+ out
+ (" cf C client loop first(default: both)\n");
+ out
+ (" sf C server loop first(default: both)\n");
+#ifdef DEBUG
+ out
+ (" -D, --debug show debug information\n");
+#endif
+ out
+ (" -m, --more show more statistics\n");
+ out
+ (" -v, --verbose show thread statistics\n");
+ out (" -h, --help help\n");
+ out (" IMPORTANT:\n");
+ out
+ (" socket() EMFILE(%d) error: ulimit -n 1048576\n",
+ EMFILE);
+ out
+ (" bind() EADDRINUSE(%d) error: echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle\n",
+ EADDRINUSE);
+ out
+ (" connect() EADDRNOTAVAIL(%d) error: echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse\n",
+ EADDRNOTAVAIL);
+ out
+ (" echo \"3000 65534\" > /proc/sys/net/ipv4/ip_local_port_range\n");
+}
+
+inline static uint64_t
+cps_p_rate (const char *arg)
+{
+ uint64_t rate = p_uint (arg, CPS_RATE_MAX, &arg);
+
+ if (!arg)
+ return (uint64_t) - 1ul;
+
+ switch (*arg)
+ {
+ case 'm': /* fall through */
+ case 'M':
+ rate *= 100; /* fall through */
+ case 'w': /* fall through */
+ case 'W':
+ rate *= 10; /* fall through */
+ case 'k': /* fall through */
+ case 'K':
+ rate *= 1000;
+ arg++;
+ break;
+ }
+
+ if (*arg)
+ return (uint64_t) - 1ul;
+
+ return rate;
+}
+
+int
+cps_opts (char *opts)
+{
+ struct cps_thread *thread;
+ struct inaddrs *client;
+ struct sockaddr_in *server;
+
+ ERR_RETURN (cps.thread_num >= CPS_THREAD_MAX, -1,
+ "Too many thread, max %d\n", CPS_THREAD_MAX);
+
+ thread = cps_new_thread ();
+ ERR_RETURN (!thread, -1, "Out of memory\n");
+ server = thread->s_addr;
+ client = thread->c_addr;
+
+ while (*opts)
+ {
+ char *value;
+ const char *end;
+ int ret = getsubopt (&opts, cps_tokens, &value);
+ switch (ret)
+ {
+ case CPSOPT_SERVER:
+ case CPSOPT_S:
+ {
+ int i;
+ uint64_t num;
+ struct inaddrs addr;
+
+ end = p_addr_set (value, &addr, PA_DEF_PORT | CPS_PORT_DEF);
+ ERR_RETURN (!end
+ || *end, -1, "Invalid server address '%s'.\n", value);
+
+ num = (uint64_t) addr.ip_num * addr.port_num;
+ ERR_RETURN (num > CPS_SERVER_MAX - thread->server_num, -1,
+ "Too many server, max %d\n", CPS_SERVER_MAX);
+
+ for (i = 0; i < addr.ip_num; ++i)
+ {
+ uint32_t ip = addr.ip + i;
+ uint16_t j;
+ for (j = 0; j < addr.port_num; ++j)
+ {
+ server->sin_family = AF_INET;
+ server->sin_addr.s_addr = htonl (ip);
+ server->sin_port = htons (addr.port + j);
+ server++;
+ }
+ }
+ thread->server_num += num;
+ break;
+ }
+ case CPSOPT_CLIENT:
+ case CPSOPT_C:
+ {
+ ERR_RETURN (thread->c_addr_num >= CPS_CLIENT_IAS_MAX, -1,
+ "Too many client set, max %d\n", CPS_CLIENT_IAS_MAX);
+
+ end = p_addr_set (value, client, PA_NO_PORT);
+ ERR_RETURN (!end
+ || *end, -1, "Invalid client address '%s'.\n", value);
+ ERR_RETURN (client->ip_num > CPS_CLIENT_MAX - thread->client_num,
+ -1, "Too many client, max %d\n", CPS_CLIENT_MAX);
+
+ client->port = 0;
+ client->port_num = 1;
+ thread->c_addr_num++;
+ thread->client_num += client->ip_num;
+ client++;
+ break;
+ }
+ case CPSOPT_RATE:
+ thread->rate = cps_p_rate (value);
+ ERR_RETURN (thread->rate > CPS_RATE_MAX, -1,
+ "Invalid thread rate '%s'\n", value);
+ break;
+
+ case CPSOPT_CF:
+ thread->loop = CPS_LOOP_CF;
+ break;
+ case CPSOPT_SF:
+ thread->loop = CPS_LOOP_SF;
+ break;
+
+ case CPSOPT_CORE:
+ thread->core = (int) p_int (value, cps.CPU_NUM - 1, &end);
+ ERR_RETURN (!end || *end
+ || thread->core <= 0, -1, "Invalid bind core '%s'.\n",
+ value);
+ break;
+
+ default:
+ ERR_RETURN (1, -1, "Unknown thread option '%s'\n", value);
+ }
+ }
+
+ ERR_RETURN (!thread->server_num, -1, "No server set for net %d\n",
+ thread->index);
+
+ cps.server_num += thread->server_num;
+ cps.client_num += thread->client_num;
+ return 0;
+}
+
+int
+cps_args (int argc, char *argv[])
+{
+ int opt, index;
+
+ while (EOF !=
+ (opt = getopt_long (argc, argv, CPS_OPTIONS, cps_options, &index)))
+ {
+ const char *end;
+
+ switch (opt)
+ {
+ case 't':
+ if (cps_opts (optarg))
+ return -1;
+ break;
+
+ case 'c':
+ cps.client = 1;
+ break;
+
+ case 'd':
+ cps.req_len = (int) p_int (optarg, CPS_DATA_MAX, &end);
+ ERR_RETURN (!end, -1, "Invalid data length '%s'\n", optarg);
+ if (*end == ':')
+ {
+ end++;
+ cps.res_len = (int) p_int (end, CPS_DATA_MAX, &end);
+ ERR_RETURN (!end, -1, "Invalid response data length '%s'\n",
+ optarg);
+ }
+ else
+ {
+ cps.res_len = cps.req_len;
+ }
+ ERR_RETURN (*end != 0, -1, "Invalid data length '%s'\n", optarg);
+ break;
+
+ case 'i':
+ cps.interval = (int) p_int (optarg, CPS_INTERVAL_MAX, &end);
+ ERR_RETURN (!end || *end, -1, "Invalid interval '%s'\n", optarg);
+ break;
+ case 'e':
+ cps.evnum = (int) p_int (optarg, CPS_EVNUM_MAX, &end);
+ ERR_RETURN (!end
+ || *end, -1, "Invalid event number '%s'\n", optarg);
+ break;
+ case 'T':
+ cps.test_time = (int) p_int (optarg, CPS_TIME_MAX, &end);
+ ERR_RETURN (!end || *end, -1, "Invalid test time '%s'\n", optarg);
+ break;
+ case 'r':
+ cps.rate = cps_p_rate (optarg);
+ ERR_RETURN (cps.rate > CPS_RATE_MAX, -1, "Invalid rate '%s'\n",
+ optarg);
+ break;
+ case 'v':
+ cps.verbose = 1;
+ break;
+ case 'm':
+ cps.more = 1;
+ break;
+
+#ifdef DEBUG
+ case 'D':
+ enable_debug = 1;
+ break;
+#endif
+ case 'h':
+ cps_usage (argv[0]);
+ exit (0);
+ case '?':
+ err ("Invalid arguments\n");
+ return -1;
+ default:
+ err ("Unknown option '%c'.\n", opt);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#endif /* #ifndef EXEC_CPS_C_ */
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ if (cps_init ())
+ return 1;
+
+ cps_args (argc, argv) || cps_start () || cps_loop ();
+
+ cps_exit ();
+ return 0;
+}
diff --git a/thirdparty/apps/testapp/cps/cps.h b/thirdparty/apps/testapp/cps/cps.h
new file mode 100644
index 0000000..9b949f3
--- /dev/null
+++ b/thirdparty/apps/testapp/cps/cps.h
@@ -0,0 +1,283 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef _CPS_H_
+#define _CPS_H_
+
+#define CPS_FRAG_NUM 64
+#define CPS_FRAG_NS (20 * 1000 * 1000) /* 20 ms */
+#define CPS_FRAG_LOOP (CPS_FRAG_NS * CPS_FRAG_NUM) /* 1.28 s */
+
+#define CPS_TIMER_MS 100
+#define CPS_DELAY_MS 5
+
+#define CPS_MAX_FD (16 * 1024 * 1024) /* 10M */
+#define CPS_CONN_MAX (256 * 1024)
+
+#define CPS_EPSIZE (1 * 1000) /* =1k */
+#define CPS_EPWAIT_MS 200 /* ms */
+
+#define CPS_THREAD_MAX 128
+#define CPS_SERVER_MAX 32
+#define CPS_CLIENT_MAX 256
+#define CPS_CLIENT_IAS_MAX 32
+
+#define CPS_PORT_DEF 58166
+#define CPS_EVNUM_DEF 256
+#define CPS_EVNUM_MAX 1024
+#define CPS_TIME_DEF 300
+#define CPS_TIME_MAX (60 * 60 * 24 * 7) /* 604800s = 1 week */
+#define CPS_RATE_DEF 10000 /* 1w */
+#define CPS_RATE_MAX (100 * 1000 * 1000) /* 100m */
+#define CPS_REQ_DEF 1
+#define CPS_RES_DEF 1
+#define CPS_DATA_MAX 4096
+#define CPS_INTERVAL_DEF 10 /* s */
+#define CPS_INTERVAL_MAX 3600 /* s */
+
+#define CPS_ERR_NUM 256
+
+#define CPS_CONN_SID (-1)
+#define CPS_EV_DATA(sid, fd) (((uint64_t)(uint32_t)(sid) << 32) | (uint64_t)(uint32_t)(fd))
+#define CPS_EV_FD(u64) ((int)(uint32_t)(u64))
+#define CPS_EV_SID(u64) ((int)(uint32_t)((u64) >> 32))
+
+enum
+{
+ CPS_LOOP_BOTH = 0,
+ CPS_LOOP_CF,
+ CPS_LOOP_SF,
+};
+
+enum
+{
+ CPS_ERROR = -2,
+ CPS_EXIT = -1,
+
+ CPS_INIT = 0,
+
+ CPS_RUNNING = 1,
+ CPS_CLOSING = 2,
+};
+
+enum
+{
+ CPS_CNT_CONN_MAX,
+ CPS_CNT_CONN_NUM,
+
+ CPS_CNT_GTFD,
+ CPS_CNT_SOCKET_ERR,
+ CPS_CNT_BIND_ERR,
+ CPS_CNT_ACCEPT_ERR,
+ CPS_CNT_CONNECT_ERR,
+ CPS_CNT_REUSEADDR_ERR,
+ CPS_CNT_NODELAY_ERR,
+ CPS_CNT_NONBLOCK_ERR,
+ CPS_CNT_SEND_ERR,
+ CPS_CNT_RECV_ERR,
+ CPS_CNT_EPOLL_ERR,
+ CPS_CNT_ERR_EVENT,
+ CPS_CNT_FD_ERR,
+
+ CPS_CNT_NUM
+};
+
+#define CPS_CNT_ITEM(thread, id) (cps.curr[(thread)->index].cnt[(id)])
+
+#define CPS_CNT_INC(thread, id) (++CPS_CNT_ITEM((thread), (id)))
+#define CPS_CNT_INC_E(thread, id, e) do { \
+ struct cps_stat *_stat = cps.curr + (thread)->index; \
+ ++_stat->cnt[(id)]; \
+ if ((e) >= CPS_ERR_NUM) ++_stat->err[0];\
+ else ++_stat->err[(e)]; \
+} while(0)
+
+enum
+{
+ CPS_REC_INIT,
+
+ CPS_REC_CONN,
+ CPS_REC_CONN_TIME,
+
+ CPS_REC_RECV,
+ CPS_REC_RECV_TIME,
+
+ CPS_REC_SEND,
+ CPS_REC_SEND_TIME,
+
+ CPS_REC_FAIL,
+
+ CPS_REC_NUM
+};
+
+#define CPS_REC_INC(thread, id) (++cps.curr[(thread)->index].rec[(id)])
+
+#define CPS_REC_TIMED_INC(thread, id, last) do { \
+ struct timespec _time; \
+ struct cps_stat *_stat = cps.curr + (thread)->index; \
+ LB_TIME(_time); \
+ _stat->rec[(id)]++; \
+ _stat->rec[(id) + 1] += LB_SUB_NS(_time, (last)); \
+ (last) = _time; \
+} while (0)
+
+struct cps_conn
+{
+ union
+ {
+ int size;
+ int sid;
+ };
+ int next;
+ int *prev;
+ struct timespec last;
+
+ struct timespec create_time;
+};
+
+struct cps_stat
+{
+ uint64_t cnt[CPS_CNT_NUM];
+ uint64_t rec[CPS_REC_NUM];
+ uint64_t err[CPS_ERR_NUM];
+};
+
+struct cps_thread
+{
+ int epfd;
+ int index;
+ int core;
+ int loop;
+
+ int server;
+ int conn;
+ int conn_num;
+
+ int server_num;
+ int client_num;
+ int c_addr_num;
+
+ uint64_t rate;
+ pthread_t tid;
+
+ struct sockaddr_in s_addr[CPS_SERVER_MAX];
+ struct inaddrs c_addr[CPS_CLIENT_MAX];
+ struct epoll_event event[CPS_EVNUM_MAX];
+};
+
+struct cps_var
+{
+ int run_state;
+ int CPU_NUM;
+
+ int verbose;
+ int more;
+ int client;
+ int evnum;
+
+ int req_len;
+ int res_len;
+
+ int test_time;
+ int interval;
+
+ int active_thread;
+ int thread_num;
+ int server_num;
+ int client_num;
+
+ uint64_t rate;
+
+ struct cps_stat *curr;
+ struct cps_stat *next;
+
+ struct cps_conn *conn;
+ struct cps_thread *thread[CPS_THREAD_MAX];
+
+ struct cps_stat records[2][CPS_THREAD_MAX];
+};
+
+extern struct cps_var cps;
+
+inline static struct cps_conn *
+CPS_CONN (int fd)
+{
+ return cps.conn + fd;
+}
+
+inline static void
+cps_add_server (struct cps_thread *thread, int fd, int sid)
+{
+ struct cps_conn *conn = CPS_CONN (fd);
+
+ conn->sid = sid;
+ conn->next = thread->server;
+ conn->prev = &thread->server;
+ LB_TIME (conn->last);
+ if (thread->server >= 0)
+ CPS_CONN (thread->server)->prev = &conn->next;
+ thread->server = fd;
+}
+
+inline static void
+cps_add_conn (struct cps_thread *thread, int fd, int size,
+ struct timespec *begin)
+{
+ struct cps_conn *conn = CPS_CONN (fd);
+
+ conn->size = size;
+ conn->last = *begin;
+ conn->next = thread->conn;
+ conn->prev = &thread->conn;
+ if (thread->conn >= 0)
+ CPS_CONN (thread->conn)->prev = &conn->next;
+ thread->conn = fd;
+
+ if (++thread->conn_num > CPS_CNT_ITEM (thread, CPS_CNT_CONN_MAX))
+ CPS_CNT_ITEM (thread, CPS_CNT_CONN_MAX) = thread->conn_num;
+ CPS_REC_TIMED_INC (thread, CPS_REC_CONN, conn->last);
+}
+
+inline static void
+cps_rem_conn (struct cps_thread *thread, int fd, struct cps_conn *conn)
+{
+ --thread->conn_num;
+
+ *conn->prev = conn->next;
+ if (conn->next >= 0)
+ CPS_CONN (conn->next)->prev = conn->prev;
+}
+
+inline static struct cps_thread *
+cps_new_thread ()
+{
+ struct cps_thread *thread = calloc (1, sizeof (struct cps_thread));
+
+ if (thread)
+ {
+ thread->index = cps.thread_num;
+ thread->epfd = -1;
+ thread->core = -1;
+ thread->conn = -1;
+ thread->server = -1;
+
+ cps.thread[cps.thread_num++] = thread;
+ }
+
+ return thread;
+}
+
+#endif /* #ifndef _CPS_H_ */
diff --git a/thirdparty/apps/testapp/cps/cps_c.c b/thirdparty/apps/testapp/cps/cps_c.c
new file mode 100644
index 0000000..dfcc341
--- /dev/null
+++ b/thirdparty/apps/testapp/cps/cps_c.c
@@ -0,0 +1,394 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+#include "cps.h"
+
+struct cps_frag
+{
+ struct timespec begin;
+ uint64_t count;
+};
+
+struct cps_run
+{
+ struct cps_frag frag[CPS_FRAG_NUM];
+ uint64_t total;
+ uint32_t fid;
+ int sid, ci, ii;
+ struct sockaddr_in addr;
+};
+
+inline static void
+cps_c_next (struct cps_thread *thread, struct cps_run *run)
+{
+ if (thread->loop == CPS_LOOP_CF)
+ {
+ if (++run->ii >= thread->c_addr[run->ci].ip_num)
+ {
+ run->ii = 0;
+ if (++run->ci == thread->client_num)
+ {
+ run->ci = 0;
+ if (++run->sid >= thread->server_num)
+ run->sid = 0;
+ }
+ }
+ run->addr.sin_addr.s_addr =
+ htonl (thread->c_addr[run->ci].ip + run->ii);
+ }
+ else if (thread->loop == CPS_LOOP_SF)
+ {
+ if (++run->sid >= thread->server_num)
+ {
+ run->sid = 0;
+ if (++run->ii >= thread->c_addr[run->ci].ip_num)
+ {
+ run->ii = 0;
+ if (++run->ci >= thread->client_num)
+ run->ci = 0;
+ }
+ run->addr.sin_addr.s_addr =
+ htonl (thread->c_addr[run->ci].ip + run->ii);
+ }
+ }
+ else
+ {
+ if (++run->sid == thread->server_num)
+ run->sid = 0;
+ if (++run->ii >= thread->c_addr[run->ci].ip_num)
+ {
+ run->ii = 0;
+ if (++run->ci == thread->client_num)
+ run->ci = 0;
+ }
+ run->addr.sin_addr.s_addr =
+ htonl (thread->c_addr[run->ci].ip + run->ii);
+ }
+}
+
+inline static int
+cps_c_trigger (struct cps_thread *thread, struct cps_run *run)
+{
+ uint64_t nsec, num;
+ struct timespec now;
+ struct cps_frag *frag = &run->frag[run->fid % CPS_FRAG_NUM];
+ struct cps_frag *from = &run->frag[(run->fid + 1) % CPS_FRAG_NUM];
+
+ LB_TIME (now);
+
+ if (LB_CMP_NS (now, frag->begin, CPS_FRAG_NS))
+ {
+ /* move to next fragment */
+ frag = from;
+ from = &run->frag[++run->fid % CPS_FRAG_NUM];
+ run->total -= frag->count;
+ frag->count = 0;
+ frag->begin = now;
+ }
+
+ nsec = LB_SUB_NS (now, from->begin);
+ num = thread->rate * nsec / NSOFS;
+ if (num >= run->total)
+ {
+ run->total++;
+ frag->count++;
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+cps_c_create (struct cps_thread *thread, struct cps_run *run)
+{
+ int fd, ret;
+ struct timespec begin;
+ struct epoll_event event;
+
+ CPS_REC_INC (thread, CPS_REC_INIT);
+ LB_TIME (begin);
+
+ fd = _socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd < 0)
+ {
+ CPS_CNT_INC_E (thread, CPS_CNT_SOCKET_ERR, errno);
+ CPS_REC_INC (thread, CPS_REC_FAIL);
+ DBG ("->socket(...)=%d:%d\n", fd, errno);
+ return -1;
+ }
+
+ if (fd >= CPS_MAX_FD)
+ {
+ CPS_CNT_INC (thread, CPS_CNT_GTFD);
+ goto ERR;
+ }
+
+ ret = set_reuseaddr (fd, 1);
+ if (ret)
+ CPS_CNT_INC_E (thread, CPS_CNT_REUSEADDR_ERR, errno);
+
+ ret = _bind (fd, (struct sockaddr *) &run->addr, sizeof (run->addr));
+ if (ret)
+ {
+ CPS_CNT_INC_E (thread, CPS_CNT_BIND_ERR, errno);
+ DBG ("->bind(%d, %s)=%d:%d\n", fd, f_inaddr (&run->addr), ret, errno);
+ goto ERR;
+ }
+ ret = set_nodelay (fd, 1);
+ if (ret)
+ CPS_CNT_INC_E (thread, CPS_CNT_NODELAY_ERR, errno);
+
+ ret = set_nonblock (fd);
+ if (ret)
+ {
+ CPS_CNT_INC_E (thread, CPS_CNT_NONBLOCK_ERR, errno);
+ goto ERR;
+ }
+
+ ret =
+ _connect (fd, (struct sockaddr *) &thread->s_addr[run->sid],
+ sizeof (thread->s_addr[run->sid]));
+ if (ret)
+ {
+ const int e = errno;
+ if (e != EINPROGRESS)
+ {
+ CPS_CNT_INC_E (thread, CPS_CNT_CONNECT_ERR, e);
+ DBG ("->connect(%d, %s)=%d:%d\n", fd,
+ f_inaddr (&thread->s_addr[run->sid]), ret, errno);
+ goto ERR;
+ }
+ }
+
+ event.events = EPOLLIN | EPOLLOUT | EPOLLET;
+ event.data.u64 = CPS_EV_DATA (CPS_CONN_SID, fd);
+ ret = _epoll_ctl (thread->epfd, EPOLL_CTL_ADD, fd, &event);
+ if (ret)
+ {
+ CPS_CNT_INC_E (thread, CPS_CNT_EPOLL_ERR, errno);
+ DBG ("->epoll_ctl(%d, ADD, %d)=%d:%d\n", thread->epfd, fd, ret, errno);
+ goto ERR;
+ }
+
+ cps_add_conn (thread, fd, 0, &begin);
+
+ return 0;
+
+ERR:
+ _close (fd);
+ CPS_REC_INC (thread, CPS_REC_FAIL);
+ return -1;
+}
+
+int
+cps_c_io (struct cps_thread *thread, int fd, uint32_t events)
+{
+ int ret;
+ static char buf[CPS_DATA_MAX];
+
+// struct cps_server *server = &thread->server[sid];
+ struct cps_conn *conn = CPS_CONN (fd);
+
+ if (events & EPOLLERR)
+ {
+ CPS_CNT_INC (thread, CPS_CNT_ERR_EVENT);
+ DBG ("(%d, %d, %x) EPOLLERR\n", thread->index, fd, events);
+ goto ERR;
+ }
+
+ if (conn->size >= 0)
+ {
+ if (0 == (events & EPOLLOUT))
+ return 0;
+
+ while (1)
+ {
+ if (cps.run_state <= CPS_INIT)
+ return -1;
+
+ ret = _send (fd, buf, cps.req_len - conn->size, 0);
+ if (ret > 0)
+ {
+ conn->size += ret;
+ if (conn->size >= cps.req_len)
+ {
+ struct epoll_event event;
+ event.events = EPOLLIN;
+ event.data.u64 = CPS_EV_DATA (CPS_CONN_SID, fd);
+ conn->size = -cps.res_len;
+ ret = _epoll_ctl (thread->epfd, EPOLL_CTL_MOD, fd, &event);
+ if (ret)
+ {
+ CPS_CNT_INC_E (thread, CPS_CNT_EPOLL_ERR, errno);
+ DBG ("->epoll_ctl(%d, MOD, %d)=%d:%d\n", thread->epfd,
+ fd, ret, errno);
+ goto ERR;
+ }
+ CPS_REC_TIMED_INC (thread, CPS_REC_SEND, conn->last);
+ break;
+ }
+ }
+ else
+ {
+ if (ret < 0)
+ {
+ const int e = errno;
+ if (e == EWOULDBLOCK || e == EAGAIN)
+ return 0;
+ if (e == EINTR)
+ continue;
+ CPS_CNT_INC_E (thread, CPS_CNT_SEND_ERR, e);
+ }
+ else
+ {
+ CPS_CNT_INC (thread, CPS_CNT_SEND_ERR);
+ }
+ DBG ("->send(%d,, %d)=%d:%d\n", fd, cps.req_len - conn->size,
+ ret, errno);
+ goto ERR;
+ }
+ }
+ }
+
+ if (0 == (events & EPOLLIN))
+ return 0;
+
+ while (cps.run_state > CPS_INIT)
+ {
+ ret = _recv (fd, buf, -conn->size, 0);
+ if (ret > 0)
+ {
+ conn->size += ret;
+ if (conn->size >= 0)
+ {
+ /* receive success */
+ _close (fd);
+ CPS_REC_TIMED_INC (thread, CPS_REC_RECV, conn->last);
+ cps_rem_conn (thread, fd, conn);
+ return 0;
+ }
+ }
+ else
+ {
+ if (ret < 0)
+ {
+ const int e = errno;
+ if (e == EWOULDBLOCK || e == EAGAIN)
+ return 0; /*wait event */
+ if (e == EINTR) /* The receive was interrupted by delivery of a signal... */
+ continue; /*recv again */
+ CPS_CNT_INC_E (thread, CPS_CNT_RECV_ERR, e);
+ }
+ else
+ {
+ CPS_CNT_INC (thread, CPS_CNT_RECV_ERR);
+ }
+ DBG ("->recv(%d,, %d)=%d:%d\n", fd, -conn->size, ret, errno);
+ goto ERR; /* ret == 0 and not block meaning error */
+ }
+ }
+
+ DBG ("(%d, %d) cannot run there\n", thread->index, fd);
+
+ERR:
+ _close (fd);
+ CPS_REC_INC (thread, CPS_REC_FAIL);
+ cps_rem_conn (thread, fd, conn);
+ return -1;
+}
+
+void *
+cps_c_thread (void *arg)
+{
+ int i, num = 0;
+ struct cps_run run = { 0 };
+ struct cps_thread *thread = (struct cps_thread *) arg;
+ struct epoll_event *event = thread->event;
+
+ run.addr.sin_family = AF_INET;
+ run.addr.sin_port = htons (0);
+
+ out
+ ("[%d] initialize thread %ld client:%d server:%d rate:%lu core:%d epfd:%d\n",
+ thread->index, pthread_self (), thread->client_num, thread->server_num,
+ thread->rate, thread->core, thread->epfd);
+
+ futex_wait (&cps.run_state, CPS_INIT);
+
+ LB_TIME (run.frag[0].begin);
+ for (i = 1; i < CPS_FRAG_NUM; ++i)
+ run.frag[i].begin = run.frag[0].begin;
+
+ while (1)
+ {
+ /* open 1 connect */
+ if (cps.run_state == CPS_RUNNING)
+ {
+ if (cps_c_trigger (thread, &run))
+ {
+ cps_c_next (thread, &run);
+ cps_c_create (thread, &run);
+ }
+ }
+ else if (cps.run_state == CPS_CLOSING)
+ {
+ if (thread->conn_num <= 0)
+ break;
+ }
+ else
+ {
+ break;
+ }
+
+ /* process 1 event */
+ if (num > 0)
+ {
+ int fd = CPS_EV_FD (event->data.u64);
+ DBG ("epoll event:{sid:%d fd:%d e:%x}\n",
+ CPS_EV_SID (event->data.u64), fd, event->events);
+
+ if ((uint32_t) fd >= CPS_MAX_FD)
+ {
+ CPS_CNT_INC (thread, CPS_CNT_FD_ERR);
+ }
+ else
+ {
+ (void) cps_c_io (thread, fd, event->events);
+ }
+
+ num--;
+ event++;
+ }
+
+ /* wait events */
+ if (num <= 0)
+ {
+ event = thread->event;
+ num = _epoll_wait (thread->epfd, event, cps.evnum, 0); /* no wait */
+ if (num < 0)
+ {
+ int e = errno;
+ if (e != EINTR)
+ CPS_CNT_INC_E (thread, CPS_CNT_EPOLL_ERR, e);
+ }
+ }
+
+ }
+
+ __sync_fetch_and_sub (&cps.active_thread, 1);
+ return NULL;
+}
diff --git a/thirdparty/apps/testapp/cps/cps_s.c b/thirdparty/apps/testapp/cps/cps_s.c
new file mode 100644
index 0000000..57d41c7
--- /dev/null
+++ b/thirdparty/apps/testapp/cps/cps_s.c
@@ -0,0 +1,320 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+#include "cps.h"
+
+inline static void
+cps_s_close (struct cps_thread *thread)
+{
+ int fd;
+ struct epoll_event ev = { 0 };
+
+ for (fd = thread->server; fd >= 0; fd = CPS_CONN (fd)->next)
+ {
+ (void) _epoll_ctl (thread->epfd, EPOLL_CTL_DEL, fd, &ev);
+ _close (fd);
+ }
+
+ thread->server = -1;
+}
+
+int
+cps_s_listen (struct cps_thread *thread)
+{
+ int i;
+
+ for (i = 0; i < thread->server_num; ++i)
+ {
+ int fd, ret;
+ struct timespec dummy;
+ struct epoll_event event;
+ struct sockaddr_in *server = &thread->s_addr[i];
+
+ fd = _socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (fd < 0, -1, "socket()=%d:%d\n", fd, errno);
+
+ ret = _bind (fd, (struct sockaddr *) server, sizeof (*server));
+ ERR_RETURN (ret, -1, "bind(%d)=%d:%d\n", fd, ret, errno);
+
+ ret = set_nonblock (fd);
+ ERR_RETURN (ret, -1, "set_nonblock(%d)=%d:%d\n", fd, ret, errno);
+
+ ret = _listen (fd, SOMAXCONN);
+ ERR_RETURN (ret, -1, "listen(%d)=%d:%d\n", fd, ret, errno);
+
+ event.events = EPOLLIN | EPOLLET;
+ event.data.u64 = CPS_EV_DATA (i, fd);
+ ret = _epoll_ctl (thread->epfd, EPOLL_CTL_ADD, fd, &event);
+ ERR_RETURN (ret, -1, "epoll_ctl(%d, %d)=%d:%d\n", thread->epfd, fd, ret,
+ errno);
+
+ out ("[%d.%d:%d] listen on %s\n", thread->index, i, fd,
+ f_inaddr (server));
+
+ cps_add_server (thread, fd, i);
+ }
+
+ return 0;
+}
+
+int
+cps_s_accept (struct cps_thread *thread, int server_fd)
+{
+ while (cps.run_state == CPS_RUNNING)
+ {
+ int fd, ret;
+ struct timespec begin;
+ struct epoll_event event;
+#if defined(DEBUG)
+ struct sockaddr_in addr;
+ socklen_t len = sizeof (addr);
+#endif
+
+ LB_TIME (begin);
+
+#if defined(DEBUG) && 0
+ fd =
+ _accept4 (server_fd, (struct sockaddr *) &addr, &len, SOCK_NONBLOCK);
+#else
+ fd = _accept4 (server_fd, NULL, NULL, SOCK_NONBLOCK);
+#endif
+ if (fd < 0)
+ {
+ int e = errno;
+ if (e == EAGAIN || e == EWOULDBLOCK)
+ return 0;
+ DBG ("->accept4(%d)=%d:%d\n", server_fd, fd, e);
+ CPS_CNT_INC_E (thread, CPS_CNT_ACCEPT_ERR, errno);
+ return -1;
+ }
+
+ CPS_REC_INC (thread, CPS_REC_INIT);
+// DBG("(%d, %d) -> accepted(%d) %d: %s", thread->index, sid, server->fd, fd, f_inaddr(&addr));
+
+ if (fd >= CPS_MAX_FD)
+ {
+ _close (fd);
+ CPS_REC_INC (thread, CPS_REC_FAIL);
+ continue;
+ }
+
+ ret = set_nodelay (fd, 1);
+ if (ret)
+ CPS_CNT_INC_E (thread, CPS_CNT_NODELAY_ERR, errno);
+
+ event.events = EPOLLIN | EPOLLET;
+ event.data.u64 = CPS_EV_DATA (CPS_CONN_SID, fd);
+ ret = _epoll_ctl (thread->epfd, EPOLL_CTL_ADD, fd, &event);
+ if (ret)
+ {
+ _close (fd);
+ CPS_CNT_INC_E (thread, CPS_CNT_EPOLL_ERR, errno);
+ CPS_REC_INC (thread, CPS_REC_FAIL);
+ DBG ("epoll_ctl(%d, %d)=%d:%d\n", thread->epfd, fd, ret, errno);
+ continue;
+ }
+
+ cps_add_conn (thread, fd, -cps.req_len, &begin);
+ }
+
+ return 0;
+}
+
+int
+cps_s_io (struct cps_thread *thread, int fd, uint32_t events)
+{
+ static char buf[CPS_DATA_MAX];
+
+ int ret;
+ struct cps_conn *conn = CPS_CONN (fd);
+
+ DBG ("(%d, %d, %x) conn:{size:%d next:%d prev:%p:%d}\n",
+ thread->index, fd, events, conn->size, conn->next, conn->prev,
+ *conn->prev);
+
+ if (events & EPOLLERR)
+ {
+ CPS_CNT_INC (thread, CPS_CNT_ERR_EVENT);
+ DBG ("(%d, %d, 0x%x)\n", thread->index, fd, events);
+ goto ERR;
+ }
+
+ if (0 == (events & EPOLLIN))
+ return 0;
+
+ while (1)
+ {
+ if (cps.run_state <= CPS_INIT)
+ goto ERR;
+
+ ret = _recv (fd, buf, sizeof (buf), 0);
+ if (ret > 0)
+ {
+ conn->size += ret;
+ if (conn->size >= 0)
+ {
+ CPS_REC_TIMED_INC (thread, CPS_REC_RECV, conn->last);
+ break; /* receive success */
+ }
+ }
+ else
+ {
+ if (ret < 0)
+ {
+ const int e = errno;
+ if (e == EWOULDBLOCK || e == EAGAIN)
+ return 0;
+ if (e == EINTR)
+ continue;
+ CPS_CNT_INC_E (thread, CPS_CNT_RECV_ERR, e);
+ }
+ else
+ {
+ CPS_CNT_INC (thread, CPS_CNT_RECV_ERR);
+ }
+ DBG ("->recv(%d,, %ld)=%d:%d\n", fd, sizeof (buf), ret, errno);
+ goto ERR;
+ }
+ }
+
+ conn->size = 0;
+
+ while (cps.run_state > CPS_INIT)
+ {
+ ret = _send (fd, buf, cps.res_len - conn->size, 0);
+ if (ret > 0)
+ {
+ conn->size += ret;
+ if (conn->size >= cps.res_len)
+ {
+ _close (fd);
+ CPS_REC_TIMED_INC (thread, CPS_REC_SEND, conn->last);
+ cps_rem_conn (thread, fd, conn);
+ return 0;
+ }
+ }
+ else
+ {
+ if (ret < 0)
+ {
+ const int e = errno;
+ if (e == EWOULDBLOCK || e == EAGAIN || e == EINTR)
+ continue;
+ CPS_CNT_INC_E (thread, CPS_CNT_SEND_ERR, e);
+ }
+ else
+ {
+ CPS_CNT_INC (thread, CPS_CNT_SEND_ERR);
+ }
+ DBG ("->send(%d,, %d)=%d:%d\n", fd, cps.res_len - conn->size, ret,
+ errno);
+ goto ERR;
+ }
+ }
+
+ return 0;
+
+ERR:
+ _close (fd);
+ cps_rem_conn (thread, fd, conn);
+ CPS_REC_INC (thread, CPS_REC_FAIL);
+ return -1;
+}
+
+void *
+cps_s_thread (void *arg)
+{
+ int num = 0;
+ struct cps_thread *thread = (struct cps_thread *) arg;
+ struct epoll_event *event = thread->event;
+
+ out ("[%d] initialize thread %ld server:%d core:%d epfd:%d\n",
+ thread->index, pthread_self (), thread->server_num, thread->core,
+ thread->epfd);
+
+ if (cps_s_listen (thread))
+ {
+ cps.run_state = CPS_ERROR;
+ return NULL;
+ }
+
+ futex_wait (&cps.run_state, CPS_INIT);
+
+ while (1)
+ {
+
+ if (num > 0)
+ {
+ int sid = CPS_EV_SID (event->data.u64);
+ int fd = CPS_EV_FD (event->data.u64);
+ DBG ("epoll evnet{sid:%d fd:%d event:%x}\n", sid, fd,
+ event->events);
+ if (sid >= 0)
+ {
+ if (event->events & EPOLLIN)
+ {
+ (void) cps_s_accept (thread, fd);
+ }
+ if (event->events & EPOLLERR)
+ {
+ wrn ("Error event for server %d\n", fd);
+ }
+ }
+ else
+ {
+ if (fd >= CPS_MAX_FD)
+ {
+ err ("Error connection index %d\n", fd);
+ }
+ else
+ {
+ (void) cps_s_io (thread, fd, event->events);
+ }
+ }
+
+ num--;
+ event++;
+ }
+
+ if (num <= 0)
+ {
+ if (cps.run_state == CPS_CLOSING)
+ {
+ if (thread->server >= 0)
+ cps_s_close (thread);
+ if (thread->conn_num <= 0)
+ break;
+ }
+ else if (cps.run_state <= CPS_INIT)
+ {
+ break;
+ }
+
+ event = thread->event;
+ num = _epoll_wait (thread->epfd, event, cps.evnum, CPS_EPWAIT_MS);
+ if (num < 0)
+ {
+ int e = errno;
+ if (e != EINTR && e != ETIMEDOUT)
+ CPS_CNT_INC_E (thread, CPS_CNT_EPOLL_ERR, e);
+ }
+ }
+ }
+
+ __sync_fetch_and_sub (&cps.active_thread, 1);
+ return NULL;
+}
diff --git a/thirdparty/apps/testapp/ft.c b/thirdparty/apps/testapp/ft.c
new file mode 100644
index 0000000..c3c6e1a
--- /dev/null
+++ b/thirdparty/apps/testapp/ft.c
@@ -0,0 +1,74 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+
+int fd = -1;
+
+void *
+thread (void *arg)
+{
+ struct epoll_event ev[32];
+ int id = *(int *) arg;
+ int ep = _epoll_create (1);
+ int i, num;
+
+ ev[0].events = EPOLLIN | EPOLLET;
+ ev[0].data.fd = id;
+ _epoll_ctl (ep, EPOLL_CTL_ADD, fd, &ev[0]);
+
+ while (1)
+ {
+ num = _epoll_wait (ep, ev, 32, -1);
+
+ (void) printf ("thread %d recv events %d\n", id, num);
+
+ for (i = 0; i < num; ++i)
+ {
+ (void)
+ printf
+ ("thread %d recv events %d : index: %d id: %d event: 0x%x\n", id,
+ num, i, ev[i].data.fd, ev[i].events);
+ }
+ }
+
+ return NULL;
+}
+
+int
+main (int argc, const char *argv[])
+{
+ struct sockaddr_in addr = { 0 };
+ int id1 = 1, id2 = 2, id3 = 3;
+
+ fd = _socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd < 0)
+ return 1;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons (10000);
+
+ _bind (fd, (struct sockaddr *) &addr, sizeof (addr));
+ _listen (fd, 10);
+
+ pthread_t t1 = lb_thread (thread, (void *) &id1, "thread-1");
+ pthread_t t2 = lb_thread (thread, (void *) &id2, "thread-2");
+ pthread_t t3 = lb_thread (thread, (void *) &id3, "thread-3");
+
+ sleep (1000000);
+
+ return 0;
+}
diff --git a/thirdparty/apps/testapp/ip6/ip6.c b/thirdparty/apps/testapp/ip6/ip6.c
new file mode 100644
index 0000000..3b61801
--- /dev/null
+++ b/thirdparty/apps/testapp/ip6/ip6.c
@@ -0,0 +1,739 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+
+#define IP6_BUF_MAX (32 * 1024)
+
+#define IP6_DEF_SHOW 16
+#define IP6_MAX_SHOW 1024
+
+#define IP6_DEF_LEN 100
+#define IP6_MAX_LEN (1024 * 1024)
+
+#define IP6_DEF_NUM -1
+#define IP6_MAX_NUM INT32_MAX
+
+#define IP6_DEF_DELAY 1
+#define IP6_MAX_DELAY 100
+
+struct ip6_var
+{
+ struct sockaddr_in6 s_addr;
+ struct sockaddr_in6 c_addr;
+ int client_bind;
+ int is_client;
+ int is_udp;
+ int num;
+ int delay;
+ int len;
+ int verbose;
+ int show_len;
+
+ int fd;
+ int sfd;
+ int epfd;
+
+ char *buf;
+};
+
+struct ip6_var ip6 = { 0 };
+
+#if 1
+
+int
+tcp_listen ()
+{
+ int ret;
+
+ ip6.sfd = _socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (!ip6.sfd, -1, "socket()=%s%d:%d%s\n", BR__, ip6.sfd, errno, CC);
+
+ ret = _bind (ip6.sfd, (struct sockaddr *) &ip6.s_addr, sizeof (ip6.s_addr));
+ ERR_RETURN (ret, ret, "bind(%d, %s)=%s%d:%d%s\n", ip6.sfd,
+ f_in6addr (&ip6.s_addr), BR__, ret, errno, CC);
+
+ ret = _listen (ip6.sfd, 100);
+ ERR_RETURN (ret, ret, "listen(%d)=%s%d:%d%s\n", ip6.sfd,
+ BR__, ret, errno, CC);
+
+ out ("TCP server listen on %s\n", f_in6addr (&ip6.s_addr));
+
+ return 0;
+}
+
+void
+tcp_server ()
+{
+ if (tcp_listen ())
+ return;
+
+ while (1)
+ {
+ int recv_all = 0, sent_all = 0;
+ struct sockaddr_in6 addr;
+ socklen_t addr_len = sizeof (addr);
+
+ ip6.fd = _accept (ip6.sfd, (struct sockaddr *) &addr, &addr_len);
+ if (ip6.fd < 0)
+ {
+ out ("accept(%d)=%s%d:%d%s\n", ip6.sfd, BR__, ip6.fd, errno, CC);
+ break;
+ }
+
+ out ("incoming %d from %s\n", ip6.fd, f_in6addr (&addr));
+
+ while (1)
+ {
+ int recv_len, sent_len = 0, len, times = 0;
+
+ recv_len = _recv (ip6.fd, ip6.buf, IP6_MAX_LEN, 0);
+ if (recv_len == 0)
+ break;
+ if (recv_len < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ out ("recv(%d)=%s%d:%d%s\n", ip6.fd, BR__, recv_len, errno, CC);
+ break;
+ }
+ recv_all += recv_len;
+ if (ip6.verbose)
+ out ("recv: %d = %d\n", recv_all, recv_len);
+
+ SENDING:
+ len = _send (ip6.fd, ip6.buf + sent_len, recv_len - sent_len, 0);
+ if (len == 0)
+ break;
+ if (len < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ out ("send(%d, %d)=%s%d:%d%s\n", ip6.fd, recv_len - sent_len,
+ BR__, len, errno, CC);
+ break;
+ }
+
+ times++;
+ sent_len += len;
+ sent_all += len;
+ if (ip6.verbose)
+ out ("sent: %d = %d + %d\n", sent_all, sent_len, len);
+
+ if (sent_len < recv_len)
+ goto SENDING;
+
+ if (times > 1)
+ out ("%d replied in %d times\n", sent_len, times);
+ else
+ out ("%d replied\n", sent_len);
+ }
+
+ out ("closing %d --- input:%d output:%d\n", ip6.fd, recv_all, sent_all);
+ _close (ip6.fd);
+ ip6.fd = -1;
+ }
+
+ err ("TCP server break\n");
+}
+
+int
+tcp_connect ()
+{
+ int ret;
+
+ ip6.fd = _socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (!ip6.fd, -1,
+ "socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP)=%s%d:%d%s\n", BR__,
+ ip6.fd, errno, CC);
+
+ if (ip6.client_bind)
+ {
+ ret =
+ _bind (ip6.fd, (struct sockaddr *) &ip6.c_addr, sizeof (ip6.c_addr));
+ ERR_RETURN (ret, ret, "bind(%d, %s)=%s%d:%d%s\n", ip6.fd,
+ f_in6addr (&ip6.c_addr), BR__, ret, errno, CC);
+ }
+
+ ret =
+ _connect (ip6.fd, (struct sockaddr *) &ip6.s_addr, sizeof (ip6.s_addr));
+ ERR_RETURN (ret, ret, "connect(%d, %s)=%s%d:%d%s\n", ip6.fd,
+ f_in6addr (&ip6.s_addr), BR__, ret, errno, CC);
+
+ if (!ip6.client_bind)
+ {
+ socklen_t len = sizeof (ip6.c_addr);
+ ret = _getsockname (ip6.fd, (struct sockaddr *) &ip6.c_addr, &len);
+ ERR_RETURN (ret, ret, "getsockname()=%d:%d\n", ret, errno);
+ }
+
+ out ("connected %d from %s to %s\n", ip6.fd,
+ f_in6addr (&ip6.c_addr), f_in6addr (&ip6.s_addr));
+
+ return 0;
+}
+
+void
+tcp_client ()
+{
+ int i, count = 0, sent_all = 0, recv_all = 0, sent_num = 0, recv_num = 0;
+const struct timespec delay = { tv_sec: ip6.delay /* / 1000 */ , tv_nsec: /*(ip6.delay % 1000) * 1000 * 100 */ 0
+ };
+
+ if (tcp_connect ())
+ return;
+
+ for (i = 0; i < ip6.len; ++i)
+ ip6.buf[i] = (char) i;
+
+ while (ip6.num != 0)
+ {
+ int len, recv_len = 0, sent_len = 0, recv_times = 0, send_times = 0;
+
+ SENDING:
+ len = _send (ip6.fd, ip6.buf + sent_len, ip6.len - sent_len, 0);
+ if (len == 0)
+ break;
+ if (len < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ out ("send(%d, %d)=%s%d:%d%s\n", ip6.fd, ip6.len - sent_len, BR__,
+ len, errno, CC);
+ break;
+ }
+
+ sent_len += len;
+ sent_all += len;
+ if (ip6.verbose)
+ out ("sent: %d = %d + %d\n", sent_all, sent_len, len);
+ if (sent_len < ip6.len)
+ goto SENDING;
+ sent_num++;
+
+ RECVING:
+ len = _recv (ip6.fd, ip6.buf + recv_len, IP6_MAX_LEN - recv_len, 0);
+ if (len == 0)
+ break;
+ if (len < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ out ("recv(%d)=%s%d:%d%s\n", ip6.fd, BR__, len, errno, CC);
+ break;
+ }
+ recv_len += len;
+ recv_all += len;
+ if (ip6.verbose)
+ out ("recv: %d = %d + %d\n", recv_all, recv_len, len);
+ if (recv_len < sent_len)
+ goto RECVING;
+ recv_num++;
+
+ out ("%d replied", sent_len);
+ if (send_times > 1)
+ out (" %d sending", send_times);
+ if (recv_times > 1)
+ out (" %d receiving", recv_times);
+
+ for (i = 0; i < recv_len; ++i)
+ {
+ if (ip6.buf[i] != (char) i)
+ {
+ out (" data error [%d]:0x%02x != %02x", i, ip6.buf[i],
+ i & 0xFF);
+ for (; i < recv_len; ++i)
+ ip6.buf[i] = (char) i;
+ break;
+ }
+ }
+
+ out ("\n");
+
+ if (ip6.num > 0 && sent_num >= ip6.num)
+ break;
+
+ if (ip6.delay)
+ {
+ (void) nanosleep (&delay, NULL);
+ }
+ }
+
+ out ("closing %d\n", ip6.fd);
+
+ if (sent_num)
+ {
+ out ("--- %s -> %s TCP ping statistics ---\n",
+ f_in6addr (&ip6.c_addr), f_in6addr (&ip6.s_addr));
+ out
+ ("%d output, %d input, %d packets transmitted, %d received, %d%% packet loss\n",
+ sent_all, recv_all, sent_num, recv_num,
+ (sent_num - recv_num) * 100 / sent_num);
+ }
+}
+
+#endif
+#if 1
+
+void
+udp_recv_show (char *buf, int len)
+{
+ int i, dot = 0;
+ char co[256];
+
+ co_init (co, sizeof (co));
+
+ if (len > ip6.show_len)
+ {
+ len = ip6.show_len;
+ dot = 1;
+ }
+
+ if (len > 16)
+ co_app_ch (co, '\n');
+
+ for (i = 0; i < len; ++i)
+ {
+ char ch;
+
+ co_ch_if (i && (i % 32) == 0, co, '\n');
+ co_ch_if ((i % 16) == 0, co, ' ');
+ co_ch_if ((i % 4) == 0, co, ' ');
+
+ ch = buf[i] >> 4;
+ ch += (ch > 9 ? 'A' : '0');
+ co_app_ch (co, ch);
+ ch = buf[i] & 0xF;
+ ch += (ch > 9 ? 'A' : '0');
+ co_app_ch (co, ch);
+ }
+
+ if (dot)
+ co_append (co, 6, " ...\n");
+ else
+ co_app_ch (co, '\n');
+
+ co_flush (co);
+}
+
+void
+udp_server ()
+{
+ int ret;
+ uint32_t count = 0;
+
+ ip6.fd = _socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (ip6.fd < 0)
+ {
+ err ("socket()=%d:%d\n", ip6.fd, errno);
+ return;
+ }
+
+ ret = _bind (ip6.fd, (struct sockaddr *) &ip6.s_addr, sizeof (ip6.s_addr));
+ if (ret)
+ {
+ err ("bind(%d, %s)=%d:%d\n", ip6.fd, f_in6addr (&ip6.s_addr), ret,
+ errno);
+ return;
+ }
+
+ out ("UDP server bound %s\n", f_in6addr (&ip6.s_addr));
+
+ while (1)
+ {
+ struct sockaddr_in6 addr;
+ socklen_t addrlen = sizeof (addr);
+ int recv_len, sent_len;
+
+ recv_len =
+ _recvfrom (ip6.fd, ip6.buf, IP6_BUF_MAX, 0, (struct sockaddr *) &addr,
+ &addrlen);
+
+ if (recv_len == 0)
+ {
+ out ("recvfrom()=0 --> exit\n");
+ break;
+ }
+ if (recv_len < 0)
+ {
+ if (errno != EINTR)
+ out ("recvfrom()=%s%d:%d%s\n", FR__, recv_len, errno, CC);
+ continue;
+ }
+
+ SENDING:
+ sent_len =
+ _sendto (ip6.fd, ip6.buf, recv_len, 0, (struct sockaddr *) &addr,
+ sizeof (addr));
+ if (sent_len == 0)
+ break;
+ if (sent_len < 0)
+ {
+ if (errno == EINTR)
+ goto SENDING;
+ out ("sendto(%d, %s)=%s%d:%d%s\n", recv_len, f_in6addr (&addr),
+ FR__, sent_len, errno, CC);
+ continue;
+ }
+
+ out ("%d received from %s", recv_len, f_in6addr (&addr));
+ if (recv_len == sent_len)
+ out ("\n");
+ else
+ out (", sent %s%d%s\n", FR__, sent_len, CC);
+ }
+
+ err ("UDP server break\n");
+}
+
+void
+udp_client ()
+{
+ int ret, i, sent_num = 0, recv_num = 0;
+const struct timespec delay = { tv_sec: ip6.delay /* / 1000 */ , tv_nsec: /*(ip6.delay % 1000) * 1000 * 100 */ 0
+ };
+
+ ip6.fd = _socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (ip6.fd < 0)
+ {
+ err ("socket()=%d:%d\n", ip6.fd, errno);
+ return;
+ }
+
+ if (ip6.client_bind)
+ {
+ ret =
+ _bind (ip6.fd, (struct sockaddr *) &ip6.c_addr,
+ sizeof (struct sockaddr_in6));
+ if (ret)
+ {
+ err ("bind(%d, %s)=%d:%d\n", ip6.fd, f_in6addr (&ip6.c_addr), ret,
+ errno);
+ return;
+ }
+ out ("UDP client bind %s\n", f_in6addr (&ip6.c_addr));
+ }
+
+ out ("UDP client ping %s size:%d\n", f_in6addr (&ip6.s_addr), ip6.len);
+
+ for (i = 0; i < ip6.len; ++i)
+ ip6.buf[i] = (char) i;
+
+ while (1)
+ {
+ struct sockaddr_in6 addr;
+ socklen_t addrlen = sizeof (addr);
+ int sent_len, recv_len;
+
+ sent_len =
+ _sendto (ip6.fd, ip6.buf, ip6.len, 0,
+ (const struct sockaddr *) &ip6.s_addr, addrlen);
+ if (sent_len == 0)
+ break;
+ if (sent_len < 0)
+ {
+ if (errno != EINTR)
+ out ("sendto(%d, %s)=%s%d:%d%s\n", ip6.len,
+ f_in6addr (&ip6.s_addr), FR__, sent_len, errno, CC);
+ continue;
+ }
+ sent_num++;
+ if (sent_len != ip6.len)
+ {
+ out ("sendto(%d, %s)=%s%d:%d%s\n", ip6.len, f_in6addr (&ip6.s_addr),
+ FR__, sent_len, errno, CC);
+ }
+ RECVING:
+ recv_len =
+ recvfrom (ip6.fd, ip6.buf, IP6_MAX_LEN, 0, (struct sockaddr *) &addr,
+ &addrlen);
+ if (recv_len == 0)
+ break;
+ if (recv_len < 0)
+ {
+ if (errno == EINTR)
+ goto RECVING;
+ out ("recvfrom()=%s%d:%d%s\n", FR__, recv_len, errno, CC);
+ continue;
+ }
+
+ recv_num++;
+ out ("%d bytes from %s", recv_len, f_in6addr (&addr));
+
+ if (sent_len != recv_len)
+ out (" recv_len != sent_len %d", sent_len);
+
+ if (addr.sin6_port != ip6.s_addr.sin6_port ||
+ addr.sin6_addr.s6_addr32[0] != ip6.s_addr.sin6_addr.s6_addr32[0] ||
+ addr.sin6_addr.s6_addr32[1] != ip6.s_addr.sin6_addr.s6_addr32[1] ||
+ addr.sin6_addr.s6_addr32[2] != ip6.s_addr.sin6_addr.s6_addr32[2] ||
+ addr.sin6_addr.s6_addr32[3] != ip6.s_addr.sin6_addr.s6_addr32[3])
+ {
+ out (" address error");
+ }
+
+ for (i = 0; i < recv_len; ++i)
+ {
+ if (ip6.buf[i] != (char) i)
+ {
+ out ("data error [%d]:0x%02x != %02x", i, ip6.buf[i], i & 0xFF);
+ for (; i < ip6.len; ++i)
+ ip6.buf[i] = (char) i;
+ break;
+ }
+ }
+
+ out ("\n");
+
+ if (ip6.num > 0 && sent_num >= ip6.num)
+ break;
+
+ if (ip6.delay)
+ {
+ (void) nanosleep (&delay, NULL);
+ }
+ }
+
+ if (sent_num)
+ {
+ out ("--- UDP ping %s statistics ---\n", f_in6addr (&ip6.s_addr));
+ out ("%d packets transmitted, %d received, %d%% packet loss\n",
+ sent_num, recv_num, (sent_num - recv_num) * 100 / sent_num);
+ }
+}
+
+#endif
+
+int
+ip6_start ()
+{
+ ip6.fd = -1;
+ ip6.sfd = -1;
+ ip6.epfd = -1;
+
+ if (ip6.num == 0)
+ ip6.num = IP6_DEF_NUM;
+
+ ip6.s_addr.sin6_family = AF_INET6;
+ ip6.c_addr.sin6_family = AF_INET6;
+
+ ip6.buf = malloc (IP6_MAX_LEN);
+ ERR_RETURN (!ip6.buf, -1, "Out of memory");
+
+ return 0;
+}
+
+void
+ip6_exit ()
+{
+ FD_CLOSE (ip6.fd);
+ FD_CLOSE (ip6.sfd);
+ FD_CLOSE (ip6.epfd);
+
+ BUF_FREE (ip6.buf);
+}
+
+#define IP6_OPTIONS "b:cun:d:l:o:" DBGOPT "vh"
+
+static const struct option ip6_options[] = {
+ {"bind", 1, 0, 'b'},
+ {"client", 0, 0, 'c'},
+ {"udp", 0, 0, 'u'},
+ {"number", 1, 0, 'n'},
+ {"delay", 1, 0, 'd'},
+ {"len", 1, 0, 'l'},
+ {"output", 1, 0, 'o'},
+ DBGOPT_LONG {"verbose", 0, 0, 'v'},
+ {"help", 0, 0, 'h'},
+ {0, 0, 0, 0}
+};
+
+void
+ip6_usage (const char *name)
+{
+ out ("USAGE: %s [OPTIONS] SERVER-ADDRESS # %s version\n", name,
+ VERSION_NAME);
+ out (" Options:\n");
+ out (" -b, --bind IP.PORT bind address\n");
+ out (" -c, --client client mode\n");
+ out (" -u, --udp udp mode\n");
+ out (" -n, --number # C packet number(default:LOOP)\n");
+ out
+ (" -d, --delay # C seconds wait send next packet(default:1, 0: no delay)\n");
+ out (" -l, --length # C data length(default:%u)\n", IP6_DEF_LEN);
+ out
+ (" -o, --output # show received data(default:%u)\n",
+ IP6_DEF_SHOW);
+#ifdef DEBUG
+ out (" -D, --debug show debug information\n");
+#endif
+ out (" -v, --verbose show thread statistics\n");
+ out (" -h, --help help\n");
+}
+
+int
+ip6_args (int argc, char *argv[])
+{
+ int ret, opt, index;
+
+ ip6.delay = IP6_DEF_DELAY;
+ ip6.len = IP6_DEF_LEN;
+
+ while (EOF !=
+ (opt = getopt_long (argc, argv, IP6_OPTIONS, ip6_options, &index)))
+ {
+ const char *end;
+
+ switch (opt)
+ {
+ case 'b':
+ ret = p_addr6 (optarg, &ip6.c_addr);
+ ERR_RETURN (ret, -1, "Invalid client set '%s'\n", optarg);
+ ip6.client_bind = 1;
+ break;
+ case 'c':
+ ip6.is_client = 1;
+ break;
+
+ case 'u':
+ ip6.is_udp = 1;
+ break;
+
+ case 'n':
+ ip6.num = p_uint (optarg, IP6_MAX_NUM, &end);
+ ERR_RETURN (!end || *end, -1, "Invalid number '%s'\n", optarg);
+ break;
+ case 'd':
+ ip6.delay = (int) p_int (optarg, IP6_MAX_DELAY, &end);
+ ERR_RETURN (!end || *end, -1, "Invalid delay '%s'\n", optarg);
+ break;
+
+ case 'l':
+ ip6.len = (int) p_int (optarg, IP6_MAX_LEN, &end);
+ ERR_RETURN (!end || *end, -1, "Invalid query '%s'\n", optarg);
+ break;
+
+ case 'o':
+ ip6.show_len = (int) p_int (optarg, IP6_MAX_SHOW, &end);
+ ERR_RETURN (!end || *end, -1, "Invalid reply '%s'\n", optarg);
+ break;
+
+ case 'v':
+ ip6.verbose = 1;
+ break;
+
+#ifdef DEBUG
+ case 'D':
+ enable_debug = 1;
+ break;
+#endif
+ case 'h':
+ ip6_usage (argv[0]);
+ exit (0);
+ case '?':
+ err ("Invalid arguments\n");
+ return -1;
+ default:
+ err ("Unknown option '%c'.\n", opt);
+ return -1;
+ }
+ }
+
+ if (optind == argc - 1)
+ {
+ ERR_RETURN (p_addr6 (argv[optind], &ip6.s_addr), -1,
+ "Invalid server address '%s'\n", argv[optind]);
+ }
+ else if (optind < argc)
+ {
+ while (optind < argc)
+ err ("Unknown argument '%s'\n", argv[optind++]);
+ return -1;
+ }
+ else
+ {
+ err ("NO server address\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+ip6_break (int s)
+{
+ DBG (" SIGNALED %d\n", s);
+ out ("\n");
+
+ ip6_exit ();
+ exit (0);
+}
+
+void
+ip6_sigpipe (int s)
+{
+ DBG ("SIGPIPE\n");
+}
+
+int
+ip6_init ()
+{
+ struct sigaction s = { 0 };
+
+ (void) sigemptyset (&s.sa_mask);
+
+ s.sa_flags = SA_NODEFER;
+ s.sa_handler = (void *) ip6_break;
+ (void) sigaction (SIGINT, &s, NULL);
+ (void) sigaction (SIGQUIT, &s, NULL);
+
+ s.sa_handler = ip6_sigpipe;
+ (void) sigaction (SIGPIPE, &s, NULL);
+
+// lb_sigsegv_setup();
+
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ if (ip6_init ())
+ return 1;
+
+ if (ip6_args (argc, argv))
+ return 1;
+
+ ip6_start ();
+
+ if (ip6.is_client)
+ {
+ if (ip6.is_udp)
+ udp_client ();
+ else
+ tcp_client ();
+ }
+ else
+ {
+ if (ip6.is_udp)
+ udp_server ();
+ else
+ tcp_server ();
+ }
+
+ ip6_exit ();
+ return 0;
+}
diff --git a/thirdparty/apps/testapp/lb/api.h b/thirdparty/apps/testapp/lb/api.h
new file mode 100644
index 0000000..f930227
--- /dev/null
+++ b/thirdparty/apps/testapp/lb/api.h
@@ -0,0 +1,169 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef _API_H_
+#define _API_H_
+
+#if defined(NSOCKET)
+#define VERSION_NAME "NSTACK"
+#define _socket nstack_socket
+#define _fcntl nstack_fcntl
+#define _bind nstack_bind
+#define _listen nstack_listen
+#define _accept nstack_accept
+#define _accept4 nstack_accept4
+#define _connect nstack_connect
+#define _close nstack_close
+#define _shutdown nstack_shutdown
+#define _recv nstack_recv
+#define _send nstack_send
+#define _getsockname nstack_getsockname
+#define _getpeername nstack_getpeername
+#define _getsockopt nstack_getsockopt
+#define _setsockopt nstack_setsockopt
+#define _recvfrom nstack_recvfrom
+#define _sendto nstack_sendto
+#define _read nstack_read
+#define _write nstack_write
+#define _epoll_create nstack_epoll_create
+#define _epoll_ctl nstack_epoll_ctl
+#define _epoll_wait nstack_epoll_wait
+#elif defined(LWIP)
+#define VERSION_NAME "LWIP"
+#define _socket lwip_socket
+#define _fcntl lwip_fcntl
+#define _bind lwip_bind
+#define _listen lwip_listen
+#define _accept lwip_accept
+#define _accept4 lwip_accept4
+#define _connect lwip_connect
+#define _close lwip_close
+#define _shutdown lwip_shutdown
+#define _recv lwip_recv
+#define _send lwip_send
+#define _getsockname lwip_getsockname
+#define _getpeername lwip_getpeername
+#define _getsockopt lwip_getsockopt
+#define _setsockopt lwip_setsockopt
+#define _recvfrom lwip_recvfrom
+#define _sendto lwip_sendto
+#define _read lwip_read
+#define _write lwip_write
+#define _epoll_create lwip_epoll_create
+#define _epoll_ctl lwip_epoll_ctl
+#define _epoll_wait lwip_epoll_wait
+#else
+#define VERSION_NAME "POSIX"
+#define _socket socket
+#define _fcntl fcntl
+#define _bind bind
+#define _listen listen
+#define _accept accept
+#define _accept4 accept4
+#define _connect connect
+#define _close close
+#define _shutdown shutdown
+#define _recv recv
+#define _send send
+#define _getsockname getsockname
+#define _getpeername getpeername
+#define _getsockopt getsockopt
+#define _setsockopt setsockopt
+#define _recvfrom recvfrom
+#define _sendto sendto
+#define _read read
+#define _write write
+#define _epoll_create epoll_create
+#define _epoll_ctl epoll_ctl
+#define _epoll_wait epoll_wait
+#endif
+
+#endif /* #ifndef _API_H_ */
+
+#ifndef SOCKET_WARP_LB_H_
+#define SOCKET_WARP_LB_H_
+
+inline static int
+set_nonblock_v (int fd, int nonblock)
+{
+ int fl = _fcntl (fd, F_GETFL, 0);
+
+ if (fl < 0)
+ return fl;
+
+ if (nonblock)
+ {
+ if (fl & O_NONBLOCK)
+ return 0;
+ fl |= O_NONBLOCK;
+ }
+ else
+ {
+ if (0 == (fl & O_NONBLOCK))
+ return 0;
+ fl &= ~(O_NONBLOCK);
+ }
+
+ return _fcntl (fd, F_SETFL, fl | O_NONBLOCK);
+}
+
+inline static int
+set_nonblock (int fd)
+{
+ int fl = _fcntl (fd, F_GETFL, 0);
+ if (fl < 0)
+ return fl;
+ return _fcntl (fd, F_SETFL, fl | O_NONBLOCK);
+}
+
+inline static int
+set_nodelay (int fd, int nodelay)
+{
+ return _setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *) &nodelay,
+ sizeof (nodelay));
+}
+
+inline static int
+set_rcvtimeo (int fd, int us)
+{
+ struct timeval timeout = {.tv_sec = us / USOFS,.tv_usec = us % USOFS };
+ return _setsockopt (fd, SOL_SOCKET, SO_RCVTIMEO, &timeout,
+ sizeof (timeout));
+}
+
+inline static int
+set_reuseaddr (int fd, int reuseaddr)
+{
+ return _setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuseaddr,
+ sizeof (reuseaddr));
+}
+
+inline static int
+set_reuseport (int fd, int reuseport)
+{
+ return _setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (char *) &reuseport,
+ sizeof (reuseport));
+}
+
+inline static int
+set_sndtimeo (int fd, int us)
+{
+ struct timeval timeout = {.tv_sec = us / USOFS,.tv_usec = us % USOFS };
+ return _setsockopt (fd, SOL_SOCKET, SO_SNDTIMEO, &timeout,
+ sizeof (timeout));
+}
+
+#endif /* #ifndef SOCKET_WARP_LB_H_ */
diff --git a/thirdparty/apps/testapp/lb/lb.c b/thirdparty/apps/testapp/lb/lb.c
new file mode 100644
index 0000000..058ddce
--- /dev/null
+++ b/thirdparty/apps/testapp/lb/lb.c
@@ -0,0 +1,1290 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+
+int enable_debug = 1;
+
+#ifdef COLOR_LB_H_
+
+const static struct lb_color lb_color_list[2] = {
+ [LB_DEF_COLOR] = {
+ .clear = "\033[0m",
+ .high = "\033[1m",
+ .uline = "\033[4m",
+ .flash = "\033[5m",
+ .rev = "\033[7m",
+
+ .fblack = "\033[30m",
+ .fr__ = "\033[31m",
+ .f_g_ = "\033[32m",
+ .f__b = "\033[34m",
+ .frg_ = "\033[33m",
+ .fr_b = "\033[35m",
+ .f_gb = "\033[36m",
+ .fwhite = "\033[37m",
+
+ .bblack = "\033[40m",
+ .br__ = "\033[41m",
+ .b_g_ = "\033[42m",
+ .b__b = "\033[44m",
+ .brg_ = "\033[43m",
+ .br_b = "\033[45m",
+ .b_gb = "\033[46m",
+ .bwhite = "\033[47m",
+ },
+ [LB_NO_COLOR] = {
+ .clear = "",
+ .high = "",
+ .uline = "",
+ .flash = "",
+ .rev = "",
+
+ .fblack = "",
+ .fr__ = "",
+ .f_g_ = "",
+ .f__b = "",
+ .frg_ = "",
+ .fr_b = "",
+ .f_gb = "",
+ .fwhite = "",
+
+ .bblack = "",
+ .br__ = "",
+ .b_g_ = "",
+ .b__b = "",
+ .brg_ = "",
+ .br_b = "",
+ .b_gb = "",
+ .bwhite = "",
+ },
+};
+
+const struct lb_color *lb_color = &lb_color_list[0];
+int lb_color_index = 0;
+
+void
+lb_set_color (int index)
+{
+ lb_color_index = index;
+ lb_color = &lb_color_list[index];
+}
+
+#endif
+
+#ifdef FORMAT_LB_H_
+
+static __thread char s_fmt_buf[64][64];
+static __thread uint32_t s_fmt_id = 0;
+
+#if 0
+const char *
+f_in6 (const struct in6_addr *ip6)
+{
+ char *buf = s_fmt_buf[(s_fmt_id++) & 63];
+ char *p = buf;
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ {
+ uint16_t c, v = htons (ip6->s6_addr16[i]);
+
+ c = v >> 12;
+ if (c > 9)
+ *p++ = 'A' + c - 10;
+ else if (c > 0)
+ *p++ = '0' + c;
+
+ c = (v >> 8) & 0xF;
+ if (c > 9)
+ *p++ = 'A' + c - 10;
+ else if (v > 0x00FF)
+ *p++ = '0' + c;
+
+ c = (v >> 4) & 0xF;
+ if (c > 9)
+ *p++ = 'A' + c - 10;
+ else if (v > 0x000F)
+ *p++ = '0' + c;
+
+ c = v & 0xF;
+ if (c > 9)
+ *p++ = 'A' + c - 10;
+ else
+ *p++ = '0' + c;
+
+ *p++ = ':';
+ }
+
+ p--;
+ *p = 0;
+ return buf;
+}
+#endif
+
+static int
+f_in6_f (char *buf, int len, uint16_t val)
+{
+ uint16_t v;
+ int num = 0;
+
+ if (val > 0xFFF)
+ {
+ if (num >= len)
+ return -1;
+ v = val >> 12;
+ if (v < 10)
+ buf[num++] = v + '0';
+ else
+ buf[num++] = v + 'a' - 10;
+ }
+ if (val > 0xff)
+ {
+ if (num >= len)
+ return -1;
+ v = (val >> 8) & 0xF;
+ if (v < 10)
+ buf[num++] = v + '0';
+ else
+ buf[num++] = v + 'a' - 10;
+ }
+ if (val > 0xf)
+ {
+ if (num >= len)
+ return -1;
+ v = (val >> 4) & 0xF;
+ if (v < 10)
+ buf[num++] = v + '0';
+ else
+ buf[num++] = v + 'a' - 10;
+ }
+
+ if (num >= len)
+ return -1;
+ v = val & 0xF;
+ if (v < 10)
+ buf[num++] = v + '0';
+ else
+ buf[num++] = v + 'a' - 10;
+
+ return num;
+}
+
+static void
+f_in6_z (const struct in6_addr *addr, int *pos, int *num)
+{
+ int zero_pos = 8, zero_num = 0;
+ int try_pos = -1, try_num = 0;
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ {
+ if (addr->s6_addr16[i] == 0)
+ {
+ if (try_num)
+ {
+ try_num++;
+ }
+ else
+ {
+ try_pos = i;
+ try_num = 1;
+ }
+ }
+ else if (try_num)
+ {
+ if (try_num > zero_num)
+ {
+ zero_pos = try_pos;
+ zero_num = try_num;
+ }
+ try_num = 0;
+ }
+ }
+
+ if (try_num && try_num > zero_num)
+ {
+ *pos = try_pos;
+ *num = try_num;
+ }
+ else
+ {
+ *pos = zero_pos;
+ *num = zero_num;
+ }
+}
+
+int
+f_in6_s (char *buf, int size, const struct in6_addr *addr)
+{
+ int ret, i, num = 0;
+ int zero_pos, zero_num;
+
+ f_in6_z (addr, &zero_pos, &zero_num);
+
+ if (zero_pos == 0)
+ {
+ if (num >= size)
+ return -1;
+ buf[num++] = ':';
+ }
+ else
+ {
+ for (i = 0; i < zero_pos; ++i)
+ {
+ ret = f_in6_f (&buf[num], size - num, htons (addr->s6_addr16[i]));
+ if (ret < 0)
+ return -1;
+ num += ret;
+ if (num >= size)
+ return -1;
+ buf[num++] = ':';
+ }
+ if (zero_pos == 8)
+ {
+ buf[--num] = 0;
+ return num;
+ }
+ }
+
+ if (zero_pos + zero_num == 8)
+ {
+ if (num >= size)
+ return -1;
+ buf[num++] = ':';
+ }
+ else
+ {
+ for (i = zero_pos + zero_num; i < 8; ++i)
+ {
+ if (num >= size)
+ return -1;
+ buf[num++] = ':';
+ ret = f_in6_f (&buf[num], size - num, htons (addr->s6_addr16[i]));
+ if (ret < 0)
+ return -1;
+ num += ret;
+ }
+ }
+
+ if (num >= size)
+ return -1;
+ buf[num] = 0;
+
+ return num;
+}
+
+const char *
+f_in6_r (const struct in6_addr *addr, char *buf, int buflen)
+{
+ if (f_in6_s (buf, buflen, addr) <= 0)
+ return NULL;
+ return buf;
+}
+
+const char *
+f_in6 (const struct in6_addr *addr)
+{
+ char *buf = s_fmt_buf[(s_fmt_id++) & 63];
+ return f_in6_r (addr, buf, sizeof (s_fmt_buf[0]));
+}
+
+const char *
+f_inaddr (const struct sockaddr_in *addr)
+{
+ char *buf = s_fmt_buf[(s_fmt_id++) & 63];
+ char *p = buf;
+ const uint8_t *ip = (uint8_t *) & addr->sin_addr.s_addr;
+ const uint16_t pt = ntohs (addr->sin_port);
+
+#define IPP(v) do { \
+ if (v > 99) { *p++ = '0' + v / 100 % 10; } \
+ if (v > 9) { *p++ = '0' + v / 10 % 10; } \
+ *p++ = '0' + v % 10; \
+} while (0)
+
+#define PTP(v) do { \
+ if (v > 9999) { *p++ = '0' + v / 10000 % 10; } \
+ if (v > 999) { *p++ = '0' + v / 1000 % 10; } \
+ IPP(v); \
+} while (0)
+
+ IPP (ip[0]);
+ *p++ = '.';
+ IPP (ip[1]);
+ *p++ = '.';
+ IPP (ip[2]);
+ *p++ = '.';
+ IPP (ip[3]);
+ *p++ = ':';
+ PTP (pt);
+ *p = 0;
+
+ return buf;
+}
+
+const char *
+f_in6addr (const struct sockaddr_in6 *addr)
+{
+ char *p, *buf = s_fmt_buf[(s_fmt_id++) & 63];
+ const uint16_t pt = htons (addr->sin6_port);
+ int len = f_in6_s (buf, sizeof (s_fmt_buf[0]), &addr->sin6_addr);
+
+ if (len < 0)
+ return "";
+
+ p = buf + len;
+ *p++ = '.';
+ PTP (pt);
+ *p = 0;
+
+ return buf;
+}
+
+inline static int
+r_uint_use (uint64_t val)
+{
+ const static uint64_t LB_VAL[21] = {
+ 0,
+ 9,
+ 99,
+ 999,
+ 9999,
+ 99999,
+ 999999,
+ 9999999,
+ 99999999,
+ 999999999,
+ 9999999999,
+ 99999999999,
+ 999999999999,
+ 9999999999999,
+ 99999999999999,
+ 999999999999999,
+ 9999999999999999,
+ 99999999999999999,
+ 999999999999999999,
+ 9999999999999999999u,
+ 18446744073709551615u,
+ /* --%%%***+++###^^^@@@ */
+ };
+
+ int a = 1, b = 20;
+
+ do
+ {
+ int i = (a + b) / 2;
+ if (val > LB_VAL[i])
+ a = i + 1;
+ else
+ b = i;
+ }
+ while (a != b);
+
+ return a;
+}
+
+inline static int
+r_uint_wide (uint64_t val)
+{
+ int wide = r_uint_use (val);
+
+ wide = wide + (wide - 1) / 3;
+
+ return wide;
+}
+
+inline static void
+r_uint_fmt (char *buf, uint64_t val, int wide)
+{
+ char *p = buf + wide;
+
+ *p-- = 0;
+
+ while (1)
+ {
+ *p-- = ('0' + val % 10);
+ if ((val /= 10) == 0)
+ break;
+
+ *p-- = ('0' + val % 10);
+ if ((val /= 10) == 0)
+ break;
+
+ *p-- = ('0' + val % 10);
+ if ((val /= 10) == 0)
+ break;
+
+ *p-- = ',';
+ }
+
+ while (p >= buf)
+ *p-- = ' ';
+}
+
+int
+r_uint (char *buf, uint64_t val, int wide)
+{
+ const int size = r_uint_wide (val);
+
+ if (size > wide)
+ wide = size;
+
+ r_uint_fmt (buf, val, wide);
+
+ return wide;
+}
+
+inline int
+s_uint (char *buf, uint64_t val)
+{
+ char *p = buf;
+
+#define F_NUM(n) if (val >= n) { *p++ = '0' + val / n % 10; }
+#define C_NUM(n) if (val >= n) { *p++ = '0' + val / n % 10; *p++ = ','; }
+
+ if (val >= 10000000ul)
+ {
+ if (val >= 1000000000000ul)
+ {
+ F_NUM (10000000000000000000ul);
+ C_NUM (1000000000000000000ul);
+ F_NUM (100000000000000000ul);
+ F_NUM (10000000000000000ul);
+ C_NUM (1000000000000000ul);
+ F_NUM (100000000000000ul);
+ F_NUM (10000000000000ul);
+ C_NUM (1000000000000ul);
+ }
+ F_NUM (100000000000ul);
+ F_NUM (10000000000ul);
+ C_NUM (1000000000ul);
+ F_NUM (100000000ul);
+ F_NUM (10000000ul);
+ }
+ C_NUM (1000000ul);
+ F_NUM (100000ul);
+ F_NUM (10000ul);
+ C_NUM (1000ul);
+ F_NUM (100ul);
+ F_NUM (10ul);
+ *p++ = '0' + val % 10;
+ *p = 0;
+
+#undef F_NUM
+#undef C_NUM
+ return p - buf;
+}
+
+const char *
+f_uint (uint64_t val)
+{
+ char *buf = s_fmt_buf[(s_fmt_id++) & 63];
+ (void) s_uint (buf, val);
+ return buf;
+}
+
+#endif
+#ifdef PARSE_LB_H_
+
+#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
+#define IS_hex(c) ((c) >= 'a' && (c) <= 'f')
+#define IS_HEX(c) ((c) >= 'A' && (c) <= 'F')
+
+uint64_t
+p_hex (const char *arg, const char **end)
+{
+ int i;
+ uint64_t val = 0;
+
+ while (*arg)
+ {
+ if (IS_DIGIT (*arg))
+ val = (val << 4) | (uint64_t) (*arg++ - '0');
+ else if (IS_hex (*arg))
+ val = (val << 4) | (uint64_t) (*arg++ - 'a' + 0xa);
+ else if (IS_HEX (*arg))
+ val = (val << 4) | (uint64_t) (*arg++ - 'A' + 0xA);
+ else
+ break;
+ if (val > 0x0FFFffffFFFFffff)
+ break;
+ }
+
+ if (end)
+ *end = arg;
+ return val;
+}
+
+#define P_UINT_RET(ret, out) ((*end = (out)), (ret))
+
+uint64_t
+p_uint (const char *arg, uint64_t max, const char **end)
+{
+ int i;
+ uint64_t v;
+ const char *out;
+
+ if (!end)
+ end = &out;
+
+ if (!arg)
+ goto P_UINT_ERR;
+
+ if (*arg == '0')
+ {
+ if (IS_DIGIT (arg[1]))
+ goto P_UINT_ERR;
+ return P_UINT_RET (0, arg + 1);
+ }
+
+ if (!IS_DIGIT (*arg))
+ return P_UINT_RET (0, NULL);
+
+ v = *arg++ - '0';
+ if (v > max)
+ goto P_UINT_ERR;
+
+ for (i = 2; i <= 19; ++i)
+ {
+ if (!IS_DIGIT (*arg))
+ return P_UINT_RET (v, arg);
+ v = v * 10 + (*arg++ - '0');
+ if (v > max)
+ goto P_UINT_ERR;
+ }
+
+ if (IS_DIGIT (*arg))
+ {
+ uint64_t n;
+ if (v > (UINT64_MAX / 10))
+ goto P_UINT_ERR;
+ n = v * 10;
+ if (UINT64_MAX - n > (*arg - '0'))
+ goto P_UINT_ERR;
+ v = n + (*arg - '0');
+ if (v > max)
+ goto P_UINT_ERR;
+ arg++;
+ if (IS_DIGIT (*arg))
+ goto P_UINT_ERR;
+ }
+
+ return P_UINT_RET (v, arg);
+
+P_UINT_ERR:
+ return P_UINT_RET (UINT64_MAX, NULL);
+}
+
+inline uint32_t
+p_ip (const char **arg)
+{
+ uint32_t b1, b2, b3, b4;
+ const char *p = *arg;
+
+ b1 = (uint32_t) p_uint (p, 255, &p);
+ if (!p || *p++ != '.')
+ goto P_IP_ERR;
+ b2 = (uint32_t) p_uint (p, 255, &p);
+ if (!p || *p++ != '.')
+ goto P_IP_ERR;
+ b3 = (uint32_t) p_uint (p, 255, &p);
+ if (!p || *p++ != '.')
+ goto P_IP_ERR;
+ b4 = (uint32_t) p_uint (p, 255, &p);
+ if (!p)
+ goto P_IP_ERR;
+
+ *arg = p;
+ return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
+
+P_IP_ERR:
+ *arg = NULL;
+ return 0;
+}
+
+int
+p_addr (const char *arg, struct sockaddr_in *addr)
+{
+ uint16_t port;
+
+ if (*arg != ':')
+ {
+ uint32_t ip = p_ip (&arg);
+ if (!arg)
+ return -1;
+ addr->sin_addr.s_addr = htonl (ip);
+ if (*arg == 0)
+ return 0;
+ if (*arg != ':')
+ return -1;
+ arg++;
+ }
+
+ port = (uint16_t) p_uint (arg, 0xffff, &arg);
+ if (!arg || *arg != 0)
+ return -1;
+ addr->sin_port = htons (port);
+
+ return 0;
+}
+
+const char *
+p_addr_set (const char *arg, struct inaddrs *addr, uint32_t flag)
+{
+ addr->ip = p_ip (&arg);
+ if (!arg)
+ return NULL;
+
+ if (!(flag & PA_NO_TO_IP) && *arg == '-')
+ {
+ uint8_t to;
+ to = (uint8_t) p_uint (arg + 1, 255, &arg);
+ if (!arg)
+ return NULL;
+ addr->ip_num = to - (uint8_t) addr->ip;
+ if (addr->ip_num >= 0)
+ ++addr->ip_num;
+ else if (flag & PA_MAY_INV_IP)
+ --addr->ip_num;
+ else
+ return NULL;
+ }
+ else if (!(flag & PA_NO_NUM_IP) && *arg == '+')
+ {
+ addr->ip_num = (int) p_uint (arg + 1, 0x7FFFffff, &arg);
+ if (!arg || addr->ip_num == 0 || 0xFFFFFFFF - addr->ip < addr->ip_num)
+ return NULL;
+ }
+ else
+ {
+ addr->ip_num = 1;
+ }
+
+ if ((flag & PA_DEF_PORT) == PA_NO_PORT)
+ return arg;
+
+ if (*arg != ':')
+ {
+ if ((flag & PA_DEF_PORT) == PA_MUST_PORT)
+ return NULL;
+ if ((flag & PA_DEF_PORT) == PA_DEF_PORT)
+ {
+ addr->port = (uint16_t) (flag);
+ addr->port_num = 1;
+ }
+ else
+ {
+ addr->port = 0;
+ addr->port_num = 0;
+ }
+ return arg;
+ }
+
+ addr->port = (uint16_t) p_uint (arg + 1, 0xffff, &arg);
+ if (!arg)
+ return NULL;
+
+ if (!(flag & PA_NO_TO_PORT) && *arg == '-')
+ {
+ uint16_t to = (uint16_t) p_uint (arg + 1, 0xffff, &arg);
+ if (!arg || to < addr->port)
+ return NULL;
+ addr->port_num = to - addr->port + 1;
+ }
+ else if (!(flag & PA_NO_NUM_PORT) && *arg == '+')
+ {
+ addr->port_num = (uint16_t) p_uint (arg + 1, 0xffff, &arg);
+ if (!arg || addr->port_num == 0 || 0xFFFF - addr->port < addr->port_num)
+ return NULL;
+ }
+ else
+ {
+ addr->port_num = 1;
+ }
+
+ if (flag & PA_MULTI_ONE)
+ {
+ if (addr->ip_num > 1 && addr->port_num > 1)
+ return NULL;
+ }
+
+ return arg;
+}
+
+inline static const char *
+pal_trim (const char *arg, uint32_t flag)
+{
+ if (flag & PAL_NO_SPACE)
+ return arg;
+
+ if (flag & PAL_WITH_NL)
+ {
+ while (*arg == ' ' || *arg == '\t' || *arg == '\r' || *arg == '\n')
+ arg++;
+ }
+ else
+ {
+ while (*arg == ' ' || *arg == '\t')
+ arg++;
+ }
+
+ return arg;
+}
+
+int
+p_addr_list (const char *arg, struct inaddrs *list, int num, uint32_t flag,
+ const char **end)
+{
+ int count = 0;
+
+ while (count < num)
+ {
+ arg = pal_trim (arg, flag);
+ arg = p_addr_set (arg, list, flag);
+ count++;
+ if (!arg)
+ return -count;
+ arg = pal_trim (arg, flag);
+ if (*arg != ',')
+ break;
+ arg++;
+ list++;
+ }
+
+ if (end)
+ *end = arg;
+ else if (*arg)
+ return -count;
+
+ return count;
+}
+
+int
+addr_total (const struct inaddrs *list, int num, uint32_t mode)
+{
+ int total = 0;
+
+ mode &= PAL_CROSS_MASK;
+
+ for (--num; num >= 0; --num)
+ {
+ if (mode == PAL_IP_X_PORT || mode == PAL_PORT_X_IP)
+ {
+ total += list[num].ip_num * list[num].port_num;
+ }
+ else if (mode == PAL_INC_BOTH)
+ {
+ int iip = 0;
+ uint16_t iport = 0;
+ do
+ {
+ total++;
+ if (++iip == list[num].ip_num)
+ iip = 0;
+ if (++iport == list[num].port_num)
+ iport = 0;
+ }
+ while (iip != 0 && iport != 0);
+ }
+ else
+ return -1;
+ }
+
+ return total;
+}
+
+int
+addr_layout (const struct inaddrs *list, int list_num,
+ struct sockaddr_in *addr, int addr_num, uint32_t mode)
+{
+ uint16_t ipt;
+ int i, iip, count = 0;
+
+ mode &= PAL_CROSS_MASK;
+
+ if (mode == PAL_IP_X_PORT)
+ {
+ for (i = 0; i < list_num; ++i)
+ {
+ if (count + list[i].ip_num * list[i].port_num > addr_num)
+ return -1;
+ for (iip = 0; iip < list[i].ip_num; ++iip)
+ {
+ for (ipt = 0; ipt < list[i].port_num; ++ipt)
+ {
+ addr[count].sin_family = AF_INET;
+ addr[count].sin_addr.s_addr = htonl (list[i].ip + iip);
+ addr[count].sin_port = htons (list[i].port + ipt);
+ count++;
+ }
+ }
+ }
+ }
+ else if (mode == PAL_PORT_X_IP)
+ {
+ for (i = 0; i < list_num; ++i)
+ {
+ if (count + list[i].ip_num * list[i].port_num > addr_num)
+ return -1;
+ for (ipt = 0; ipt < list[i].port_num; ++ipt)
+ {
+ for (iip = 0; iip < list[i].ip_num; ++iip)
+ {
+ addr[count].sin_family = AF_INET;
+ addr[count].sin_addr.s_addr = htonl (list[i].ip + iip);
+ addr[count].sin_port = htons (list[i].port + ipt);
+ count++;
+ }
+ }
+ }
+ }
+ else if (mode == PAL_INC_BOTH)
+ {
+ for (i = 0; i < list_num; ++i)
+ {
+ do
+ {
+ if (count >= addr_num)
+ return -1;
+ addr[count].sin_family = AF_INET;
+ addr[count].sin_addr.s_addr = htonl (list[i].ip + iip);
+ addr[count].sin_port = htons (list[i].port + ipt);
+ count++;
+ if (++iip >= list[i].ip_num)
+ iip = 0;
+ if (++ipt >= list[i].port_num)
+ ipt = 0;
+ }
+ while (iip != 0 && ipt != 0);
+ }
+ }
+ else
+ {
+ return -1;
+ }
+
+ return count;
+}
+
+inline static const char *
+p_ip6_se (const char *p, uint16_t * val)
+{
+ int i;
+ uint32_t v = 0;
+
+ for (i = 0; i < 4; ++i)
+ {
+ if (p[i] >= '0' && p[i] <= '9')
+ v = (v << 4) + p[i] - '0';
+ else if (p[i] >= 'a' && p[i] <= 'f')
+ v = (v << 4) + p[i] - 'a' + 10;
+ else if (p[i] >= 'A' && p[i] <= 'F')
+ v = (v << 4) + p[i] - 'A' + 10;
+ else
+ break;
+ }
+
+ if (i == 0)
+ return NULL;
+
+ *val = htons (v);
+ return p + i;
+}
+
+const char *
+p_ip6 (const char *pos, struct in6_addr *ip)
+{
+ int zero = -1, num = 0;
+ const char *last;
+
+ if (*pos == ':')
+ {
+ pos++;
+ if (*pos != ':')
+ return NULL;
+ pos++;
+ zero = 0;
+ }
+
+ last = pos;
+
+ while (*pos)
+ {
+ pos = p_ip6_se (pos, &ip->s6_addr16[num]);
+ if (!pos)
+ {
+ if (zero == num)
+ break;
+ return NULL;
+ }
+
+ num++;
+ if (num == 8)
+ break;
+
+ if (*pos == ':')
+ {
+ pos++;
+ if (*pos == ':')
+ {
+ if (zero >= 0)
+ return NULL;
+ zero = num;
+ pos++;
+ }
+ last = pos;
+ }
+ else if (*pos == '.')
+ {
+ if (num > 6)
+ return NULL;
+ *(uint32_t *) (&ip->s6_addr16[num - 1]) = htonl (p_ip (&last));
+ if (!last)
+ return NULL;
+ pos = last;
+ num++;
+ break;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (num == 0)
+ {
+ if (zero != 0)
+ return NULL;
+ ip->s6_addr32[0] = htonl (0);
+ ip->s6_addr32[1] = htonl (0);
+ ip->s6_addr32[2] = htonl (0);
+ ip->s6_addr32[3] = htonl (0);
+ return pos;
+ }
+
+ if (num < 8)
+ {
+ int i, cp;
+ if (zero < 0)
+ return NULL;
+ /* move */
+ for (i = num - 1, cp = 7; i >= zero; --i)
+ ip->s6_addr16[cp--] = ip->s6_addr16[i];
+ /* fill 0 */
+ for (i = num, cp = zero; i < 8; ++i)
+ ip->s6_addr16[cp++] = htons (0);
+ }
+ else if (zero >= 0)
+ {
+ return NULL;
+ }
+
+ return pos;
+}
+
+int
+p_addr6 (const char *arg, struct sockaddr_in6 *addr)
+{
+ uint16_t port;
+
+ if (*arg != '.')
+ {
+ arg = p_ip6 (arg, &addr->sin6_addr);
+ if (!arg)
+ return -1;
+ if (*arg == 0)
+ return 0;
+ if (*arg != '.')
+ return -1;
+ arg++;
+ }
+
+ port = (uint16_t) p_uint (arg, 0xffff, &arg);
+ if (!arg || *arg != 0)
+ return -1;
+ addr->sin6_port = htons (port);
+
+ return 0;
+}
+
+#endif
+#ifdef UNIT_LB_H_
+
+const static uint64_t UNITS[UNIT_NUM] = {
+ [UNIT_1] = 1,
+ [UNIT_k] = 1000,
+ [UNIT_m] = 1000 * 1000,
+ [UNIT_g] = 1000 * 1000 * 1000,
+ [UNIT_w] = 10000,
+ [UNIT_K] = 1024,
+ [UNIT_M] = 1024 * 1024,
+ [UNIT_G] = 1024 * 1024 * 1024,
+
+ [UNIT_hour] = 60 * 60,
+ [UNIT_min] = 60,
+ [UNIT_sec] = 1,
+
+ [UNIT_hn] = 1000ull * 1000 * 1000 * 60 * 60,
+ [UNIT_mn] = 1000ull * 1000 * 1000 * 60,
+ [UNIT_sn] = 1000 * 1000 * 1000,
+ [UNIT_1n] = 1000 * 1000 * 1000,
+ [UNIT_ms] = 1000 * 1000,
+ [UNIT_us] = 1000,
+ [UNIT_ns] = 1,
+
+ [UNIT_PC] = 1,
+};
+
+#define P_UNIT_END(ret, end) ({ \
+ *arg = (end); \
+ if (unit) *unit = UNITS[ret]; \
+ ret; \
+})
+
+int
+p_unit (const char **arg, int mask, uint64_t * unit)
+{
+ const char *opt = *arg;
+ int ret;
+
+ switch (*opt)
+ {
+ case 'w':
+ ret = UNIT_w;
+ break;
+ case 'm':
+ if ((mask & UB_ms) && opt[1] == 's')
+ return P_UNIT_END (UNIT_ms, opt + 2);
+ if (mask & UB_min)
+ return P_UNIT_END (UNIT_min, opt + 1);
+ ret = UNIT_m;
+ break;
+ case 'k':
+ ret = UNIT_k;
+ break;
+ case 'g':
+ ret = UNIT_g;
+ break;
+
+ case 'h':
+ ret = UNIT_hour;
+ break;
+ case 's':
+ ret = UNIT_sec;
+ break;
+ case 'u':
+ if ((mask & UB_us) && opt[1] == 's')
+ return P_UNIT_END (UNIT_us, opt + 2);
+ goto NO_UNIT;
+ case 'n':
+ if ((mask & UB_ns) && opt[1] == 's')
+ return P_UNIT_END (UNIT_ns, opt + 2);
+ goto NO_UNIT;
+
+ case '%':
+ ret = UNIT_PC;
+ break;
+
+ case 'K':
+ ret = UNIT_K;
+ break;
+ case 'M':
+ ret = UNIT_M;
+ break;
+ case 'G':
+ ret = UNIT_G;
+ break;
+
+ default:
+ goto NO_UNIT;
+ }
+
+ if ((1 << ret) & mask)
+ return P_UNIT_END (ret, opt + 1);
+
+NO_UNIT:
+ if (0 == (mask & UB_1))
+ return -1;
+
+ return P_UNIT_END (UNIT_1, opt);
+}
+
+#endif
+#ifdef CACHED_OUTPUT_LB_H_
+
+int
+co_app_ch (char buf[], char ch)
+{
+ struct cohead *head = (struct cohead *) buf;
+
+ buf += sizeof (struct cohead);
+
+ if (head->free > 3)
+ {
+ buf += (head->size - head->free);
+ buf[0] = ch;
+ buf[1] = 0;
+ head->free -= 1;
+ }
+ else
+ {
+ (void) fprintf (CO_OUT (head), "%s%c", buf, ch);
+ buf[0] = 0;
+ head->free = head->size;
+ }
+
+ return 1;
+}
+
+int
+co_append (char buf[], cosize_t max, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+ struct cohead *head = (struct cohead *) buf;
+
+ /* no space for max+1 size -> output if cached */
+ if (max >= head->free && head->free < head->size)
+ _co_flush (head);
+
+ /* enough space -> try cache format */
+ if (max < head->free)
+ {
+ char *p = buf + (sizeof (struct cohead) + head->size - head->free);
+ va_start (ap, fmt);
+ ret = vsnprintf (p, head->free, fmt, ap);
+ va_end (ap);
+ if (ret >= 0 && ret < head->free)
+ {
+ head->free -= ret;
+ return ret;
+ }
+ }
+
+ /* no space or format failed -> output if cached */
+ if (head->free != head->size)
+ _co_flush (head);
+
+ /* direct output */
+ va_start (ap, fmt);
+ ret = fprintf (CO_OUT (head), fmt, ap);
+ va_end (ap);
+
+ return ret;
+}
+
+int
+co_wr_uint (char buf[], uint64_t val, int wide)
+{
+ struct cohead *head = (struct cohead *) buf;
+ int size = r_uint_wide (val);
+ char *p;
+
+ if (size > wide)
+ wide = size;
+
+ if (head->free <= wide)
+ _co_flush (head);
+
+ if (head->free <= wide)
+ {
+ assert (0);
+ }
+
+ p = buf + (sizeof (struct cohead) + head->size - head->free);
+
+ r_uint_fmt (p, val, wide);
+
+ head->free -= wide;
+
+ return wide;
+}
+
+#endif
+
+#ifdef SYSTEM_LB_H_
+
+pthread_t
+lb_thread (void *(*proc) (void *), void *arg, const char *fmt, ...)
+{
+ pthread_t tid;
+ int ret;
+
+ ret = pthread_create (&tid, NULL, proc, arg);
+ if (ret)
+ return 0;
+
+ if (fmt)
+ {
+ char name[20];
+ va_list args;
+
+ va_start (args, fmt);
+ ret = vsnprintf (name, sizeof (name), fmt, args);
+ va_end (args);
+
+ if (ret > 0)
+ {
+ name[sizeof (name) - 1] = 0;
+ (void) pthread_setname_np (tid, name);
+ }
+ }
+
+ return tid;
+}
+
+static void
+lb_sigsegv_proc (int s)
+{
+ int num;
+ void *buf[128];
+
+ out ("Signal SIGSEGV, Segmentation fault!\n");
+
+ num = backtrace (buf, 128);
+ if (num > 0)
+ backtrace_symbols_fd (buf, num, STDOUT_FILENO);
+ exit (1);
+}
+
+void
+lb_sigsegv_setup ()
+{
+ struct sigaction s = { 0 };
+
+ (void) sigemptyset (&s.sa_mask);
+
+ s.sa_flags = SA_NODEFER;
+ s.sa_handler = (void *) lb_sigsegv_proc;
+ (void) sigaction (SIGSEGV, &s, NULL);
+}
+
+#endif
+
+#ifdef KERNEL_SYSCALL_API
+
+#define KAPI(name) (typeof name) *k_##name = ##name;
+#include "kapi.h"
+#undef API
+
+void
+kapi_init ()
+{
+#define KAPI(name) k_##name = ld_load;
+}
+
+#endif
diff --git a/thirdparty/apps/testapp/lb/lb.h b/thirdparty/apps/testapp/lb/lb.h
new file mode 100644
index 0000000..b7e4ddb
--- /dev/null
+++ b/thirdparty/apps/testapp/lb/lb.h
@@ -0,0 +1,731 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef _LB_H_
+#define _LB_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <time.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/epoll.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/eventfd.h>
+#include <sys/syscall.h>
+#include <sys/sysinfo.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#include <pthread.h>
+#include <sched.h>
+#include <getopt.h>
+#include <execinfo.h>
+#include <linux/futex.h>
+
+#define KB 1000
+#define MB (1000 * KB)
+#define GB (1000 * MB)
+#define TB (1000 * GB)
+
+#define MSOFS (1000)
+#define USOFS (1000 * 1000)
+#define NSOFS (1000 * 1000 * 1000)
+#define NSOFMS (1000 * 1000)
+
+#define NOINLINE __attribute__((noinline))
+#define no_inline __attribute__((noinline))
+
+#ifndef SO_REUSEPORT
+#define SO_REUSEPORT 15
+#endif
+
+#include "api.h"
+
+#define out(fmt, arg...) (void)printf(fmt, ##arg)
+
+#define info(fmt, arg...) (void)printf("%s[I:%d]%s " fmt, CR, __LINE__, CC, ##arg)
+#define wrn(fmt, arg...) (void)printf("%s[W:%d]%s " fmt, FR__, __LINE__, CC, ##arg)
+#define err(fmt, arg...) (void)fprintf(stderr, "%s[E:%d]%s " fmt, BR__, __LINE__, CC, ##arg)
+
+#define WRN(cond, fmt, arg...) do { if (cond) wrn(fmt, ##arg); } while (0)
+
+#define ERR_RETURN(cond, ret, fmt, arg...) do { \
+ if (cond) { \
+ if (fmt) err(fmt, ##arg); \
+ return ret; \
+ } \
+} while(0)
+
+#define ERR_GOTO(cond, TO, fmt, arg...) do { \
+ if (cond) { \
+ if (fmt) err(fmt, ##arg); \
+ goto TO; \
+ } \
+} while (0)
+
+#define DBGOPT "D"
+#define DBGOPT_LONG {"debug", 0, 0, 'D'},
+
+extern int enable_debug;
+
+#define DBG(fmt, arg...) do { \
+ if (enable_debug) \
+ out("[D:%d]%s " fmt, __LINE__, __func__, ##arg); \
+} while (0)
+
+#define T DBG("\n");
+
+#define CNT_OF(a) (sizeof(a) / sizeof(a[0]))
+
+#define OFF_OF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#define CON_OF(ptr, type, member) ({ \
+ const typeof( ((type*)0)->member ) *__mptr = (ptr); \
+ (type*)( (char*)__mptr - OFF_OF(type, member) ); \
+})
+#define NUM_OF(a) (sizeof((a)) / sizeof((a)[0]))
+
+#if 1
+#define TIMEPOINT
+
+#define TP(name) struct timespec _tp_##name; \
+ (void)clock_gettime(CLOCK_MONOTONIC, &_tp_##name)
+#define TO(from, to) do { \
+ struct timespec _t; \
+ LB_SUB_TS(_tp_##to, _tp_##from, _t); \
+ out("@TP>%s:%d:%s %lu.%09lu %s-%s\n", __FILE__, __LINE__, __func__, \
+ _t.tv_sec, _t.tv_nsec, #from, #to); \
+} while (0)
+#define TN(from, to, NUM) do { \
+ static uint64_t _n = 0; \
+ static struct timespec _t = {0}; \
+ _t.tv_nsec += (_tp_##to.tv_nsec - _tp_##from.tv_nsec); \
+ _t.tv_sec += (_tp_##to.tv_sec - _tp_##from.tv_sec); \
+ if (++_n >= NUM) { \
+ uint64_t _nsec = _t.tv_sec * 1000000000ul + _t.tv_nsec; \
+ _nsec /= _n; \
+ out("@TP<%lu>%s:%d:%s %lu.%09lu %s-%s\n", _n, __FILE__, __LINE__, __func__, \
+ _nsec/1000000000ul, _nsec%1000000000ul, #from, #to); \
+ _t.tv_sec = 0; \
+ _t.tv_nsec = 0; \
+ _n = 0; \
+ } \
+} while (0)
+#else
+
+#define TP(name) ((void)0)
+#define TO(from, to) ((void)0)
+#define TN(from, to, NUM) ((void)0)
+
+#endif
+
+#define TQ(name) do { TP(__); TO(name, __); } while (0)
+#define TM(name, NUM) do { TP(__); TN(name, __, NUM); } while (0)
+
+#define TO1(n1,n2) TO(n1,n2)
+#define TO2(n1,n2,n3) do { TO(n1,n2); TO1(n2,n3); } while(0)
+#define TO3(n1,n2,n3...) do { TO(n1,n2); TO2(n2,n3); } while(0)
+#define TO4(n1,n2,n3...) do { TO(n1,n2); TO3(n2,n3); } while(0)
+#define TO5(n1,n2,n3...) do { TO(n1,n2); TO4(n2,n3); } while(0)
+#define TO6(n1,n2,n3...) do { TO(n1,n2); TO5(n2,n3); } while(0)
+
+#define TE(N,n...) do { TP(__); TO##N(n, __);} while (0)
+
+#define tp1 TP(1)
+#define tq1 TQ(1)
+#define tp2 TP(2)
+#define tq2 TQ(2)
+#define tp3 TP(3)
+#define tq3 TQ(3)
+#define tp4 TP(4)
+#define tq4 TQ(4)
+#define tp5 TP(5)
+#define tq5 TQ(5)
+
+#ifndef COLOR_LB_H_
+#define COLOR_LB_H_
+
+struct lb_color
+{
+ const char *clear;
+ const char *high;
+ const char *uline;
+ const char *flash;
+ const char *rev;
+
+ const char *fblack;
+ const char *fr__;
+ const char *f_g_;
+ const char *f__b;
+ const char *frg_;
+ const char *fr_b;
+ const char *f_gb;
+ const char *fwhite;
+
+ const char *bblack;
+ const char *br__;
+ const char *b_g_;
+ const char *b__b;
+ const char *brg_;
+ const char *br_b;
+ const char *b_gb;
+ const char *bwhite;
+};
+
+enum
+{
+ LB_DEF_COLOR = 0,
+ LB_NO_COLOR = 1,
+};
+
+extern const struct lb_color *lb_color;
+extern int lb_color_index;
+void lb_set_color (int index);
+
+#define CC lb_color->clear
+#define CR lb_color->rev
+#define CH lb_color->high
+#define CU lb_color->uline
+#define CF lb_color->flash
+
+#define FBLACK lb_color->fblack
+#define FR__ lb_color->fr__
+#define F_G_ lb_color->f_g_
+#define F__B lb_color->f__b
+#define FRG_ lb_color->frg_
+#define FR_B lb_color->fr_b
+#define F_GB lb_color->f_gb
+#define FWHITE lb_color->fwhite
+
+#define BBLACK lb_color->bblack
+#define BR__ lb_color->br__
+#define B_G_ lb_color->b_g_
+#define B__B lb_color->b__b
+#define BRG_ lb_color->brg_
+#define BR_B lb_color->br_b
+#define B_GB lb_color->b_gb
+#define BWHITE lb_color->bwhite
+
+#endif
+
+#ifndef TIME_LB_H_
+#define TIME_LB_H_
+
+#define LB_RAND(num) ((int) ((random() / (RAND_MAX + 1.0)) * num))
+
+#define LB_TIME(now) (void)clock_gettime(CLOCK_MONOTONIC, &(now))
+#define LB_REALTIME(now) (void)clock_gettime(CLOCK_REALTIME, &(now))
+
+#define LB_SUB_OS(end, begin) ((end).tv_sec - (begin).tv_sec)
+#define LB_SUB_NS(end, begin) (((end).tv_sec - (begin).tv_sec) * NSOFS + (end).tv_nsec - (begin).tv_nsec)
+
+#define LB_SUB_TS(end, begin, out) ({ \
+ if ((end).tv_nsec >= (begin).tv_nsec) { \
+ (out).tv_nsec = (end).tv_nsec - (begin).tv_nsec; \
+ (out).tv_sec = (end).tv_sec - (begin).tv_sec; \
+ } else { \
+ (out).tv_nsec = (end).tv_nsec + NSOFS - (begin).tv_nsec; \
+ (out).tv_sec = (end).tv_sec - (begin).tv_sec - 1; \
+ } \
+})
+
+#define LB_CMP(end, begin) ((end).tv_sec > (begin).tv_sec ? 1 : ( \
+ (end).tv_sec < (begin).tv_sec ? -1 : (end).tv_nsec - (begin).tv_nsec))
+
+#define LB_CMP_SN(end, begin, sec, nsec) ({ \
+ time_t _s = (end).tv_sec - (begin).tv_sec; \
+ (_s > (sec)) || (_s == (sec) && (end).tv_nsec - (begin).tv_nsec >= (nsec)); \
+})
+
+#define LB_CMP_TS(end, begin, ts) LB_CMP_SN((end), (begin), (ts).tv_sec, (ts).tv_nsec)
+#define LB_CMP_S(end, begin, sec) LB_CMP_SN((end), (begin), (sec), 0)
+#define LB_CMP_NS(end, begin, nsec) LB_CMP_SN((end), (begin), 0, (nsec))
+
+#endif /* #ifndef TIME_LB_H_ */
+
+#ifndef MATH_LB_H_
+#define MATH_LB_H_
+
+/* return a * 10^9 / b */
+inline static uint64_t
+lb_gdiv (uint64_t a, uint64_t b)
+{
+ const uint64_t M = 0xFFFFffffFFFFfffful;
+ const uint64_t N = 1000 * 1000 * 1000;
+ const uint64_t P = 1000;
+
+ uint64_t r;
+
+ if (b == 0)
+ b = 1;
+
+ if (a <= M / N)
+ return a * N / b;
+
+ r = a / b;
+
+ a = a % b * P;
+ r = r * P + a / b;
+
+ a = a % b * P;
+ r = r * P + a / b;
+
+ a = a % b * P;
+ r = r * P + a / b;
+
+ return r;
+}
+
+inline static uint64_t
+lb_sdiv (uint64_t a, uint64_t b)
+{
+ if (b)
+ return a / b;
+ return 0;
+}
+
+#endif /* #ifndef MATH_LB_H_ */
+#ifndef RUN_LB_H_
+#define RUN_LB_H_
+
+struct lb_slot
+{
+ struct timespec begin;
+ uint64_t count;
+};
+
+struct lb_run
+{
+ uint32_t index;
+ uint32_t mask;
+ uint32_t rate;
+ uint32_t time;
+ uint64_t total;
+ struct lb_slot slot[0];
+};
+
+/* num:1 << N; time: ns */
+inline static void
+run_init (struct lb_run *run, uint32_t rate, uint32_t num, uint32_t time)
+{
+ int i;
+ struct lb_slot *slot = run->slot;
+ struct timespec begin;
+
+ LB_TIME (begin);
+
+ run->index = 0;
+ run->mask = num - 1;
+ run->rate = rate;
+ run->time = time;
+ run->total = 0;
+
+ for (i = 0; i < num; ++i, ++slot)
+ {
+ slot->begin = begin;
+ slot->count = 0;
+ }
+}
+
+/* return: the number should add for run to now */
+inline static int64_t
+run_test (struct lb_run *run, struct timespec *now)
+{
+ uint64_t time, num;
+ struct lb_slot *slot = run->slot;
+ struct lb_slot *cur = slot + (run->index & run->mask);
+
+ if (LB_CMP_NS (*now, cur->begin, run->time))
+ {
+ cur = slot + ((++run->index) & run->mask);
+ run->total -= cur->count;
+ cur->count = 0;
+ cur->begin = *now;
+ }
+
+ slot += ((run->index + 1) & run->mask);
+ time = LB_SUB_NS (*now, slot->begin);
+ num = time * run->rate;
+
+ if ((num % NSOFS) >= (NSOFS / 2))
+ return num / NSOFS - run->total + 1;
+ return num / NSOFS - run->total;
+}
+
+inline static int
+run_add (struct lb_run *run, int64_t num)
+{
+ run->total += num;
+ run->slot[run->index & run->mask].count += num;
+}
+
+#endif
+
+#ifndef FORMAT_LB_H_
+#define FORMAT_LB_H_
+
+const char *f_in6 (const struct in6_addr *ip6);
+const char *f_in6addr (const struct sockaddr_in6 *addr);
+const char *f_inaddr (const struct sockaddr_in *addr);
+const char *f_uint (uint64_t val);
+int s_uint (char *buf, uint64_t val);
+int r_uint (char *buf, uint64_t val, int size);
+
+#endif
+
+#ifndef PARSE_LB_H_
+#define PARSE_LB_H_
+
+uint64_t p_hex (const char *arg, const char **end);
+uint64_t p_uint (const char *arg, uint64_t max, const char **end);
+inline static long
+p_int (const char *arg, long max, const char **end)
+{
+ return (long) (unsigned long) p_uint (arg, (uint64_t) (unsigned long) max,
+ end);
+}
+
+struct inaddrs
+{
+ uint32_t ip;
+#if 0
+ uint32_t ip_num;
+ uint32_t ip_step;
+#else
+ int ip_num;
+#endif
+ uint16_t port;
+ uint16_t port_num;
+};
+
+uint32_t p_ip (const char **arg);
+int p_addr (const char *str, struct sockaddr_in *addr);
+const char *p_addr_set (const char *arg, struct inaddrs *addr, uint32_t flag);
+int p_addr_list (const char *arg, struct inaddrs *list, int num,
+ uint32_t flag, const char **end);
+int addr_total (const struct inaddrs *list, int num, uint32_t mode);
+int addr_layout (const struct inaddrs *list, int list_num,
+ struct sockaddr_in *addr, int addr_num, uint32_t mode);
+inline static int
+p_addrin_list (const char *arg, struct sockaddr_in **addr, int max,
+ uint32_t flag, const char **end)
+{
+ int num, total;
+ struct inaddrs list[max];
+ struct sockaddr_in *out;
+
+ num = p_addr_list (arg, list, max, flag, end);
+ if (num <= 0)
+ return -1;
+
+ total = addr_total (list, num, flag);
+ if (total > max)
+ return -1;
+
+ out = (struct sockaddr_in *) malloc (sizeof (struct sockaddr_in) * total);
+ if (!out)
+ return -1;
+
+ num = addr_layout (list, num, out, total, flag);
+
+ if (num != total)
+ {
+ free (out);
+ return -1;
+ }
+
+ *addr = out;
+ return num;
+}
+
+#define PA_DEFPORT_MASK 0x0000FFFF
+
+#define PA_NO_TO_IP 0x00010000
+#define PA_NO_NUM_IP 0x00020000
+#define PA_MAY_INV_IP 0x00040000
+#define PA_MULTI_ONE 0x00080000
+
+#define PA_NO_TO_PORT 0x00100000
+#define PA_NO_NUM_PORT 0x00200000
+#define PA_NO_PORT 0x00400000
+#define PA_MUST_PORT 0x00800000
+#define PA_DEF_PORT 0x00C00000
+
+#define PA_NO_TO_ALL (PA_NO_TO_IP | PA_NO_TO_PORT)
+#define PA_NO_NUM_ALL (PA_NO_NUM_IP | PA_NO_NUM_PORT)
+#define PA_SINGLE_IP (PA_NO_TO_IP | PA_NO_NUM_IP)
+#define PA_SINGLE_PORT (PA_NO_TO_PORT | PA_NO_NUM_PORT)
+
+#define PAL_NO_SPACE 0x10000000
+#define PAL_WITH_NL 0x20000000
+//#define PAL_SC_SPLIT 0x40000000
+
+#define PAL_CROSS_MASK 0x03000000
+#define PAL_IP_X_PORT 0x00000000
+#define PAL_INC_BOTH 0x01000000
+#define PAL_PORT_X_IP 0x02000000
+
+const char *p_ip6 (const char *pos, struct in6_addr *ip);
+inline static int
+inet6_aton (const char *cp, struct in6_addr *addr)
+{
+ cp = p_ip6 (cp, addr);
+ if (!cp || cp[0] != 0)
+ return 0;
+ return 1;
+}
+
+int p_addr6 (const char *arg, struct sockaddr_in6 *addr);
+
+#endif
+
+#ifndef UNIT_LB_H_
+#define UNIT_LB_H_
+
+enum unit_type
+{
+ UNIT_1,
+
+ UNIT_k,
+ UNIT_m,
+ UNIT_g,
+ UNIT_w,
+
+ UNIT_K,
+ UNIT_M,
+ UNIT_G,
+
+ UNIT_hour,
+ UNIT_min,
+ UNIT_sec,
+
+ UNIT_1n,
+ UNIT_hn,
+ UNIT_mn,
+ UNIT_sn,
+ UNIT_ms,
+ UNIT_us,
+ UNIT_ns,
+
+ UNIT_PC,
+
+ UNIT_NUM,
+
+ UB_1 = 1 << UNIT_1,
+
+ UB_k = 1 << UNIT_k,
+ UB_m = 1 << UNIT_m,
+ UB_g = 1 << UNIT_g,
+ UB_w = 1 << UNIT_w,
+
+ UB_K = 1 << UNIT_K,
+ UB_M = 1 << UNIT_M,
+ UB_G = 1 << UNIT_G,
+
+ UB_hour = 1 << UNIT_hour,
+ UB_min = 1 << UNIT_min,
+ UB_sec = 1 << UNIT_sec,
+
+ UB_hn = 1 << UNIT_hn,
+ UB_mn = 1 << UNIT_mn,
+ UB_sn = 1 << UNIT_sn,
+ UB_1n = 1 << UNIT_1n,
+ UB_ms = 1 << UNIT_ms,
+ UB_us = 1 << UNIT_us,
+ UB_ns = 1 << UNIT_ns,
+
+ UB_PC = 1 << UNIT_PC,
+
+ UB_T1U_MASK = 3 << UNIT_NUM,
+ UB_T1U_ns = 0 << UNIT_NUM,
+ UB_T1U_us = 1 << UNIT_NUM,
+ UB_T1U_ms = 2 << UNIT_NUM,
+ UB_T1U_s = 3 << UNIT_NUM,
+
+ UB_kmgw = UB_k | UB_m | UB_g | UB_w,
+ UB_KMG = UB_K | UB_M | UB_G,
+ UB_1kmgwKMG = UB_1 | UB_kmgw | UB_KMG,
+
+ UB_smun = UB_sn | UB_ms | UB_us | UB_ns,
+ UB_hms1 = UB_hour | UB_min | UB_sec | UB_1,
+
+};
+
+int p_unit (const char **arg, int mask, uint64_t * unit);
+
+inline static uint64_t
+p_value (const char *arg, uint64_t max, int mask, const char **end)
+{
+ uint64_t val = p_uint (arg, max, &arg);
+
+ if (arg)
+ {
+ uint64_t unit;
+ if (p_unit (&arg, mask, &unit) >= 0)
+ {
+ val *= unit;
+ if (val <= max)
+ {
+ if (end)
+ *end = arg;
+ return val;
+ }
+ }
+ }
+
+ if (end)
+ *end = NULL;
+ return 0;
+}
+
+#endif
+
+#ifndef CACHED_OUTPUT_LB_H_
+#define CACHED_OUTPUT_LB_H_
+
+typedef uint16_t cosize_t;
+
+struct cohead
+{
+ cosize_t size;
+ cosize_t free;
+};
+
+#define CO_OUT(head) stdout
+#define CO_INIT(buf) co_init(buf, sizeof(buf))
+
+inline static void
+co_init (char buf[], cosize_t size)
+{
+ struct cohead *head = (struct cohead *) buf;
+ head->size = size - sizeof (struct cohead);
+ head->free = head->size;
+ buf[sizeof (struct cohead)] = 0;
+}
+
+inline static void
+_co_flush (struct cohead *head)
+{
+ char *buf = (char *) (head + 1);
+ (void) fputs (buf, CO_OUT (head));
+ head->free = head->size;
+ *buf = 0;
+}
+
+inline static void
+co_flush (char buf[])
+{
+ struct cohead *head = (struct cohead *) buf;
+ if (head->free != head->size)
+ _co_flush (head);
+}
+
+int co_wr_uint (char buf[], uint64_t val, int wide);
+
+int co_app_ch (char buf[], char ch);
+#define co_ch_if(cond, buf, ch) ( \
+ (!!(cond)) ? co_app_ch((buf), (ch)) : 0)
+
+int co_append (char buf[], cosize_t max, const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+#define co_app_if(cond, buf, max, fmt, arg...) ( \
+ (!!(cond)) ? co_append((buf), (max), (fmt), ##arg) : 0)
+#define co_app_fls(buf, max, fmt, arg...) do { \
+ co_append(buf, max, fmt, ##arg); \
+ co_flush(); \
+} while (0)
+
+#endif
+
+#ifndef SYSTEM_LB_H_
+#define SYSTEM_LB_H_
+
+inline static void
+futex_wait (volatile int *addr, int val)
+{
+ while (*addr == val)
+ {
+ (void) syscall (SYS_futex, addr, FUTEX_WAIT, val, NULL, NULL, 0);
+ }
+}
+
+inline static void
+futex_wake (volatile int *addr, int num)
+{
+ (void) syscall (SYS_futex, addr, FUTEX_WAKE, num, NULL, NULL, 0);
+}
+
+pthread_t lb_thread (void *(*proc) (void *), void *arg, const char *fmt, ...);
+
+inline static int
+lb_setcpu (pthread_t thread, int cpu)
+{
+ cpu_set_t set;
+ CPU_ZERO (&set);
+ CPU_SET (cpu, &set);
+ return pthread_setaffinity_np (thread, sizeof (set), &set);
+}
+
+inline static int
+lb_sleep (time_t sec, long nsec)
+{
+const struct timespec timeout = { tv_sec: sec, tv_nsec:nsec };
+ return nanosleep (&timeout, NULL);
+}
+
+void lb_sigsegv_setup ();
+
+#endif /* #ifndef SYSTEM_LB_H_ */
+
+#define FD_CLOSE(fd) do { \
+ if(fd >= 0) { \
+ _close(fd); \
+ fd = -1; \
+ } \
+} while(0)
+
+#define BUF_FREE(p) do { \
+ if (p) { \
+ free(p); \
+ p = NULL; \
+ } \
+} while (0)
+
+#endif
+
+#ifdef KERNEL_SYSCALL_API
+#define KERNEL_SYSCALL_API
+
+#define KAPI(name) extern (typeof name) *k_##name;
+#include "kapi.h"
+#undef API
+
+#endif
diff --git a/thirdparty/apps/testapp/lp/lp.c b/thirdparty/apps/testapp/lp/lp.c
new file mode 100644
index 0000000..a9b71d1
--- /dev/null
+++ b/thirdparty/apps/testapp/lp/lp.c
@@ -0,0 +1,1138 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+#include "lp.h"
+
+void lp_exec (struct lp_worker *worker);
+
+#define LP_OPTIONS "s:c:bi:e:m:nwEC" DBGOPT "vh"
+
+static const struct option lp_options[] = {
+ {"block", 0, 0, 'b'},
+ {"server", 1, 0, 's'},
+ {"client", 1, 0, 'c'},
+ {"nodelay", 0, 0, 'n'},
+ {"interval", 1, 0, 'i'},
+ {"no-error", 1, 0, 'e'},
+ {"error-msg", 0, 0, 'E'},
+ {"core", 1, 0, 'm'},
+ DBGOPT_LONG {"watch", 0, 0, 'w'},
+ {"no-color", 0, 0, 'C'},
+ {"verbose", 0, 0, 'v'},
+ {"help", 0, 0, 'h'},
+ {0, 0, 0, 0}
+};
+
+static const char *MODES[] = {
+ [LP_RAND] = "*random link",
+ [LP_SYNC] = "=sync increment",
+ [LP_CPS] = "}client per server",
+ [LP_SPC] = "{server per client",
+};
+
+struct lp_var lp = { 0 };
+
+void
+lp_dump_sess (int fd)
+{
+ char buf[256];
+ struct lp_sess *sess = LP_SESS (fd);
+
+ co_init (buf, sizeof (buf));
+
+ co_append (buf, 80,
+ "fd:%d sess:%p state:0x%x test:%u epout:%u io_num:%u query:%d reply:%d\n",
+ fd, sess, sess->state, sess->test, sess->epout, sess->io_num,
+ sess->query, sess->reply);
+ co_append (buf, 50, " nest-sess:%d prev-sess:%p", sess->next_sess,
+ sess->prev_sess);
+ co_app_if (sess->prev_sess, buf, 10, "(%ld)",
+ CON_OF (sess->prev_sess, struct lp_sess, next_sess) - lp.sess);
+ co_append (buf, 50, " nest-rest:%d prev-rest:%p", sess->next_rest,
+ sess->prev_rest);
+ co_app_if (sess->prev_rest, buf, 10, "(%ld)",
+ CON_OF (sess->prev_rest, struct lp_sess, next_rest) - lp.sess);
+ co_append (buf, 30, " time:%ld.%09ld\n", sess->time.tv_sec,
+ sess->time.tv_nsec);
+
+ co_flush (buf);
+}
+
+void
+lp_clean (struct lp_worker *worker)
+{
+ int i, fd;
+
+ while (lp.run_state == LP_CLEAN)
+ {
+ fd = worker->conn.first;
+ if (fd < 0)
+ break;
+ lp_del_conn (worker, fd, LP_SESS (fd));
+ }
+ LP_ASSERT (worker->conn.num == 0);
+ LP_ASSERT (worker->conn.first == -1);
+ LP_ASSERT (worker->conn.last = &worker->conn.first);
+
+ while (lp.run_state == LP_CLEAN)
+ {
+ fd = worker->sess.first;
+ if (fd < 0)
+ break;
+ lp_del_sess (worker, fd);
+ }
+ LP_ASSERT (worker->sess.num == 0);
+ LP_ASSERT (worker->sess.first == -1);
+ LP_ASSERT (worker->sess.last = &worker->sess.first);
+
+ for (i = 0; i < LP_MAX_TEST; ++i)
+ {
+ LP_ASSERT (worker->rest[i].num == 0);
+ LP_ASSERT (worker->rest[i].first == -1);
+ LP_ASSERT (worker->rest[i].last = &worker->rest[i].first);
+ LP_ASSERT (worker->wait[i].num == 0);
+ LP_ASSERT (worker->wait[i].first == -1);
+ LP_ASSERT (worker->wait[i].last = &worker->rest[i].first);
+ }
+}
+
+void *
+lp_thread (void *arg)
+{
+ const uint64_t one = 1;
+ struct lp_worker *worker = (struct lp_worker *) arg;
+
+ (void) __sync_or_and_fetch (&lp.active_worker, one << worker->index);
+
+ futex_wait (&lp.run_state, LP_INIT);
+
+ if (lp.client_mode)
+ lp_client (worker);
+ else
+ lp_server (worker);
+
+ lp_clean (worker);
+
+ out ("%s! worker %d return%s\n", CR, worker->index, CC);
+ (void) __sync_and_and_fetch (&lp.active_worker, ~(one << worker->index));
+
+ return NULL;
+}
+
+void
+lp_round (int id)
+{
+ struct lp_test *test = &lp.test[id];
+ char buf[128];
+
+ co_init (buf, sizeof (buf));
+
+ co_append (buf, 30, "%s! round %d:", CR, id);
+ co_append (buf, 30, " target:%s",
+ test->target == LP_TARGET_INF ? "*" : f_uint (test->target));
+ co_append (buf, 30, " time:%s",
+ test->time == LP_TIME_INF ? "*" : f_uint (test->time));
+ co_append (buf, 30, " up:%s",
+ test->up == LP_UP_INF ? "*" : f_uint (test->up));
+ co_append (buf, 30, " down:%s",
+ test->down == LP_DOWN_INF ? "*" : f_uint (test->down));
+ co_append (buf, 30, " query:%u", test->query);
+ co_append (buf, 30, " reply:%u", test->reply);
+ co_append (buf, 30, " times:%s",
+ test->times == LP_TIMES_INF ? "*" : f_uint (test->times));
+ co_app_if (test->close_after_io, buf, 1, "-");
+ co_append (buf, 30, " period:%u", test->period);
+ co_append (buf, 30, " wait:%u", test->wait);
+ co_append (buf, 30, " %s\n", CC);
+
+ co_flush (buf);
+}
+
+int
+lp_start ()
+{
+ int i;
+ cpu_set_t set;
+
+ lp.sess = (struct lp_sess *) calloc (LP_MAX_FD, sizeof (struct lp_sess));
+ ERR_RETURN (!lp.sess, -1, "Out of memory\n");
+
+ lp.run_state = LP_INIT;
+
+ lp.curr = lp.stat[0];
+ lp.next = lp.stat[1];
+
+ if (lp.interval == 0)
+ lp.interval = LP_INTERVAL_DEF;
+
+ if (lp.core)
+ {
+ CPU_ZERO (&set);
+ for (i = 0; i < 64; ++i)
+ {
+ if (lp.core & (1 << i))
+ CPU_SET (i, &set);
+ }
+ }
+
+ for (i = 0; i < lp.worker_num; ++i)
+ {
+ int ret;
+ struct epoll_event event;
+ struct lp_worker *worker = LP_WORKER (i);
+
+ out ("[%d] creating worker\n", i);
+
+ worker->io_buf = malloc (LP_IOBUF_SIZE);
+ ERR_RETURN (!worker->io_buf, -1, "Out of memory for IO buffer\n");
+
+ worker->ev_buf = malloc (sizeof (struct epoll_event) * LP_EVENT_NUM);
+ ERR_RETURN (!worker->ev_buf, -1, "Out of memory for events buffer\n");
+
+ TP (epoll_create);
+ worker->epfd = _epoll_create (10);
+ ERR_RETURN (worker->epfd < 0, -1, "epoll_create()=%d:%d\n",
+ worker->epfd, errno);
+ worker->ctlfd = eventfd (0, 0);
+ ERR_RETURN (worker->ctlfd < 0, -1, "eventfd()=%d:%d\n", worker->epfd,
+ errno);
+ TQ (epoll_create);
+
+ event.events = EPOLLIN;
+ event.data.u64 = LP_EV_MK (LP_CONTROL_TYPE, worker->ctlfd);
+ ret = _epoll_ctl (worker->epfd, EPOLL_CTL_ADD, worker->ctlfd, &event);
+ ERR_RETURN (ret, -1, "epoll_ctl(epfd:%d, add, evfd:%d,)=%d:%d\n",
+ worker->epfd, worker->ctlfd, ret, errno);
+
+ worker->tid =
+ lb_thread (lp_thread, worker, "lp-%s-%d",
+ lp.client_mode ? "client" : "server", i);
+ ERR_RETURN (worker->tid <= 0, -1, "Create worker thread failed\n");
+
+ if (lp.core)
+ {
+ ret = pthread_setaffinity_np (worker->tid, sizeof (set), &set);
+ if (ret)
+ err ("Bind core failed!\n");
+ }
+
+ if (lp.client_mode)
+ {
+ size_t size;
+
+ size =
+ sizeof (struct lb_run) + sizeof (struct lb_slot) * LP_UP_SLOT;
+ worker->up_run = (struct lb_run *) calloc (1, size);
+ ERR_RETURN (!worker->up_run, -1, "Out of memory for up run\n");
+
+ size =
+ sizeof (struct lb_run) + sizeof (struct lb_slot) * LP_DOWN_SLOT;
+ worker->down_run = (struct lb_run *) calloc (1, size);
+ ERR_RETURN (!worker->down_run, -1, "Out of memory for down run\n");
+
+ out
+ ("[%d] worker %ld created, client:%d server:%d epfd:%d ctlfd:%d\n",
+ worker->index, pthread_self (), worker->client_num,
+ worker->server_num, worker->epfd, worker->ctlfd);
+ }
+ else
+ {
+ int j;
+ TP (lp_listen);
+ for (j = 0; j < worker->server_num; ++j)
+ {
+ if (lp_listen (worker, j))
+ return -1;
+ }
+ TQ (lp_listen);
+ out ("[%d] worker %ld created, server:%d epfd:%d ctlfd:%d\n",
+ worker->index, pthread_self (), worker->server_num,
+ worker->epfd, worker->ctlfd);
+ }
+ }
+
+ out ("%s! running %s\n", CR, CC);
+ if (lp.client_mode)
+ {
+ lp_round (0);
+ }
+
+ lp.run_state = LP_EXEC;
+
+ futex_wake (&lp.run_state, lp.worker_num);
+ return 0;
+}
+
+void
+lp_stop (int state)
+{
+ int i;
+
+ lp.run_state = state;
+
+ for (i = 0; i < lp.worker_num; ++i)
+ {
+ struct lp_worker *worker = LP_WORKER (i);
+ if (worker->tid && worker->ctlfd >= 0)
+ {
+ (void) lp_post_cmd (worker->ctlfd, LP_CMD_STOP);
+ }
+ }
+}
+
+#define _FREE(p) do { if (p) { free(p); p = NULL; } } while (0)
+
+void
+lp_exit ()
+{
+ int i;
+
+ lp_stop (LP_EXIT);
+
+ for (i = 0; i < lp.worker_num; ++i)
+ {
+ int fd;
+ struct lp_worker *worker = LP_WORKER (i);
+
+ if (worker->tid)
+ {
+ const struct timespec wait = { tv_sec: 3, tv_nsec:0 };
+ (void) pthread_timedjoin_np (worker->tid, NULL, &wait);
+ worker->tid = 0;
+ }
+
+ for (fd = worker->server.first; fd >= 0; fd = LP_SESS (fd)->next_sess)
+ _close (fd);
+
+ lp_clean (worker);
+
+ if (worker->ctlfd >= 0)
+ {
+ _close (worker->ctlfd);
+ worker->ctlfd = -1;
+ }
+ if (worker->epfd >= 0)
+ {
+ _close (worker->epfd);
+ worker->epfd = -1;
+ }
+
+ _FREE (worker->server_addr);
+ _FREE (worker->client_addr);
+ _FREE (worker->up_run);
+ _FREE (worker->down_run);
+ _FREE (worker->io_buf);
+ _FREE (worker->ev_buf);
+ }
+
+ _FREE (lp.sess);
+}
+
+inline static const char *
+lp_errmsg (int e)
+{
+ static const char *errmsg[LP_ERRNO_NUM] = { 0 };
+ if (NULL == errmsg[e])
+ errmsg[e] = strerror (e);
+ return errmsg[e];
+}
+
+const static char *lp_cntmsg[LP_CNT_NUM] = {
+ [LP_E_SOCKET] = "socket",
+ [LP_E_BIND] = "bind",
+ [LP_E_ACCEPT] = "accept",
+ [LP_E_CONNECT] = "connect",
+ [LP_E_NODELAY] = "nodelay",
+ [LP_E_NONBLOCK] = "nonblock",
+ [LP_E_REUSEADDR] = "reuseaddr",
+ [LP_E_REUSEPORT] = "reuseport",
+ [LP_E_RECV] = "recv",
+ [LP_E_SEND] = "send",
+
+ [LP_E_EPADD] = "ep-add",
+ [LP_E_EPMOD] = "ep-mod",
+ [LP_E_EPDEL] = "ep-del",
+ [LP_E_EPWAIT] = "ep-wait",
+ [LP_E_EPUNUSED] = "ep-unused",
+ [LP_E_EPHUP] = "ep-hup",
+ [LP_E_EPERR] = "ep-err",
+ [LP_E_EPINOUT] = "ep-inout",
+ [LP_E_EVIDLE] = "ep-idle",
+ [LP_E_EPEVENT] = "ep-event",
+
+ [LP_E_IOSHUT] = "io-shut",
+ [LP_E_IOSIZE] = "io-size",
+ [LP_E_IOMORE] = "io-more",
+ [LP_E_IOEXCEED] = "io-exceed",
+ [LP_E_IOSEND0] = "io-send0",
+
+ [LP_W_CREATE] = "cre",
+ [LP_W_SOCKET] = "soc",
+ [LP_W_BIND] = "bin",
+ [LP_W_CONNECT] = "con",
+ [LP_W_CONNECTED] = "est",
+ [LP_W_ACCEPT] = "acc",
+ [LP_W_CLOSE] = "clo",
+};
+
+void
+lp_output (char buf[], const struct lp_stat *stat, uint64_t nsec, int mask)
+{
+ int i;
+ const uint64_t *cnt = stat->cnt;
+ static int w_num = 0, w_up = 0, w_down = 0, w_conn = 0;
+ static int w_q_mb = 0, w_q_cp = 0, w_r_mb = 0, w_r_cp = 0;
+
+ co_append (buf, 5, " %s ", CH);
+ w_num = co_wr_uint (buf, cnt[LP_REC_NUM], w_num);
+ co_append (buf, 5, "%s", CC);
+
+ co_append (buf, 3, " < ");
+ w_up = co_wr_uint (buf, lb_gdiv (cnt[LP_CONNECTED], nsec), w_up);
+ if (lp.client_mode && !lp.block_connecting)
+ {
+ co_append (buf, 1, " / ");
+ w_conn = co_wr_uint (buf, lb_gdiv (cnt[LP_CONNECT], nsec), w_conn);
+ }
+ co_append (buf, 3, " - ");
+ w_down = co_wr_uint (buf, lb_gdiv (cnt[LP_CLOSE], nsec), w_down);
+ co_append (buf, 3, " > ");
+
+ co_append (buf, 3, " [ ");
+ w_q_mb =
+ co_wr_uint (buf,
+ lb_gdiv (cnt[LP_QUERY_BYTE] * 8, nsec /* * (1000000 / 8) */ ),
+ w_q_mb);
+ co_append (buf, 1, " ");
+ w_q_cp = co_wr_uint (buf, lb_gdiv (cnt[LP_QUERY_COMP], nsec /* * 1000 */ ),
+ w_q_cp);
+ co_append (buf, 3, " : ");
+ w_r_mb =
+ co_wr_uint (buf,
+ lb_gdiv (cnt[LP_REPLY_BYTE] * 8, nsec /* * (1000000 / 8) */ ),
+ w_r_mb);
+ co_append (buf, 1, " ");
+ w_r_cp = co_wr_uint (buf, lb_gdiv (cnt[LP_REPLY_COMP], nsec /* * 1000 */ ),
+ w_r_cp);
+ co_append (buf, 3, " ] ");
+
+ co_app_if (cnt[LP_FAILED], buf, 40, " F:%s%s%s",
+ FR__, f_uint (lb_gdiv (cnt[LP_FAILED], nsec)), CC);
+
+ if (mask & LP_W_SIGN)
+ {
+ co_append (buf, 8, " time{");
+ for (i = LP_W_BEGIN; i < LP_W_END; i += 2)
+ co_app_if (cnt[i], buf, 60, " %s:%s", lp_cntmsg[i],
+ f_uint (cnt[i + 1] / cnt[i]));
+ co_append (buf, 4, " }");
+ }
+
+ if (mask & LP_E_SIGN)
+ {
+ co_append (buf, 8, " err{");
+ for (i = LP_E_BEGIN; i < LP_E_END; ++i)
+ co_app_if (cnt[i], buf, 60, " %s:%s", lp_cntmsg[i], f_uint (cnt[i]));
+ co_append (buf, 4, " }");
+ }
+
+ if (!lp.err_msg && (mask & LP_ERR_SIGN))
+ {
+ co_append (buf, 5, " E:{");
+ for (i = 1; i < LP_ERRNO_NUM; ++i)
+ co_app_if (stat->err[i], buf, 40, " %d:%lu", i, stat->err[i]);
+ co_app_if (stat->err[0], buf, 30, " -:%lu", stat->err[0]);
+ co_append (buf, 5, " }");
+ }
+
+ co_append (buf, 4, "\n");
+
+ if (lp.err_msg && (mask & LP_ERR_SIGN))
+ {
+ for (i = 1; i < LP_ERRNO_NUM; ++i)
+ co_app_if (stat->err[i], buf, 100, "<E%d:%lu> %s\n", i, stat->err[i],
+ lp_errmsg (i));
+ co_app_if (stat->err[0], buf, 100, "<E-:%s> Other error\n",
+ f_uint (stat->err[0]));
+ }
+}
+
+void
+lp_timer (uint64_t nsec)
+{
+ const static struct timespec delay = {.tv_sec = 0,.tv_nsec =
+ LP_DELAY_MS * 1000 * 1000
+ };
+ static int line = -2;
+ static int base;
+
+ int i, second, total = 0;
+ char buf[256];
+ struct tm *lc;
+ struct lp_stat *curr, sum = { 0 };
+
+ curr = lp.curr;
+ lp.curr = lp.next;
+ lp.next = curr;
+
+ {
+ time_t tv = time (NULL);
+ lc = localtime (&tv);
+ }
+
+ co_init (buf, sizeof (buf));
+
+ (void) nanosleep (&delay, NULL) /* wait for cps.curr use */ ;
+
+ for (i = 0; i < lp.worker_num; ++i)
+ {
+ int j, mask = 0;
+ uint64_t count = 0;
+
+ curr->cnt[LP_REC_NUM] = LP_WORKER (i)->sess.num;
+
+ for (count = 0, j = 0; j < LP_R_END; ++j)
+ {
+ sum.cnt[j] += curr->cnt[j];
+ count += curr->cnt[j];
+ }
+ if (count)
+ mask |= LP_R_SIGN;
+
+ for (count = 0, j = LP_E_BEGIN; j < LP_E_END; ++j)
+ {
+ sum.cnt[j] += curr->cnt[j];
+ count += curr->cnt[j];
+ }
+ if (count)
+ mask |= LP_E_SIGN;
+
+ if (lp.watch)
+ {
+ for (count = 0, j = LP_W_BEGIN; j < LP_W_END; j += 2)
+ {
+ sum.cnt[j] += curr->cnt[j];
+ sum.cnt[j + 1] += curr->cnt[j + 1];
+ count += curr->cnt[j];
+ }
+ if (count)
+ mask |= LP_W_SIGN;
+ }
+
+ for (count = 0, j = 0; j < LP_ERRNO_NUM; ++j)
+ {
+ sum.err[j] += curr->err[j];
+ count += curr->err[j];
+ }
+ if (count)
+ mask |= LP_ERR_SIGN;
+
+ if (mask && lp.verbose)
+ {
+ co_append (buf, 10, " %4dw ", i);
+ lp_output (buf, curr + i, nsec, mask);
+ }
+
+ total |= mask;
+ }
+
+ if (total)
+ {
+ line = line < 0 ? 0 : line + 1;
+ if (line == 0)
+ {
+ base = lc->tm_hour * 3600 + lc->tm_min * 60 + lc->tm_sec;
+ }
+ }
+ else
+ {
+ line = line > 0 ? 0 : line - 1;
+ if (line == -1)
+ co_append (buf, 5, "\n");
+ }
+
+ if (line >= 0)
+ {
+ if (line)
+ {
+ second = (lc->tm_hour * 3600 + lc->tm_min * 60 + lc->tm_sec) - base;
+ while (second < 0)
+ second += (24 * 3600);
+ co_append (buf, 10, " %5d", second);
+ }
+ else
+ {
+ co_append (buf, 10, " %2d:%02d ", lc->tm_hour, lc->tm_min);
+ }
+ lp_output (buf, &sum, nsec, total);
+ }
+
+ co_flush (buf);
+
+ (void) memset (curr, 0, sizeof (struct lp_stat) * lp.worker_num);
+}
+
+int
+lp_loop ()
+{
+ const static struct timespec timeout = {.tv_sec = 0,.tv_nsec = LP_LOOP_TIMER
+ };
+
+ struct timespec begin, from, last_begin;
+ time_t next_time = lp.interval;
+
+ LB_TIME (begin);
+ from = begin;
+ last_begin = begin;
+
+ while (lp.run_state > 0)
+ {
+ struct timespec now;
+
+ (void) nanosleep (&timeout, NULL);
+
+ LB_TIME (now);
+
+ if (lp.run_state == LP_CLEAN)
+ {
+ if (lp.active_worker == 0)
+ break;
+ }
+
+ if (lp.client_mode && lp.run_state == LP_EXEC)
+ {
+ struct lp_test *test = &lp.test[lp.test_id];
+ uint64_t total = lp_total_sess ();
+
+ if (LB_CMP_S (now, last_begin, test->time)
+ || (test->up >= test->down ? total >= test->target : total <=
+ test->target))
+ {
+ if (lp.test_id >= lp.test_num - 1)
+ {
+ lp.run_state = LP_CLEAN;
+ out ("%s! cleanup%s\n", CR, CC);
+ }
+ else
+ {
+ lp.test_id++; /* run changed */
+ last_begin = now;
+ lp_round (lp.test_id);
+ }
+ }
+ }
+
+ if (!LB_CMP_S (now, begin, next_time))
+ continue;
+
+ lp_timer (LB_SUB_NS (now, from));
+
+ from = now;
+ next_time += lp.interval;
+
+ if (!lp.client_mode)
+ {
+ const struct timespec rest = {.tv_sec = lp.interval - 1,.tv_nsec =
+ LP_LOOP_REST
+ };
+ (void) nanosleep (&rest, NULL);
+ }
+ }
+
+ return 0;
+}
+
+#ifndef SIGNAL_LP_C_
+#define SIGNAL_LP_C_
+
+void
+lp_break (int s)
+{
+ DBG (" SIGNALED %d running:%d\n", s, lp.run_state);
+ out ("\n");
+
+ if (lp.run_state == LP_CLEAN)
+ {
+ out ("%s! safe exit%s\n", CR, CC);
+ lp_exit ();
+ }
+ else if (lp.run_state >= 0)
+ {
+ out ("%s! clean exit%s\n", CR, CC);
+ lp_stop (LP_CLEAN);
+ }
+ else
+ {
+ out ("%s! direct exit%s\n", CR, CC);
+ exit (1);
+ }
+}
+
+void
+lp_sigpipe (int s)
+{
+ DBG ("SIGPIPE\n");
+}
+
+int
+lp_init ()
+{
+ struct sigaction s = { 0 };
+
+ (void) sigemptyset (&s.sa_mask);
+
+ s.sa_flags = SA_NODEFER;
+ s.sa_handler = (void *) lp_break;
+ (void) sigaction (SIGINT, &s, NULL);
+ (void) sigaction (SIGQUIT, &s, NULL);
+
+ s.sa_handler = lp_sigpipe;
+ (void) sigaction (SIGPIPE, &s, NULL);
+
+// lb_sigsegv_setup();
+
+ lp.CPU_NUM = get_nprocs ();
+ if (lp.CPU_NUM <= 0)
+ lp.CPU_NUM = 1;
+
+ {
+ struct timespec t;
+ LB_TIME (t);
+ srandom (getpid () + t.tv_sec + (t.tv_sec >> 32) + t.tv_nsec +
+ (t.tv_nsec >> 32));
+ }
+
+ return 0;
+}
+
+#endif
+
+void
+lp_usage (const char *name)
+{
+ out ("USAGE: %s [OPTIONS] TEST-SET... # %s version\n", name, VERSION_NAME);
+}
+
+void
+lp_help (const char *name)
+{
+ lp_usage (name);
+ out (" Options:\n");
+ out (" -s, --server LIST set one server address list\n");
+ out (" X.Y.Z.M-N:P1-P2,...\n");
+ out (" -c, --client LIST set one client address list\n");
+ out
+ (" CLIENT*SERVER: R.S.T.K-J:Pa-Pb,...*X.Y.Z.M-N:P1-P2,...\n");
+ out (" A,B,C,D*1,2 random link\n");
+ out (" A,B,C,D=1,2 A1B2C1D2\n");
+ out (" A,B,C,D}1,2 A1B1C1D1 A2B2C2D2\n");
+ out
+ (" A,B,C,D{1,2 A1A2 B1B2 C1C2 D1D2\n");
+ out
+ (" -b, --block set block mode for connecting(client only)\n");
+ out (" -n, --nodelay set nodelay\n");
+ out (" -i, --interval # report time(default:%ds max:%ds)\n",
+ LP_INTERVAL_DEF, LP_INTERVAL_MAX);
+ out
+ (" -m, --core #HEX set bind cpu core mask(hex mode)\n");
+#ifdef DEBUG
+ out (" -D, --debug show debug information\n");
+#endif
+ out
+ (" -w, --watch show watch time statistic\n");
+ out (" -e, --no-error #-# skip error\n");
+ out (" -E, --error-msg show error message\n");
+ out (" -C, --no-color no color\n");
+ out (" -v, --verbose show worker statistics\n");
+ out (" -h, --help help\n");
+ out (" TEST-SET for client\n");
+ out
+ (" TARGET@TIME+UP-DOWN=QUERY:REPLY*TIMES-/PERIOD%%WAIT (client only)\n");
+ out (" TARGET max connection(default: INFINITE)\n");
+ out (" @TIME max time(0 or default:INFINITE)\n");
+ out
+ (" +UP connect rate(default: 0 no connnect; *: INFINITE)\n");
+ out
+ (" -DOWN close rate(default: 0 no close; *: INFINITE)\n");
+ out (" =... IO set(default: no IO)\n");
+ out (" QUERY send query data len(%u-%u)\n",
+ LP_QUERY_MIN, LP_QUERY_MAX);
+ out
+ (" :REPLY receive response data len(0-%d; default: same with QUERY)\n",
+ LP_REPLY_MAX);
+ out
+ (" *TIMES- IO times(0 or default: INFINITE; suffix-: IO then close)\n");
+ out
+ (" /PERIOD IO period time(0-%us; default: one by one)\n",
+ LP_PERIOD_MAX);
+ out
+ (" %%WAIT first IO wait time(0-%us; default: 0 no wait)\n",
+ LP_WAIT_MAX);
+ out (" UNITS:\n");
+ out (" k=1000 m=1000k g=1000m w=10000 K=1024 M=1024K G=1024M\n");
+ out (" s=Seconds m=Minutes h=Hours\n");
+}
+
+int
+lp_args_test (const char *arg)
+{
+ const char *p;
+ struct lp_test *test = &lp.test[lp.test_num];
+
+ ERR_RETURN (lp.test_num >= LP_MAX_TEST, -1, "Too many test set, max:%d\n",
+ LP_MAX_TEST);
+ (void) memset (test, 0, sizeof (struct lp_test));
+
+ if (*arg >= '0' && *arg <= '9')
+ {
+ test->target = p_value (arg, LP_TARGET_MAX, UB_1kmgwKMG, &p);
+ ERR_RETURN (!p, -1, "Invalid test TARGET set: '%s'\n", arg);
+ }
+ else
+ {
+ test->target = LP_TARGET_DEF;
+ p = arg;
+ }
+
+ if (*p == '@')
+ {
+ test->time = p_value (p + 1, LP_TIME_MAX, UB_hms1, &p);
+ ERR_RETURN (!p, -1, "Invalid test TIME set: '%s'\n", arg);
+ }
+ else
+ {
+ test->time = LP_TIME_DEF;
+ }
+
+ if (*p == '+')
+ {
+ if (p[1] == '*')
+ {
+ test->up = LP_UP_INF;
+ p += 2;
+ }
+ else
+ {
+ test->up = p_value (p + 1, LP_UP_MAX, UB_1kmgwKMG, &p);
+ ERR_RETURN (!p, -1, "Invalid test UP-RATE set: '%s'\n", arg);
+ }
+ }
+ else
+ {
+ test->up = LP_UP_DEF;
+ }
+
+ if (*p == '-')
+ {
+ if (p[1] == '*')
+ {
+ test->down = LP_DOWN_INF;
+ p += 2;
+ }
+ else
+ {
+ test->down = p_value (p + 1, LP_DOWN_MAX, UB_1kmgwKMG, &p);
+ ERR_RETURN (!p, -1, "Invalid test DOWN-RATE set: '%s'\n", arg);
+ }
+ }
+ else
+ {
+ test->down = LP_DOWN_DEF;
+ }
+
+ if (*p == '=')
+ {
+ test->query = p_value (p + 1, LP_QUERY_MAX, UB_1kmgwKMG, &p);
+ ERR_RETURN (!p
+ || test->query < LP_QUERY_MIN, -1,
+ "Invalid test QUERY '%s'\n", arg);
+
+ if (*p == ':')
+ {
+ test->reply = p_value (p + 1, LP_REPLY_MAX, UB_1kmgwKMG, &p);
+ ERR_RETURN (!p, -1, "Invalid test REPLY set: '%s'\n", arg);
+ }
+ else
+ {
+ test->reply = test->query;
+ }
+
+ if (*p == '*')
+ {
+ test->times = p_uint (p + 1, LP_TIMES_MAX, &p);
+ ERR_RETURN (!p, -1, "Invalid test TIMES set: '%s'\n", arg);
+ if (test->times == 0)
+ test->times = LP_TIMES_INF;
+ if (*p == '-')
+ {
+ test->close_after_io = 1;
+ p++;
+ }
+ }
+ else
+ {
+ test->times = LP_TIMES_DEF;
+ }
+
+ if (*p == '/')
+ {
+ test->period = p_value (p + 1, LP_PERIOD_MAX, UB_hms1, &p);
+ ERR_RETURN (!p, -1, "Invalid test PRIOD set: '%s'\n", arg);
+ if (*p == '%')
+ {
+ test->wait = p_value (p + 1, LP_WAIT_MAX, UB_hms1, &p);
+ ERR_RETURN (!p, -1, "Invalid test WAIT set: '%s'\n", arg);
+ }
+ else
+ {
+ test->wait = LP_WAIT_DEF;
+ }
+ }
+ else
+ {
+ test->period = LP_PERIOD_DEF;
+ test->wait = 0;
+ }
+ }
+ else
+ {
+ test->query = 0;
+ test->reply = 0;
+ test->times = 0;
+ test->period = 0;
+ test->wait = 0;
+ }
+
+ ERR_RETURN (*p, -1, "Invalid test set: '%s'\n", arg);
+
+ if (test->up < test->down)
+ test->down_mode = 1;
+ lp.test_num++;
+ return 0;
+}
+
+inline static void
+lp_noerr (int b, int e)
+{
+ for (; b <= e; ++b)
+ lp.no_err[b / 64] |= (1 << (b % 64));
+}
+
+/* -e M-N */
+int
+lp_args_noerr (const char *arg)
+{
+ int b, e;
+
+ b = (int) p_uint (arg, LP_ERRNO_NUM, &arg);
+ if (!arg)
+ return -1;
+ if (*arg == '-')
+ {
+ e = (int) p_uint (arg + 1, LP_ERRNO_NUM, &arg);
+ if (!arg || e < b)
+ return -1;
+ }
+ else
+ {
+ e = b;
+ }
+
+ if (*arg != 0)
+ return -1;
+
+ lp_noerr (b, e);
+
+ return 0;
+}
+
+struct lp_worker *
+lp_init_worker ()
+{
+ int i;
+ struct lp_worker *worker = LP_WORKER (lp.worker_num);
+
+ ERR_RETURN (lp.worker_num >= LP_MAX_WORKER, NULL,
+ "Too many workers, limit:%d\n", LP_MAX_WORKER);
+
+ (void) memset (worker, 0, sizeof (*worker));
+
+ worker->index = lp.worker_num;
+ worker->epfd = -1;
+ worker->ctlfd = -1;
+
+ lp_init_head (&worker->server);
+ lp_init_head (&worker->sess);
+ lp_init_head (&worker->conn);
+ for (i = 0; i < LP_MAX_TEST; ++i)
+ {
+ lp_init_head (&worker->rest[i]);
+ lp_init_head (&worker->wait[i]);
+ }
+
+ lp.worker_num++;
+
+ return worker;
+}
+
+int
+lp_args (int argc, char *argv[])
+{
+ int i, opt, index, ret;
+ struct lp_worker *worker;
+ const char *arg;
+ int server_mode = 0;
+
+ while (EOF !=
+ (opt = getopt_long (argc, argv, LP_OPTIONS, lp_options, &index)))
+ {
+ const char *end;
+
+ switch (opt)
+ {
+ case 'c':
+ ERR_RETURN (server_mode, -1, "Only server or client\n");
+ lp.client_mode = 1;
+ worker = lp_init_worker ();
+ if (!worker)
+ return -1;
+ worker->client_num = p_addrin_list (optarg, &worker->client_addr,
+ LP_CLIENT_MAX,
+ PA_DEF_PORT | PAL_NO_SPACE,
+ &arg);
+ ERR_RETURN (worker->client_num <= 0, -1,
+ "Bad client for address list '%s'\n", optarg);
+ for (i = 0; i < CNT_OF (MODES); ++i)
+ {
+ if (*arg == MODES[i][0])
+ break;
+ }
+ ERR_RETURN (i >= CNT_OF (MODES), -1,
+ "Bad mode for address list '%s'\n", optarg);
+ worker->link_mode = i;
+ arg++;
+ worker->server_num = p_addrin_list (arg, &worker->server_addr,
+ LP_SERVER_MAX,
+ PA_MUST_PORT | PAL_NO_SPACE,
+ NULL);
+ ERR_RETURN (worker->server_num <= 0, -1,
+ "Bad server for address list '%s'\n", arg);
+ break;
+ case 's':
+ ERR_RETURN (lp.client_mode, -1, "Only server or client\n");
+ server_mode = 1;
+ worker = lp_init_worker ();
+ if (!worker)
+ return -1;
+ worker->server_num =
+ p_addrin_list (optarg, &worker->server_addr, LP_SERVER_MAX,
+ PA_MUST_PORT | PAL_NO_SPACE, NULL);
+ ERR_RETURN (worker->server_num <= 0, -1,
+ "Bad server for address list '%s'\n", optarg);
+ break;
+
+ case 'i':
+ lp.interval = (int) p_int (optarg, LP_INTERVAL_MAX, &end);
+ ERR_RETURN (!end || *end, -1, "Invalid interval '%s'\n", optarg);
+ break;
+ case 'e':
+ ret = lp_args_noerr (optarg);
+ ERR_RETURN (ret, ret, "Invalid no-error set '%s'\n", optarg);
+ break;
+ case 'm':
+ lp.core = p_hex (optarg, &end);
+ ERR_RETURN (!end
+ || lp.core >= (1 << lp.CPU_NUM), -1,
+ "Invalid bind core set\n");
+ break;
+ case 'C':
+ lb_set_color (LB_NO_COLOR);
+ break;
+
+ case 'b':
+ lp.block_connecting = 1;
+ break;
+ case 'n':
+ lp.nodelay = 1;
+ break;
+ case 'w':
+ lp.watch = 1;
+ break;
+ case 'E':
+ lp.err_msg = 1;
+ break;
+ case 'v':
+ lp.verbose = 1;
+ break;
+
+#ifdef DEBUG
+ case 'D':
+ enable_debug = 1;
+ break;
+#endif
+ case 'h':
+ lp_help (argv[0]);
+ exit (0);
+ case '?':
+ err ("Invalid arguments\n");
+ return -1;
+ default:
+ err ("Unknown option '%c'.\n", opt);
+ return -1;
+ }
+ }
+
+ ERR_RETURN (lp.worker_num <= 0, -1,
+ "Please set server or client address\n");
+
+ if (lp.client_mode)
+ {
+ for (index = optind; index < argc; ++index)
+ {
+ ret = lp_args_test (argv[index]);
+ if (ret)
+ return ret;
+ }
+ ERR_RETURN (lp.test_num <= 0, -1, "Please set test\n");
+ }
+ else
+ {
+ ERR_RETURN (optind < argc, -1, "Unknown option '%s'\n", argv[optind]);
+ }
+
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ if (argc <= 1)
+ {
+ lp_usage (argv[0]);
+ return 0;
+ }
+
+ if (lp_init ())
+ return 1;
+
+ if (lp_args (argc, argv) == 0 && lp_start () == 0)
+ lp_loop ();
+
+ lp_exit ();
+
+ return 0;
+}
diff --git a/thirdparty/apps/testapp/lp/lp.h b/thirdparty/apps/testapp/lp/lp.h
new file mode 100644
index 0000000..4a2a09a
--- /dev/null
+++ b/thirdparty/apps/testapp/lp/lp.h
@@ -0,0 +1,615 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef _LP_H_
+#define _LP_H_ 1
+
+#define LP_DBG 1
+
+#if LP_DBG
+#define LP_IF_DBG(line) line
+#else
+#define LP_IF_DBG(line) ((void)0)
+#endif
+
+#define LP_ASSERT(cond) LP_IF_DBG(assert(cond))
+
+#define LP_DELAY_MS 5
+#define LP_LOOP_TIMER (49 * 1000 * 1000)
+#define LP_LOOP_REST (900 * 1000 * 1000)
+
+#define LP_UP_SLOT 1024
+#define LP_UP_NSEC (1000 * 1000)
+
+#define LP_DOWN_SLOT 1024
+#define LP_DOWN_NSEC (1000 * 1000)
+
+#define LP_MAX_FD (16 * 1024 * 1024)
+#define LP_MAX_WORKER 64
+#define LP_MAX_TEST 10
+
+#define LP_IOBUF_SIZE (128 * 1024)
+
+#define LP_EVENT_NUM 256
+
+#define LP_SERVER_MAX 10000
+#define LP_CLIENT_MAX 100000
+
+#define LP_INFINITE (0xFFFFffff)
+#define LP_UNLIMITED LP_INFINITE
+#define LP_VALUE_MAX (LP_INFINITE - 1)
+
+#define LP_INTERVAL_MIN 1
+#define LP_INTERVAL_MAX 60
+#define LP_INTERVAL_DEF 1
+
+#define LP_TARGET_INF LP_INFINITE
+#define LP_TARGET_MAX (16 * 1000 * 1000) /* 16m max */
+#define LP_TARGET_DEF LP_INFINITE
+
+#define LP_TIME_INF LP_INFINITE
+#define LP_TIME_MAX (24 * 60 * 60)
+#define LP_TIME_DEF LP_TIME_INF
+
+#define LP_UP_MAX ( 1 * 1000 * 1000)
+#define LP_UP_INF LP_INFINITE
+#define LP_UP_DEF 0
+
+#define LP_DOWN_MAX (1 * 1000 * 1000)
+#define LP_DOWN_INF LP_INFINITE
+#define LP_DOWN_DEF 0
+
+#define LP_QUERY_MIN 8 /* 2 unsigned int */
+#define LP_QUERY_MAX 65536
+
+#define LP_REPLY_MAX (10 * 1024 * 1024) /* 10M */
+
+#define LP_TIMES_INF LP_INFINITE
+#define LP_TIMES_MAX LP_VALUE_MAX
+#define LP_TIMES_DEF LP_TIMES_INF
+
+#define LP_PERIOD_MIN 1
+#define LP_PERIOD_MAX (60 * 60)
+#define LP_PERIOD_DEF 1
+
+#define LP_WAIT_MAX (60 * 60)
+#define LP_WAIT_DEF 0
+
+#define LP_FLAG_MASK (0xffffFFFFull << 32)
+#define LP_TYPE_MASK (0x3ull << 32)
+#define LP_CONTROL_TYPE (0x1ull << 32)
+#define LP_LISTEN_TYPE (0x2ull << 32)
+#define LP_SESSION_TYPE (0x3ull << 32)
+
+inline static uint64_t
+LP_EV_MK (uint64_t flag, int fd)
+{
+ return flag | (uint64_t) (uint32_t) fd;
+}
+
+inline static int
+LP_EV_FD (uint64_t data_u64)
+{
+ return (int) (uint32_t) data_u64;
+}
+
+inline static uint64_t
+LP_EV_TYPE (uint64_t data_u64)
+{
+ return data_u64 & LP_TYPE_MASK;
+}
+
+inline static uint64_t
+LP_EV_FLAG (uint64_t data_u64)
+{
+ return data_u64 & LP_FLAG_MASK;
+}
+
+#define LP_R_SIGN 1
+#define LP_E_SIGN 2
+#define LP_W_SIGN 4
+#define LP_ERR_SIGN 8
+
+enum
+{
+ LP_CONNECTED,
+ LP_CONNECT,
+ LP_CLOSE,
+ LP_FAILED,
+
+ LP_QUERY_COMP,
+ LP_QUERY_BYTE,
+ LP_REPLY_COMP,
+ LP_REPLY_BYTE,
+
+ LP_REC_NUM,
+
+ LP_R_END,
+ LP_E_BEGIN = LP_R_END,
+
+ LP_E_SOCKET = LP_E_BEGIN,
+ LP_E_BIND,
+ LP_E_ACCEPT,
+ LP_E_CONNECT,
+ LP_E_NODELAY,
+ LP_E_NONBLOCK,
+ LP_E_REUSEADDR,
+ LP_E_REUSEPORT,
+ LP_E_RECV,
+ LP_E_SEND,
+
+ LP_E_EPADD,
+ LP_E_EPMOD,
+ LP_E_EPDEL,
+ LP_E_EPWAIT,
+ LP_E_EPUNUSED,
+ LP_E_EPHUP,
+ LP_E_EPERR,
+ LP_E_EPINOUT,
+ LP_E_EVIDLE,
+ LP_E_EPEVENT,
+
+ LP_E_IOSHUT,
+ LP_E_IOSIZE,
+ LP_E_IOMORE,
+ LP_E_IOEXCEED,
+ LP_E_IOSEND0,
+
+ LP_E_END,
+ LP_W_BEGIN = LP_E_END,
+
+ LP_W_CREATE = LP_W_BEGIN, LP_T_CREATE,
+ LP_W_SOCKET, LP_T_SOCKET,
+ LP_W_BIND, LP_T_BIND,
+ LP_W_CONNECT, LP_T_CONNECT,
+ LP_W_CONNECTED, LP_T_CONNECTED,
+ LP_W_ACCEPT, LP_T_ACCEPT,
+ LP_W_CLOSE, LP_T_CLOSE,
+
+ LP_W_END,
+
+ LP_CNT_NUM = LP_W_END
+};
+
+#define LP_ERRNO_NUM 256
+#define LP_NOERR_NUM ((LP_ERRNO_NUM + 63) / 64)
+
+struct lp_stat
+{
+ uint64_t cnt[LP_CNT_NUM];
+ uint64_t err[LP_ERRNO_NUM];
+};
+
+#define LP_STAT(worker) (lp.curr + (worker)->index)
+#define LP_ADD(worker, id, num) (LP_STAT(worker)->cnt[(id)] += (num))
+#define LP_CNT(worker, id) (++LP_STAT(worker)->cnt[(id)])
+#define LP_ERR(worker, id, e) do { \
+ unsigned int _e = (unsigned int)(e); \
+ if (_e >= LP_ERRNO_NUM) \
+ _e = 0; \
+ if (0 == (lp.no_err[_e / 64] & (1 << (_e % 64)))) { \
+ struct lp_stat *_stat = LP_STAT(worker); \
+ _stat->cnt[(id)]++; \
+ _stat->err[_e]++; \
+ } \
+} while (0)
+#define LP_CNT2(worker, id1, id2) do { \
+ struct lp_stat *_stat = LP_STAT(worker); \
+ _stat->cnt[(id1)]++; \
+ _stat->cnt[(id2)]++; \
+} while (0)
+#define LP_ERR2(worker, id1, id2, e) do { \
+ unsigned int _e = (unsigned int)(e); \
+ if (_e >= LP_ERRNO_NUM) \
+ _e = 0; \
+ if (0 == (lp.no_err[_e / 64] & (1 << (_e % 64)))) { \
+ struct lp_stat *_stat = LP_STAT(worker); \
+ _stat->cnt[(id1)]++; \
+ _stat->cnt[(id2)]++; \
+ _stat->err[_e]++; \
+ } \
+} while (0)
+
+#define LP_TIME_SET(begin) struct timespec begin; \
+ do { \
+ if (lp.watch) \
+ LB_TIME(begin); \
+ } while (0)
+#define LP_TIME_REG(worker, id, nsec) do { \
+ if (lp.watch) { \
+ uint64_t *_w = &(LP_STAT(worker)->cnt[(id)]); \
+ _w[0] ++; \
+ _w[1] += nsec; \
+ } \
+} while (0)
+#define LP_TIME_FOR(worker, id, begin, end) LP_TIME_REG((worker), (id), LB_SUB_NS((end), (begin)))
+#define LP_TIME_END(worker, id, begin) do { \
+ LP_TIME_SET(_end); \
+ LP_TIME_FOR((worker), (id), (begin), _end); \
+} while (0)
+
+struct lp_io
+{
+ int query;
+ int reply;
+} __attribute__ ((__packed__));
+
+struct lp_head
+{
+ uint32_t num;
+ int first;
+ int *last;
+};
+
+enum
+{
+ LP_S_UNUSED = 0,
+ LP_S_PREPARE = 0x20,
+ LP_S_CONNECTING = 0x80,
+
+ LP_S_CONNECTED = 0x10,
+
+ LP_S_IDLE = LP_S_CONNECTED | 0,
+ LP_S_QUERY = LP_S_CONNECTED | 1,
+ LP_S_REPLY = LP_S_CONNECTED | 2,
+ LP_S_REST = LP_S_CONNECTED | 4,
+ LP_S_WAIT = LP_S_CONNECTED | 8,
+};
+
+struct lp_sess
+{
+ uint8_t state;
+ uint8_t test;
+ uint8_t epout;
+ uint32_t io_num;
+ int query;
+ int reply;
+
+ int *prev_sess;
+ int next_sess;
+ int next_rest;
+ int *prev_rest;
+ struct timespec time;
+
+#if LP_DBG
+ uint16_t work;
+ uint16_t anum;
+ uint16_t fnum;
+#endif
+};
+
+struct lp_test
+{
+ uint32_t target;
+ uint32_t time;
+
+ uint32_t up;
+ uint32_t down;
+
+ int query;
+ int reply;
+
+ uint32_t times;
+ uint32_t period;
+ uint32_t wait;
+
+ uint8_t down_mode;
+ uint8_t close_after_io;
+ uint8_t _pad[2];
+};
+
+enum
+{
+ LP_SYNC,
+ LP_RAND,
+ LP_CPS,
+ LP_SPC,
+};
+
+struct lp_worker
+{
+ int index;
+ int epfd;
+ int ctlfd;
+ int server_num;
+ int client_num;
+ int link_mode;
+
+ pthread_t tid;
+
+ struct lp_head server;
+ struct lp_head sess; /* ESTABLISHED */
+ struct lp_head conn; /* connecting(for nonblock of client) */
+ struct lp_head rest[LP_MAX_TEST]; /* io wait queue */
+ struct lp_head wait[LP_MAX_TEST]; /* io wait queue */
+
+ struct sockaddr_in *server_addr;
+ struct sockaddr_in *client_addr;
+
+ struct lb_run *up_run;
+ struct lb_run *down_run;
+
+ struct epoll_event *ev_buf;
+
+ void *io_buf;
+};
+
+enum lp_state
+{
+ LP_EXIT = -1,
+ LP_INIT = 0,
+ LP_EXEC = 1,
+ LP_CLEAN = 2,
+};
+
+struct lp_var
+{
+ int CPU_NUM;
+ volatile int run_state;
+ int worker_num;
+
+ uint8_t verbose;
+ uint8_t watch;
+ uint8_t err_msg;
+ uint8_t _pad;
+
+ int client_mode;
+ int block_connecting;
+
+ int interval;
+ int nodelay;
+
+ int test_num;
+ volatile int test_id;
+
+ uint64_t core;
+ uint64_t active_worker;
+
+ struct lp_sess *sess;
+ struct lp_stat *volatile curr;
+ struct lp_stat *next;
+ struct lp_stat stat[2][LP_MAX_WORKER];
+ struct lp_test test[LP_MAX_TEST];
+ struct lp_worker worker[LP_MAX_WORKER];
+ uint64_t no_err[LP_NOERR_NUM];
+};
+
+extern struct lp_var lp;
+
+inline static struct lp_worker *
+LP_WORKER (int index)
+{
+ return &lp.worker[index];
+}
+
+inline static struct lp_sess *
+LP_SESS (int fd)
+{
+ return lp.sess + fd;
+}
+
+inline static uint64_t
+lp_total_sess ()
+{
+ int i;
+ uint64_t total = 0;
+ for (i = 0; i < lp.worker_num; ++i)
+ total += lp.worker[i].sess.num;
+ return total;
+}
+
+#define LP_APPEND(head, fd, sess, name) do { \
+ struct lp_sess *_s = (sess); \
+ LP_ASSERT(_s->next_##name == fd); \
+ LP_ASSERT(_s->prev_##name == NULL); \
+ _s->next_##name = -1; \
+ _s->prev_##name = (head).last; \
+ *(head).last = fd; \
+ (head).last = &_s->next_##name; \
+ (head).num++; \
+} while (0)
+
+#define LP_REMOVE(head, fd, sess, name) do { \
+ struct lp_sess *_s = (sess); \
+ LP_ASSERT((head).num); \
+ if ((*_s->prev_##name = _s->next_##name) >= 0) \
+ LP_SESS(_s->next_##name)->prev_##name = _s->prev_##name; \
+ else \
+ (head).last = _s->prev_##name; \
+ (head).num--; \
+ LP_IF_DBG(_s->next_##name = (fd)); \
+ LP_IF_DBG(_s->prev_##name = NULL); \
+} while (0)
+
+inline static void
+lp_init_head (struct lp_head *head)
+{
+ head->first = -1;
+ head->num = 0;
+ head->last = &head->first;
+}
+
+inline static void
+lp_dest_sess (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ LP_ASSERT (sess->next_rest == fd);
+ LP_ASSERT (sess->next_sess == fd);
+ LP_ASSERT (sess->prev_rest == NULL);
+ LP_ASSERT (sess->prev_sess == NULL);
+ LP_ASSERT (sess->work == worker->index);
+#if LP_DBG
+ sess->fnum++;
+#endif
+ LP_ASSERT (sess->fnum == sess->anum);
+
+ sess->state = LP_S_UNUSED;
+}
+
+inline static struct lp_sess *
+lp_init_sess (struct lp_worker *worker, int fd)
+{
+ struct lp_sess *sess = LP_SESS (fd);
+
+ if (sess->state != LP_S_UNUSED)
+ {
+ void lp_dump_sess (int fd);
+ wrn ("Invalid session fd:%d\n", fd);
+#if LP_DBG
+ lp_dump_sess (fd);
+#endif
+ LP_ASSERT (0);
+ }
+ LP_ASSERT (sess->fnum == sess->anum);
+
+ sess->state = LP_S_PREPARE;
+ sess->epout = 0;
+ sess->io_num = 0;
+ sess->query = 0;
+ sess->reply = 0;
+
+#if LP_DBG
+ sess->work = worker->index;
+ sess->anum++;
+ sess->next_rest = sess->next_sess = fd;
+ sess->prev_rest = sess->prev_sess = NULL;
+#endif
+
+ return sess;
+}
+
+inline static void
+lp_add_conn (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ LP_ASSERT (sess->state == LP_S_PREPARE);
+
+ LP_APPEND (worker->conn, fd, sess, sess);
+ sess->state = LP_S_CONNECTING;
+}
+
+inline static void
+lp_out_conn (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ LP_ASSERT (worker->conn.num);
+ LP_ASSERT (sess->state == LP_S_CONNECTING);
+
+ LP_REMOVE (worker->conn, fd, sess, sess);
+}
+
+inline static void
+lp_del_conn (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ lp_out_conn (worker, fd, sess);
+ lp_dest_sess (worker, fd, sess);
+ _close (fd);
+}
+
+inline static void
+lp_add_rest (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ LP_APPEND (worker->rest[sess->test], fd, sess, rest);
+ sess->state = LP_S_REST;
+}
+
+inline static void
+lp_out_rest (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ LP_ASSERT (worker->rest[sess->test].num);
+
+ LP_REMOVE (worker->rest[sess->test], fd, sess, rest);
+ sess->state = LP_S_IDLE;
+}
+
+inline static void
+lp_add_wait (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ LP_APPEND (worker->wait[sess->test], fd, sess, rest);
+ sess->state = LP_S_WAIT;
+}
+
+inline static void
+lp_out_wait (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ LP_ASSERT (worker->wait[sess->test].num);
+
+ LP_REMOVE (worker->wait[sess->test], fd, sess, rest);
+ sess->state = LP_S_IDLE;
+}
+
+inline static void
+lp_del_sess (struct lp_worker *worker, int fd)
+{
+ struct lp_sess *sess = LP_SESS (fd);
+
+ LP_ASSERT (sess->state & LP_S_CONNECTED);
+
+ if (sess->state == LP_S_REST)
+ lp_out_rest (worker, fd, sess);
+ else if (sess->state == LP_S_WAIT)
+ lp_out_wait (worker, fd, sess);
+ LP_REMOVE (worker->sess, fd, sess, sess);
+
+ lp_dest_sess (worker, fd, sess);
+ LP_TIME_SET (begin);
+ _close (fd);
+ LP_TIME_END (worker, LP_W_CLOSE, begin);
+
+ LP_CNT (worker, LP_CLOSE);
+}
+
+inline static int
+lp_epctl (const struct lp_worker *worker, int op, int fd, uint32_t io)
+{
+ struct epoll_event event;
+ event.events = io | EPOLLET | EPOLLRDHUP | EPOLLHUP;
+ event.data.u64 = LP_EV_MK (LP_SESSION_TYPE, fd);
+ return _epoll_ctl (worker->epfd, op, fd, &event);
+}
+
+#define lp_epadd(worker, fd, io) lp_epctl((worker), EPOLL_CTL_ADD, (fd), (io))
+#define lp_epmod(worker, fd, io) lp_epctl((worker), EPOLL_CTL_MOD, (fd), (io))
+#define lp_epdel(worker, fd) _epoll_ctl((worker->epfd), EPOLL_CTL_DEL, (fd), NULL)
+
+inline static int
+lp_set_epout (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ if (sess->epout)
+ return 1;
+
+ if (lp_epmod (worker, fd, EPOLLOUT))
+ {
+ LP_ERR (worker, LP_E_EPMOD, errno);
+ return -1;
+ }
+
+ sess->epout = 1;
+ return 1;
+}
+
+#define LP_CMD_STOP 1
+
+inline static int
+lp_post_cmd (int fd, long long int cmd)
+{
+ ssize_t ret = _write (fd, (void *) &cmd, sizeof (cmd));
+
+ return ret - sizeof (cmd);
+}
+
+void lp_client (struct lp_worker *worker);
+void lp_server (struct lp_worker *worker);
+int lp_listen (struct lp_worker *worker, int index);
+
+#endif /* #ifndef _LP_H_ */
diff --git a/thirdparty/apps/testapp/lp/lpc.c b/thirdparty/apps/testapp/lp/lpc.c
new file mode 100644
index 0000000..7da0414
--- /dev/null
+++ b/thirdparty/apps/testapp/lp/lpc.c
@@ -0,0 +1,669 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+#include "lp.h"
+
+inline static int
+lp_io_finish (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ int ret;
+
+ sess->state = LP_S_IDLE;
+ --sess->io_num;
+
+ if (sess->io_num)
+ {
+ lp_add_rest (worker, fd, sess);
+ sess->time.tv_sec += lp.test[sess->test].period;
+ return 0;
+ }
+
+ if (lp.test[sess->test].close_after_io)
+ return -1;
+
+ if (lp_epdel (worker, fd))
+ LP_ERR (worker, LP_E_EPDEL, errno);
+
+ return 0;
+}
+
+int
+lp_recv_reply (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ int ret;
+ char *buf = worker->io_buf;
+
+ LP_ASSERT (sess->query == 0);
+
+ while (1)
+ {
+ ret = _recv (fd, buf, LP_IOBUF_SIZE, 0);
+ if (ret > 0)
+ {
+ LP_ADD (worker, LP_REPLY_BYTE, ret);
+ sess->reply -= ret;
+ }
+ else if (ret < 0)
+ {
+ int e = errno;
+ if (e == EWOULDBLOCK || e == EAGAIN)
+ {
+ if (sess->reply > 0)
+ return 1;
+ break;
+ }
+ if (e == EINTR)
+ continue;
+ LP_ERR (worker, LP_E_RECV, e);
+ return -1;
+ }
+ else
+ {
+ if (sess->reply)
+ LP_CNT (worker, LP_E_IOSHUT);
+ else
+ LP_CNT (worker, LP_REPLY_COMP);
+ return -1;
+ }
+ }
+
+ LP_CNT (worker, LP_REPLY_COMP);
+
+ if (sess->reply < 0)
+ {
+ LP_CNT (worker, LP_E_IOEXCEED);
+ sess->reply = 0;
+ }
+
+ return lp_io_finish (worker, fd, sess);
+}
+
+int
+lp_more_query (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ int ret;
+ char *buf = worker->io_buf;
+
+ LP_ASSERT (sess->io_num);
+
+ while (sess->query > 0)
+ {
+ const int LEN =
+ sess->query < LP_IOBUF_SIZE ? sess->query : LP_IOBUF_SIZE;
+
+ ret = _send (fd, buf, LEN, 0);
+ if (ret > 0)
+ {
+ LP_ADD (worker, LP_QUERY_BYTE, ret);
+ sess->query -= ret;
+ }
+ else if (ret < 0)
+ {
+ int e = errno;
+ if (e == EWOULDBLOCK || e == EAGAIN)
+ return lp_set_epout (worker, fd, sess);
+ if (e == EINTR)
+ continue;
+ LP_ERR (worker, LP_E_SEND, e);
+ return -1;
+ }
+ else
+ {
+ LP_CNT (worker, LP_E_IOSEND0);
+ }
+ }
+
+ LP_CNT (worker, LP_QUERY_COMP);
+
+ if (sess->epout)
+ {
+ if (lp_epmod (worker, fd, EPOLLIN))
+ {
+ LP_ERR (worker, LP_E_EPMOD, errno);
+ return -1;
+ }
+ sess->epout = 0;
+ }
+
+ if (!sess->reply)
+ {
+ return lp_io_finish (worker, fd, sess);
+ }
+
+ sess->state = LP_S_REPLY;
+ return 0;
+}
+
+int
+lp_new_query (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ int ret, len = 0;
+ char *buf = worker->io_buf;
+ struct lp_io *io = (struct lp_io *) buf;
+
+ LP_ASSERT (sess->state == LP_S_IDLE);
+ LP_ASSERT (sess->query == 0);
+ LP_ASSERT (sess->reply == 0);
+ LP_ASSERT (sess->io_num);
+
+ sess->state = LP_S_QUERY;
+ sess->query = lp.test[sess->test].query;
+ sess->reply = lp.test[sess->test].reply;
+
+ io->query = htonl (sess->query);
+ io->reply = htonl (sess->reply);
+
+ while (1)
+ {
+ ret = _send (fd, buf + len, sess->query - len, 0);
+ if (ret > 0)
+ {
+ LP_ADD (worker, LP_QUERY_BYTE, ret);
+ len += ret;
+ if (len >= sizeof (struct lp_io))
+ break;
+ LP_CNT (worker, LP_E_IOMORE);
+ }
+ else if (ret < 0)
+ {
+ int e = errno;
+ if (e == EWOULDBLOCK || e == EAGAIN)
+ {
+ LP_CNT (worker, LP_E_IOMORE);
+ continue;
+ }
+ if (e == EINTR)
+ continue;
+ LP_ERR (worker, LP_E_SEND, e);
+ return -1;
+ }
+ else
+ {
+ LP_CNT (worker, LP_E_IOSEND0);
+ }
+ }
+
+ sess->query -= len;
+
+ return lp_more_query (worker, fd, sess);
+}
+
+int
+lp_pre_connect (struct lp_worker *worker, int fd, struct sockaddr_in *c_addr)
+{
+ int ret;
+
+ if (fd >= LP_MAX_FD)
+ {
+ LP_CNT (worker, LP_FAILED);
+ err ("fd(%d) >= LP_MAX_FD(%d)\n", fd, LP_MAX_FD);
+ return -1;
+ }
+
+ ret = set_reuseaddr (fd, 1);
+ if (ret)
+ {
+ const int e = errno;
+ LP_ERR (worker, LP_E_REUSEADDR, e);
+ DBG ("set_reuseaddr(%d, 1)=%d:%d\n", fd, ret, e);
+ }
+
+ ret = set_reuseport (fd, 1);
+ if (ret)
+ {
+ const int e = errno;
+ LP_ERR (worker, LP_E_REUSEPORT, errno);
+ DBG ("set_reuseport(%d, 1)=%d:%d\n", fd, ret, e);
+ }
+
+ if (c_addr->sin_addr.s_addr != INADDR_ANY || c_addr->sin_port != 0)
+ {
+ LP_TIME_SET (bind_begin);
+ ret =
+ _bind (fd, (struct sockaddr *) c_addr, sizeof (struct sockaddr_in));
+ LP_TIME_END (worker, LP_W_BIND, bind_begin);
+ if (ret)
+ {
+ int e = errno;
+ if (e == EADDRINUSE)
+ return -1;
+ LP_ERR2 (worker, LP_FAILED, LP_E_BIND, errno);
+ DBG ("->bind(%d, %s)=%d:%d\n", fd, f_inaddr (c_addr), ret, errno);
+ return -1;
+ }
+ }
+
+ if (lp.nodelay)
+ {
+ ret = set_nodelay (fd, 1);
+ if (ret)
+ LP_ERR2 (worker, LP_FAILED, LP_E_NODELAY, errno);
+ }
+
+ if (!lp.block_connecting)
+ {
+ ret = set_nonblock (fd);
+ if (ret)
+ {
+ LP_ERR2 (worker, LP_FAILED, LP_E_NONBLOCK, errno);
+ return -1;
+ }
+#if 1
+ ret = lp_epadd (worker, fd, EPOLLOUT);
+ if (ret)
+ {
+ LP_ERR2 (worker, LP_FAILED, LP_E_EPADD, errno);
+ DBG ("->epoll_ctl(%d, ADD, %d)=%d:%d", worker->epfd, fd, ret,
+ errno);
+ return -1;
+ }
+ return 1;
+#endif
+ }
+
+ return 0;
+}
+
+int
+lp_connected (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ struct timespec now;
+ struct lp_test *test;
+
+ LB_TIME (now);
+ LP_TIME_FOR (worker, LP_W_CONNECTED, sess->time, now);
+ sess->time = now;
+
+ LP_APPEND (worker->sess, fd, sess, sess);
+ sess->state = LP_S_CONNECTED;
+ LP_CNT (worker, LP_CONNECTED);
+
+ test = &lp.test[sess->test];
+ if (test->query)
+ {
+ if (lp.block_connecting && set_nonblock (fd))
+ {
+ LP_ERR (worker, LP_E_NONBLOCK, errno);
+ return -1;
+ }
+ if (sess->epout)
+ {
+ if (lp_epmod (worker, fd, EPOLLIN))
+ {
+ LP_ERR (worker, LP_E_EPMOD, errno);
+ return -1;
+ }
+ sess->epout = 0;
+ }
+ else
+ {
+ if (lp_epadd (worker, fd, EPOLLIN))
+ {
+ LP_ERR (worker, LP_E_EPADD, errno);
+ return -1;
+ }
+ }
+ sess->io_num = test->times;
+
+ if (test->wait)
+ {
+ sess->time.tv_sec += test->wait;
+ lp_add_wait (worker, fd, sess);
+ return 0;
+ }
+
+ return lp_new_query (worker, fd, sess);
+ }
+
+ if (sess->epout)
+ {
+ if (lp_epdel (worker, fd))
+ LP_ERR (worker, LP_E_EPDEL, errno);
+ sess->epout = 0;
+ }
+
+ return 0;
+}
+
+int
+lp_connect (struct lp_worker *worker, int cid, int sid, int test_id)
+{
+ int ret, fd;
+ struct lp_sess *sess;
+ struct timespec connect_begin;
+
+ LP_TIME_SET (begin);
+ fd = _socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd < 0)
+ {
+ LP_ERR2 (worker, LP_FAILED, LP_E_SOCKET, errno);
+ DBG ("->socket(...)=%d:%d\n", fd, errno);
+ return -1;
+ }
+ LP_TIME_END (worker, LP_W_SOCKET, begin);
+
+ ret = lp_pre_connect (worker, fd, worker->client_addr + cid);
+ if (ret < 0)
+ {
+ _close (fd);
+ return -1;
+ }
+
+ LB_TIME (connect_begin);
+ ret =
+ _connect (fd, (struct sockaddr *) (worker->server_addr + sid),
+ sizeof (struct sockaddr_in));
+ LP_TIME_END (worker, LP_W_CONNECT, connect_begin);
+
+ if (ret)
+ {
+ const int e = errno;
+ if (lp.block_connecting || e != EINPROGRESS)
+ {
+ LP_ERR2 (worker, LP_FAILED, LP_E_CONNECT, e);
+ DBG ("->connect(%d, %s)=%d:%d\n", fd,
+ f_inaddr (worker->server_addr + sid), ret, e);
+ _close (fd);
+ return -1;
+ }
+ }
+
+ LP_TIME_END (worker, LP_W_CREATE, begin);
+ LP_CNT (worker, LP_CONNECT);
+
+ sess = lp_init_sess (worker, fd);
+ sess->test = test_id;
+ sess->time = connect_begin;
+ if (!lp.block_connecting)
+ sess->epout = 1;
+
+ if (ret)
+ {
+ /* nonblock connect inprogress */
+ lp_add_conn (worker, fd, sess);
+ return 1;
+ }
+
+ ret = lp_connected (worker, fd, sess);
+ if (ret < 0)
+ lp_del_sess (worker, fd);
+
+ return ret;
+}
+
+inline static int
+lp_handle_client (struct lp_worker *worker, int fd, uint32_t events)
+{
+ struct lp_sess *sess = LP_SESS (fd);
+
+ if (sess->state == LP_S_UNUSED)
+ {
+ LP_CNT (worker, LP_E_EPUNUSED);
+ return 0;
+ }
+
+ if (events & EPOLLRDHUP)
+ {
+ LP_CNT (worker, LP_E_EPHUP);
+ return -1;
+ }
+
+ if (events & EPOLLERR)
+ {
+ LP_CNT (worker, LP_E_EPERR);
+ DBG ("epoll event error, fd:%d event:0x%x\n", fd, events);
+ return -1;
+ }
+
+ if (events & EPOLLIN)
+ {
+ if (sess->state == LP_S_REPLY)
+ return lp_recv_reply (worker, fd, sess);
+ LP_CNT (worker, LP_E_EPERR);
+ return 0;
+ }
+
+ if (events & EPOLLOUT)
+ {
+ if (sess->state == LP_S_CONNECTING)
+ {
+ lp_out_conn (worker, fd, sess);
+ return lp_connected (worker, fd, sess);
+ }
+ if (sess->state == LP_S_QUERY)
+ return lp_more_query (worker, fd, sess);
+ LP_CNT (worker, LP_E_EPERR);
+ return 0;
+ }
+
+ LP_CNT (worker, LP_E_EPEVENT);
+ return -1;
+}
+
+inline static void
+lp_init_mode (const struct lp_worker *worker, int *cid, int *sid)
+{
+ if (worker->link_mode == LP_RAND)
+ {
+ *cid = LB_RAND (worker->client_num);
+ *sid = LB_RAND (worker->server_num);
+ }
+ else
+ {
+ *cid = 0;
+ *sid = 0;
+ }
+}
+
+inline static void
+lp_next_mode (const struct lp_worker *worker, int *cid, int *sid)
+{
+ if (worker->link_mode == LP_RAND)
+ {
+ *cid = LB_RAND (worker->client_num);
+ *sid = LB_RAND (worker->server_num);
+ }
+ else if (worker->link_mode == LP_SYNC)
+ {
+ if (++*sid >= worker->server_num)
+ *sid = 0;
+ if (++*cid >= worker->client_num)
+ *cid = 0;
+ }
+ else if (worker->link_mode == LP_CPS)
+ {
+ if (++*cid >= worker->client_num)
+ {
+ *cid = 0;
+ if (++*sid >= worker->server_num)
+ *sid = 0;
+ }
+ }
+ else if (worker->link_mode == LP_SPC)
+ {
+ if (++*sid >= worker->server_num)
+ {
+ *sid = 0;
+ if (++*cid >= worker->client_num)
+ *cid = 0;
+ }
+ }
+ else
+ {
+ err ("Error mode value:%d\n", worker->link_mode);
+ }
+}
+
+void
+lp_client (struct lp_worker *worker)
+{
+ int ret, num = 0, cid, sid, test_id = -1;
+ struct epoll_event *event;
+ struct lp_test *test = &lp.test[0];
+ struct lb_run *up = worker->up_run;
+ struct lb_run *down = worker->down_run;
+ const int epfd = worker->epfd;
+
+ lp_init_mode (worker, &cid, &sid);
+
+ while (lp.run_state == LP_EXEC)
+ {
+ int i;
+ struct timespec now;
+
+ if (test_id != lp.test_id)
+ {
+ DBG ("worker %d change test_id %d\n", worker->index, lp.test_id);
+ test = &lp.test[test_id = lp.test_id];
+
+ if (test->up)
+ run_init (up, (test->up + lp.worker_num - 1) / lp.worker_num,
+ LP_UP_SLOT, LP_UP_NSEC);
+ if (test->down)
+ run_init (down, (test->down + lp.worker_num - 1) / lp.worker_num,
+ LP_DOWN_SLOT, LP_DOWN_NSEC);
+ }
+
+ LB_TIME (now);
+
+ /* up process */
+ if (test->up)
+ {
+ if (run_test (up, &now) > 0)
+ {
+ ret = lp_connect (worker, cid, sid, test_id);
+ if (ret >= 0)
+ run_add (up, 1);
+ lp_next_mode (worker, &cid, &sid);
+ LB_TIME (now);
+ }
+ }
+
+ /* down process */
+ if (test->down && worker->sess.num)
+ {
+ if (run_test (down, &now) > 0)
+ {
+ lp_del_sess (worker, worker->sess.first);
+ run_add (down, 1);
+ LB_TIME (now);
+ }
+ }
+
+ /* query */
+ for (i = 0; i <= test_id; ++i)
+ {
+ int fd;
+ struct lp_sess *sess;
+
+ if (worker->rest[i].num)
+ {
+ fd = worker->rest[i].first;
+ sess = LP_SESS (fd);
+ if (LB_CMP (now, sess->time) >= 0)
+ {
+ LP_ASSERT (sess->state == LP_S_REST);
+ LP_ASSERT (sess->test == i);
+ lp_out_rest (worker, fd, sess);
+ if (lp_new_query (worker, fd, sess) < 0)
+ {
+ lp_del_sess (worker, fd);
+ if (test->down)
+ run_add (down, 1);
+ }
+ LB_TIME (now);
+ }
+ }
+ if (worker->wait[i].num)
+ {
+ fd = worker->wait[i].first;
+ sess = LP_SESS (fd);
+ if (LB_CMP (now, sess->time) >= 0)
+ {
+ LP_ASSERT (sess->state == LP_S_WAIT);
+ LP_ASSERT (sess->test == i);
+ lp_out_wait (worker, fd, sess);
+ if (lp_new_query (worker, fd, sess) < 0)
+ {
+ lp_del_sess (worker, fd);
+ if (test->down)
+ run_add (down, 1);
+ }
+ LB_TIME (now);
+ }
+ }
+ }
+
+ /* check connect timeout */
+ if (worker->conn.first >= 0)
+ {
+ }
+
+ /* epoll event process */
+ if (num > 0)
+ {
+ const uint64_t type = LP_EV_TYPE (event->data.u64);
+ const int fd = LP_EV_FD (event->data.u64);
+
+ if (type == LP_SESSION_TYPE)
+ {
+ if (lp_handle_client (worker, fd, event->events) < 0)
+ {
+ struct lp_sess *sess = LP_SESS (fd);
+ if (sess->state & LP_S_CONNECTED)
+ {
+ lp_del_sess (worker, fd);
+ if (test->down)
+ run_add (down, 1);
+ }
+ else if (sess->state == LP_S_CONNECTING)
+ {
+ lp_del_conn (worker, fd, sess);
+ }
+ else
+ {
+ }
+ }
+ }
+ else if (type == LP_CONTROL_TYPE)
+ {
+ break;
+ }
+ else
+ {
+ err ("epoll event error flag:%lx, fd:%d event:%x}\n",
+ LP_EV_FLAG (event->data.u64), fd, event->events);
+ }
+ num--;
+ event++;
+ }
+ else
+ {
+ num = _epoll_wait (epfd, worker->ev_buf, LP_EVENT_NUM, 0);
+ if (num > 0)
+ {
+ event = worker->ev_buf;
+ }
+ else if (num < 0)
+ {
+ int e = errno;
+ if (e != EINTR && e != ETIMEDOUT)
+ LP_ERR (worker, LP_E_EPWAIT, e);
+ }
+ }
+ }
+}
diff --git a/thirdparty/apps/testapp/lp/lps.c b/thirdparty/apps/testapp/lp/lps.c
new file mode 100644
index 0000000..8462c21
--- /dev/null
+++ b/thirdparty/apps/testapp/lp/lps.c
@@ -0,0 +1,372 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+#include "lp.h"
+
+int
+lp_send_reply (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ int ret;
+ char *buf = worker->io_buf;
+
+ while (sess->reply > 0)
+ {
+ const int LEN =
+ sess->reply < LP_IOBUF_SIZE ? sess->reply : LP_IOBUF_SIZE;
+
+ ret = _send (fd, buf, LEN, 0);
+ if (ret > 0)
+ {
+ LP_ADD (worker, LP_REPLY_BYTE, ret);
+ sess->reply -= ret;
+ }
+ else if (ret < 0)
+ {
+ int e = errno;
+ if (e == EWOULDBLOCK || e == EAGAIN)
+ return lp_set_epout (worker, fd, sess);
+ if (e == EINTR)
+ continue;
+ LP_ERR (worker, LP_E_SEND, e);
+ return -1;
+ }
+ else
+ {
+ LP_CNT (worker, LP_E_IOSEND0);
+ }
+ }
+
+ LP_CNT (worker, LP_REPLY_COMP);
+
+ if (sess->epout)
+ {
+ if (lp_epmod (worker, fd, EPOLLIN))
+ {
+ LP_ERR (worker, LP_E_EPMOD, errno);
+ return -1;
+ }
+ sess->epout = 0;
+ }
+
+ return 0;
+}
+
+int
+lp_just_query (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ char *buf = worker->io_buf;
+ struct lp_io *io = (struct lp_io *) buf;
+ int len = 0;
+
+ while (1)
+ {
+ int ret;
+
+ ret = _recv (fd, buf + len, LP_IOBUF_SIZE - len, 0);
+
+ if (ret > 0)
+ {
+ LP_ADD (worker, LP_QUERY_BYTE, ret);
+ len += ret;
+ if (len >= sizeof (struct lp_io))
+ break;
+ LP_CNT (worker, LP_E_IOMORE);
+ }
+ else if (ret < 0)
+ {
+ int e = errno;
+ if (e == EWOULDBLOCK || e == EAGAIN)
+ {
+ LP_CNT (worker, LP_E_IOMORE);
+ continue;
+ }
+ if (e == EINTR)
+ continue;
+ LP_ERR (worker, LP_E_RECV, e);
+ return -1;
+ }
+ else
+ {
+ //LP_CNT(worker, LP_E_IOSHUT);
+ return -1;
+ }
+ }
+
+ sess->query = htonl (io->query);
+ sess->reply = htonl (io->reply);
+
+ if (sess->query < LP_QUERY_MIN || sess->reply < 0)
+ {
+ LP_CNT (worker, LP_E_IOSIZE);
+ return -1;
+ }
+
+ sess->query -= len;
+ return 0;
+}
+
+int
+lp_recv_query (struct lp_worker *worker, int fd, struct lp_sess *sess)
+{
+ int ret;
+ char *buf = worker->io_buf;
+
+ if (sess->query == 0)
+ {
+ ret = lp_just_query (worker, fd, sess);
+ if (ret)
+ return ret;
+ }
+
+ while (1)
+ {
+ ret = _recv (fd, buf, LP_IOBUF_SIZE, 0);
+ if (ret > 0)
+ {
+ LP_ADD (worker, LP_QUERY_BYTE, ret);
+ sess->query -= ret;
+ }
+ else if (ret < 0)
+ {
+ int e = errno;
+ if (e == EWOULDBLOCK || e == EAGAIN)
+ {
+ if (sess->query > 0)
+ return 1;
+ break;
+ }
+ if (e == EINTR)
+ continue;
+ LP_ERR (worker, LP_E_RECV, e);
+ return -1;
+ }
+ else
+ {
+ if (sess->query || sess->reply)
+ {
+ //LP_CNT(worker, LP_E_IOSHUT);
+ }
+ else
+ LP_CNT (worker, LP_QUERY_COMP);
+ return -1;
+ }
+ }
+
+ LP_CNT (worker, LP_QUERY_COMP);
+
+ if (sess->query < 0)
+ {
+ LP_CNT (worker, LP_E_IOEXCEED);
+ sess->query = 0;
+ }
+
+ if (sess->reply)
+ return lp_send_reply (worker, fd, sess);
+
+ return 0;
+}
+
+inline static int
+lp_service (struct lp_worker *worker, int fd, uint32_t events)
+{
+ struct lp_sess *sess = LP_SESS (fd);
+
+ if (sess->state == LP_S_UNUSED)
+ {
+ LP_CNT (worker, LP_E_EPUNUSED);
+ return 0;
+ }
+
+ if (events & EPOLLRDHUP)
+ return -1;
+
+ if (events & EPOLLERR)
+ {
+ LP_CNT (worker, LP_E_EPERR);
+ DBG ("epoll event error, fd:%d event:0x%x\n", fd, events);
+ return -1;
+ }
+
+ if ((events & (EPOLLIN | EPOLLOUT)) == (EPOLLIN | EPOLLOUT))
+ {
+ LP_CNT (worker, LP_E_EPINOUT);
+ return -1;
+ }
+
+ if (events & EPOLLIN)
+ return lp_recv_query (worker, fd, sess);
+
+ if (events & EPOLLOUT)
+ return lp_send_reply (worker, fd, sess);
+
+ LP_CNT (worker, LP_E_EPEVENT);
+ return -1;
+}
+
+void
+lp_accept (struct lp_worker *worker, int listen_fd)
+{
+ while (lp.run_state == LP_EXEC)
+ {
+ int fd, ret;
+ struct lp_sess *sess;
+
+ LP_TIME_SET (begin);
+
+ fd = _accept4 (listen_fd, NULL, NULL, SOCK_NONBLOCK);
+ if (fd < 0)
+ {
+ int e = errno;
+ if (e == EAGAIN || e == EWOULDBLOCK)
+ return;
+ if (e == EINTR)
+ continue;
+ LP_ERR (worker, LP_E_ACCEPT, e);
+ DBG ("->accept4(%d)=%d:%d\n", listen_fd, fd, e);
+ return;
+ }
+ else
+ {
+ LP_TIME_END (worker, LP_W_ACCEPT, begin);
+ }
+
+ if (fd >= LP_MAX_FD)
+ {
+ LP_CNT (worker, LP_FAILED);
+ _close (fd);
+ err ("accept fd(%d) >= LP_MAX_FD(%d)\n", fd, LP_MAX_FD);
+ continue;
+ }
+
+ if (lp.nodelay)
+ {
+ ret = set_nodelay (fd, 1);
+ if (ret)
+ LP_ERR (worker, LP_E_NODELAY, errno);
+ }
+
+ ret = lp_epadd (worker, fd, EPOLLIN);
+ if (ret)
+ {
+ int e = errno;
+ LP_ERR2 (worker, LP_FAILED, LP_E_EPADD, e);
+ _close (fd);
+ DBG ("epoll_ctl(%d, %d)=%d:%d\n\n", worker->epfd, fd, ret, e);
+ continue;
+ }
+
+ sess = lp_init_sess (worker, fd);
+ LP_APPEND (worker->sess, fd, sess, sess);
+ sess->state = LP_S_CONNECTED;
+ LP_CNT (worker, LP_CONNECTED);
+
+ LP_TIME_END (worker, LP_W_CREATE, begin);
+ }
+}
+
+void
+lp_server (struct lp_worker *worker)
+{
+ int num = 0;
+ struct epoll_event *event;
+ const int epfd = worker->epfd;
+
+ while (lp.run_state == LP_EXEC)
+ {
+ if (num > 0)
+ {
+ const uint64_t type = LP_EV_TYPE (event->data.u64);
+ const int fd = LP_EV_FD (event->data.u64);
+
+ if (type == LP_LISTEN_TYPE)
+ {
+ lp_accept (worker, fd);
+ }
+ else if (type == LP_SESSION_TYPE)
+ {
+ if (lp_service (worker, fd, event->events) < 0)
+ lp_del_sess (worker, fd);
+ }
+ else if (type == LP_CONTROL_TYPE)
+ {
+ break;
+ }
+ else
+ {
+ err ("epoll event error flag:%lx, fd:%d event:%x}\n",
+ LP_EV_FLAG (event->data.u64), fd, event->events);
+ }
+ num--;
+ event++;
+ }
+ else
+ {
+ num = _epoll_wait (epfd, worker->ev_buf, LP_EVENT_NUM, -1);
+ if (num > 0)
+ {
+ event = worker->ev_buf;
+ }
+ else if (num < 0)
+ {
+ int e = errno;
+ if (e != EINTR && e != ETIMEDOUT)
+ LP_ERR (worker, LP_E_EPWAIT, e);
+ }
+ }
+ }
+}
+
+int
+lp_listen (struct lp_worker *worker, int index)
+{
+ int fd, ret;
+ struct epoll_event event;
+
+ fd = _socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (fd < 0, -1, "socket()=%d:%d\n", fd, errno);
+
+ if (fd >= LP_MAX_FD)
+ {
+ err ("socket()=%d >= LP_MAX_FD(%d)\n", fd, LP_MAX_FD);
+ (void) _close (fd);
+ return -1;
+ }
+
+ LP_APPEND (worker->server, fd, lp_init_sess (worker, fd), sess);
+
+ ret =
+ _bind (fd, (struct sockaddr *) &worker->server_addr[index],
+ sizeof (worker->server_addr[index]));
+ ERR_RETURN (ret, -1, "bind(%d, %s)=%d:%d\n", fd,
+ f_inaddr (&worker->server_addr[index]), ret, errno);
+
+ ret = set_nonblock (fd);
+ ERR_RETURN (ret, -1, "set_nonblock(%d)=%d:%d\n", fd, ret, errno);
+
+ ret = _listen (fd, SOMAXCONN);
+ ERR_RETURN (ret, -1, "listen(%d)=%d:%d\n", fd, ret, errno);
+
+ event.events = EPOLLIN | EPOLLET;
+ event.data.u64 = LP_EV_MK (LP_LISTEN_TYPE, fd);
+ ret = _epoll_ctl (worker->epfd, EPOLL_CTL_ADD, fd, &event);
+ ERR_RETURN (ret, -1, "epoll_ctl(%d, %d)=%d:%d\n", worker->epfd, fd, ret,
+ errno);
+
+ DBG ("worker %d server %d fd %d listen on %s\n", worker->index, index, fd,
+ f_inaddr (&worker->server_addr[index]));
+ return 0;
+}
diff --git a/thirdparty/apps/testapp/te/te.c b/thirdparty/apps/testapp/te/te.c
new file mode 100644
index 0000000..4f17d29
--- /dev/null
+++ b/thirdparty/apps/testapp/te/te.c
@@ -0,0 +1,782 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "lb.h"
+
+#define TEST_ASSERT(cond) do { if(!(cond)) err("%s\n", #cond); } while(0)
+
+int
+test_v6_udp (int argc, const char *argv[])
+{
+ int fd, ret;
+ struct sockaddr_in6 addr = { 0 };
+ struct sockaddr_in6 out = { 0 };
+ socklen_t len = sizeof (out);
+ const char *ip = argv[1];
+
+ fd = _socket (AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ ERR_RETURN (fd < 0, -1, "socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)=%d:%d\n",
+ fd, errno);
+
+ ret = inet_pton (AF_INET6, ip, &addr.sin6_addr);
+ ERR_GOTO (ret != 1, CLEAN, "inet_pton(AF_INET6, %s)=%d:%d\n", ip, ret,
+ errno);
+
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons (54321);
+ ret = _bind (fd, (struct sockaddr *) &addr, sizeof (addr));
+ ERR_GOTO (ret < 0, CLEAN, "bind(%d, %s, %ld)=%d:%d\n", fd,
+ f_in6addr (&addr), sizeof (addr), ret, errno);
+
+ ret = _getsockname (fd, (struct sockaddr *) &out, &len);
+ ERR_GOTO (ret < 0, CLEAN, "getsockname(%d, %s, %d)=%d:%d\n", fd,
+ f_in6addr (&out), len, ret, errno);
+ TEST_ASSERT (out.sin6_family == AF_INET6);
+ TEST_ASSERT (out.sin6_addr.s6_addr32[0] == addr.sin6_addr.s6_addr32[0]);
+ TEST_ASSERT (out.sin6_addr.s6_addr32[1] == addr.sin6_addr.s6_addr32[1]);
+ TEST_ASSERT (out.sin6_addr.s6_addr32[2] == addr.sin6_addr.s6_addr32[2]);
+ TEST_ASSERT (out.sin6_addr.s6_addr32[3] == addr.sin6_addr.s6_addr32[3]);
+ TEST_ASSERT (out.sin6_port == addr.sin6_port);
+
+ ret = _close (fd);
+ if (ret)
+ err ("close(%d)=%d:%d\n", fd, ret, errno);
+
+ return ret;
+
+CLEAN:
+ (void) _close (fd);
+ return -1;
+}
+
+int
+test_v4_udp (int argc, const char *argv[])
+{
+ int fd, ret;
+ struct sockaddr_in addr = { 0 };
+ struct sockaddr_in out = { 0 };
+ socklen_t len = sizeof (out);
+ const char *ip = argv[1];
+
+ fd = _socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ ERR_RETURN (fd < 0, fd, "socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)=%d:%d\n",
+ fd, errno);
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr (ip);
+ addr.sin_port = htons (12345);
+ ret = _bind (fd, (struct sockaddr *) &addr, sizeof (addr));
+ ERR_GOTO (ret < 0, CLEAN, "bind(%d, %s, %ld)=%d:%d\n", fd, f_inaddr (&addr),
+ sizeof (addr), ret, errno);
+
+ ret = _getsockname (fd, (struct sockaddr *) &out, &len);
+ ERR_GOTO (ret < 0, CLEAN, "getsockname(%d, %s, %d)=%d:%d\n", fd,
+ f_inaddr (&out), len, ret, errno);
+ TEST_ASSERT (out.sin_family == AF_INET);
+ TEST_ASSERT (out.sin_addr.s_addr == addr.sin_addr.s_addr);
+ TEST_ASSERT (out.sin_port == addr.sin_port);
+
+ ret = _close (fd);
+ if (ret)
+ err ("close(%d)=%d:%d\n", fd, ret, errno);
+
+ return ret;
+
+CLEAN:
+ (void) _close (fd);
+ return -1;
+}
+
+int
+test_v4_tcp (int argc, const char *argv[])
+{
+ int sfd, cfd, afd, ret;
+ struct sockaddr_in saddr = { 0 }, caddr =
+ {
+ 0}, aaddr =
+ {
+ 0}, out =
+ {
+ 0};
+ socklen_t len;
+ const char *ip = argv[1];
+
+ sfd = _socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (sfd < 0, sfd,
+ "sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)=%d:%d\n", sfd,
+ errno);
+
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = inet_addr (ip);
+ saddr.sin_port = htons (23456);
+ ret = _bind (sfd, (struct sockaddr *) &saddr, sizeof (saddr));
+ ERR_GOTO (ret < 0, CLEAN_S, "bind(%d, %s, %ld)=%d:%d\n", sfd,
+ f_inaddr (&saddr), sizeof (saddr), ret, errno);
+
+ ret = _listen (sfd, 100);
+ ERR_GOTO (ret < 0, CLEAN_S, "listen(%d, 100)=%d:%d\n", sfd, ret, errno);
+
+ cfd = _socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ERR_GOTO (cfd < 0, CLEAN_S,
+ "cfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)=%d:%d\n", cfd,
+ errno);
+
+ ret = _connect (cfd, (struct sockaddr *) &saddr, sizeof (saddr));
+ ERR_GOTO (ret < 0, CLEAN_C, "connect(%d, %s, %ld)=%d:%d\n", cfd,
+ f_inaddr (&saddr), sizeof (saddr), ret, errno);
+
+ len = sizeof (caddr);
+ ret = _getsockname (cfd, (struct sockaddr *) &caddr, &len);
+ TEST_ASSERT (ret == 0);
+ TEST_ASSERT (len == sizeof (caddr));
+
+ len = sizeof (aaddr);
+ afd = _accept (sfd, (struct sockaddr *) &aaddr, &len);
+ ERR_GOTO (ret < 0, CLEAN_C, "accept(%d, %s, %d)=%d:%d\n", sfd,
+ f_inaddr (&aaddr), len, ret, errno);
+ TEST_ASSERT (len == sizeof (caddr));
+
+ len = sizeof (out);
+ ret = _getsockname (afd, (struct sockaddr *) &out, &len);
+ TEST_ASSERT (ret == 0);
+ TEST_ASSERT (len == sizeof (out));
+ TEST_ASSERT (out.sin_family == AF_INET);
+ TEST_ASSERT (out.sin_addr.s_addr == saddr.sin_addr.s_addr);
+ TEST_ASSERT (out.sin_port == saddr.sin_port);
+
+ len = sizeof (out);
+ ret = _getpeername (afd, (struct sockaddr *) &out, &len);
+ TEST_ASSERT (ret == 0);
+ TEST_ASSERT (len == sizeof (out));
+ TEST_ASSERT (out.sin_family == AF_INET);
+ TEST_ASSERT (out.sin_addr.s_addr == caddr.sin_addr.s_addr);
+ TEST_ASSERT (out.sin_port == caddr.sin_port);
+
+ ret = _close (afd);
+ TEST_ASSERT (ret == 0);
+
+ ret = _close (cfd);
+ TEST_ASSERT (ret == 0);
+
+ ret = _close (sfd);
+ TEST_ASSERT (ret == 0);
+
+ return ret;
+
+CLEAN:
+ (void) _close (afd);
+CLEAN_C:
+ (void) _close (cfd);
+CLEAN_S:
+ (void) _close (sfd);
+ return -1;
+}
+
+int
+v6_udp_close_select (int argc, const char *argv[])
+{
+ int fd, ret;
+ struct sockaddr_in6 addr = { 0 };
+ struct sockaddr_in6 out = { 0 };
+ socklen_t len = sizeof (out);
+ const char *ip = argv[1];
+ const char *port = argv[2];
+
+ fd = _socket (AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ ERR_RETURN (fd < 0, -1, "socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)=%d:%d\n",
+ fd, errno);
+
+ ret = inet_pton (AF_INET6, ip, &addr.sin6_addr);
+ ERR_GOTO (ret != 1, CLEAN, "inet_pton(AF_INET6, %s)=%d:%d\n", ip, ret,
+ errno);
+
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons (atoi (port));
+ ret = _bind (fd, (struct sockaddr *) &addr, sizeof (addr));
+ ERR_GOTO (ret < 0, CLEAN, "bind(%d, %s, %ld)=%d:%d\n", fd,
+ f_in6addr (&addr), sizeof (addr), ret, errno);
+
+ ret = _close (fd);
+ if (ret)
+ err ("close(%d)=%d:%d\n", fd, ret, errno);
+
+ {
+ fd_set rfds, wfds, efds;
+ int nfds = fd + 1;
+ FD_ZERO (&rfds);
+ FD_SET (fd, &rfds);
+ FD_ZERO (&wfds);
+ FD_SET (fd, &wfds);
+ FD_ZERO (&efds);
+ FD_SET (fd, &efds);
+ ret = select (nfds, &rfds, &wfds, &efds, NULL);
+ int err = errno;
+ TEST_ASSERT (ret == -1);
+ TEST_ASSERT (err == EBADF);
+ }
+
+ return 0;
+
+CLEAN:
+ (void) _close (fd);
+ return -1;
+}
+
+int
+v6_tcp_server_listen (int argc, const char *argv[])
+{
+ return -1;
+}
+
+int
+v6_tcp_server_shutdown_rd (int argc, const char *argv[])
+{
+ int sfd = -1, afd = -1, ret;
+ struct sockaddr_in6 saddr = { 0 }, aaddr =
+ {
+ 0};
+ socklen_t len;
+ const char *ip = argv[1];
+ const char *port = argv[2];
+
+ sfd = _socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (sfd < 0, sfd,
+ "socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)=%d:%d\n", sfd,
+ errno);
+
+ saddr.sin6_family = AF_INET6;
+ ret = inet_pton (AF_INET6, ip, &saddr.sin6_addr);
+ ERR_GOTO (ret != 1, CLEAN_S,
+ "inet_pton(AF_INET6, ip=\"%s\", &saddr.sin6_addr)=%d:%d\n", ip,
+ ret, errno);
+ saddr.sin6_port = htons (atoi (port));
+
+ ret = _bind (sfd, (struct sockaddr *) &saddr, sizeof (saddr));
+ ERR_GOTO (ret < 0, CLEAN_S, "bind(%d, %s, %ld)=%d:%d\n", sfd,
+ f_in6addr (&saddr), sizeof (saddr), ret, errno);
+
+ ret = _listen (sfd, 100);
+ ERR_GOTO (ret < 0, CLEAN_S, "listen(%d, 100)=%d:%d\n", sfd, ret, errno);
+
+ len = sizeof (aaddr);
+ afd = _accept (sfd, (struct sockaddr *) &aaddr, &len);
+ ERR_GOTO (ret < 0, CLEAN_S, "accept(%d, %s, %d)=%d:%d\n", sfd,
+ f_in6addr (&aaddr), len, ret, errno);
+
+ out ("accept(sfd=%d, addr=%s, len=%d)=%d\n", sfd, f_in6addr (&aaddr), len,
+ afd);
+
+ ret = _shutdown (afd, SHUT_RD);
+ ERR_GOTO (ret != 0, CLEAN, "shutdown(afd=%d, SHUT_RD)=%d:%d\n", afd, ret,
+ errno);
+
+ out ("shutdown(afd=%d, SHUT_RD) ok --> sleep(10)\n", afd);
+ sleep (10);
+
+ out ("closing\n");
+
+ ret = _close (afd);
+ TEST_ASSERT (ret == 0);
+
+ ret = _close (sfd);
+ TEST_ASSERT (ret == 0);
+
+ return ret;
+
+CLEAN:
+ (void) _close (afd);
+CLEAN_S:
+ (void) _close (sfd);
+ return -1;
+}
+
+int
+v6_tcp_server_shutdown_wr (int argc, const char *argv[])
+{
+ int sfd = -1, afd = -1, ret;
+ struct sockaddr_in6 saddr = { 0 }, aaddr =
+ {
+ 0};
+ socklen_t len;
+ const char *ip = argv[1];
+ const char *port = argv[2];
+
+ sfd = _socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (sfd < 0, sfd,
+ "socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)=%d:%d\n", sfd,
+ errno);
+
+ saddr.sin6_family = AF_INET6;
+ ret = inet_pton (AF_INET6, ip, &saddr.sin6_addr);
+ ERR_GOTO (ret != 1, CLEAN_S,
+ "inet_pton(AF_INET6, ip=\"%s\", &saddr.sin6_addr)=%d:%d\n", ip,
+ ret, errno);
+ saddr.sin6_port = htons (atoi (port));
+
+ ret = _bind (sfd, (struct sockaddr *) &saddr, sizeof (saddr));
+ ERR_GOTO (ret < 0, CLEAN_S, "bind(%d, %s, %ld)=%d:%d\n", sfd,
+ f_in6addr (&saddr), sizeof (saddr), ret, errno);
+
+ ret = _listen (sfd, 100);
+ ERR_GOTO (ret < 0, CLEAN_S, "listen(%d, 100)=%d:%d\n", sfd, ret, errno);
+
+ len = sizeof (aaddr);
+ afd = _accept (sfd, (struct sockaddr *) &aaddr, &len);
+ ERR_GOTO (ret < 0, CLEAN_S, "accept(%d, %s, %d)=%d:%d\n", sfd,
+ f_in6addr (&aaddr), len, ret, errno);
+
+ out ("accept(sfd=%d, addr=%s, len=%d)=%d\n", sfd, f_in6addr (&aaddr), len,
+ afd);
+
+ ret = _shutdown (afd, SHUT_WR);
+ ERR_GOTO (ret != 0, CLEAN, "shutdown(afd=%d, SHUT_WR)=%d:%d\n", afd, ret,
+ errno);
+
+ out ("shutdown(afd=%d, SHUT_WR) ok --> sleep(10)\n", afd);
+ sleep (10);
+
+ out ("closing\n");
+
+ ret = _close (afd);
+ TEST_ASSERT (ret == 0);
+
+ ret = _close (sfd);
+ TEST_ASSERT (ret == 0);
+
+ return ret;
+
+CLEAN:
+ (void) _close (afd);
+CLEAN_S:
+ (void) _close (sfd);
+ return -1;
+}
+
+int
+v6_tcp_server_shutdown_rdwr (int argc, const char *argv[])
+{
+ int sfd = -1, afd = -1, ret;
+ struct sockaddr_in6 saddr = { 0 }, aaddr =
+ {
+ 0};
+ socklen_t len;
+ const char *ip = argv[1];
+ const char *port = argv[2];
+
+ sfd = _socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (sfd < 0, sfd,
+ "socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)=%d:%d\n", sfd,
+ errno);
+
+ saddr.sin6_family = AF_INET6;
+ ret = inet_pton (AF_INET6, ip, &saddr.sin6_addr);
+ ERR_GOTO (ret != 1, CLEAN_S,
+ "inet_pton(AF_INET6, ip=\"%s\", &saddr.sin6_addr)=%d:%d\n", ip,
+ ret, errno);
+ saddr.sin6_port = htons (atoi (port));
+
+ ret = _bind (sfd, (struct sockaddr *) &saddr, sizeof (saddr));
+ ERR_GOTO (ret < 0, CLEAN_S, "bind(%d, %s, %ld)=%d:%d\n", sfd,
+ f_in6addr (&saddr), sizeof (saddr), ret, errno);
+
+ ret = _listen (sfd, 100);
+ ERR_GOTO (ret < 0, CLEAN_S, "listen(%d, 100)=%d:%d\n", sfd, ret, errno);
+
+ len = sizeof (aaddr);
+ afd = _accept (sfd, (struct sockaddr *) &aaddr, &len);
+ ERR_GOTO (ret < 0, CLEAN_S, "accept(%d, %s, %d)=%d:%d\n", sfd,
+ f_in6addr (&aaddr), len, ret, errno);
+
+ out ("accept(sfd=%d, addr=%s, len=%d)=%d\n", sfd, f_in6addr (&aaddr), len,
+ afd);
+
+ ret = _shutdown (afd, SHUT_RDWR);
+ ERR_GOTO (ret != 0, CLEAN, "shutdown(afd=%d, SHUT_RDWR)=%d:%d\n", afd, ret,
+ errno);
+
+ out ("shutdown(afd=%d, SHUT_WR) ok --> sleep(10)\n", afd);
+ sleep (10);
+
+ out ("closing\n");
+
+ ret = _close (afd);
+ TEST_ASSERT (ret == 0);
+
+ ret = _close (sfd);
+ TEST_ASSERT (ret == 0);
+
+ return ret;
+
+CLEAN:
+ (void) _close (afd);
+CLEAN_S:
+ (void) _close (sfd);
+ return -1;
+}
+
+int
+v6_tcp_client_s (int argc, const char *argv[])
+{
+ int cfd = -1, ret;
+ struct sockaddr_in6 saddr = { 0 };
+ socklen_t len;
+ char buf[10] = { 'X', 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ const char *ip = argv[1];
+ const char *port = argv[2];
+
+ cfd = _socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (cfd < 0, cfd,
+ "socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)=%d:%d\n", cfd,
+ errno);
+
+ saddr.sin6_family = AF_INET6;
+ ret = inet_pton (AF_INET6, ip, &saddr.sin6_addr);
+ ERR_GOTO (ret != 1, CLEAN,
+ "inet_pton(AF_INET6, ip=\"%s\", &saddr.sin6_addr)=%d:%d\n", ip,
+ ret, errno);
+ saddr.sin6_port = htons (atoi (port));
+
+ ret = _connect (cfd, (struct sockaddr *) &saddr, sizeof (saddr));
+ ERR_GOTO (ret < 0, CLEAN, "connect(%d, %s, %d)=%d:%d\n", cfd,
+ f_in6addr (&saddr), len, ret, errno);
+ out ("connect ok --> sleep(5)\n");
+ sleep (5);
+
+ ret = _send (cfd, buf, 10, 0);
+ out ("send()=%d:%d --> sleep(5)\n", ret, errno);
+ sleep (5);
+
+ ret = _close (cfd);
+ TEST_ASSERT (ret == 0);
+
+ return ret;
+
+CLEAN:
+ (void) _close (cfd);
+ return -1;
+}
+
+int
+v4_tcp_server_shutdown_rd (int argc, const char *argv[])
+{
+ int sfd = -1, afd = -1, ret;
+ struct sockaddr_in saddr = { 0 }, aaddr =
+ {
+ 0};
+ socklen_t len;
+ const char *ip = argv[1];
+ const char *port = argv[2];
+
+ sfd = _socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (sfd < 0, sfd,
+ "socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)=%d:%d\n", sfd,
+ errno);
+
+ saddr.sin_family = AF_INET;
+ ret = inet_pton (AF_INET, ip, &saddr.sin_addr);
+ ERR_GOTO (ret != 1, CLEAN_S,
+ "inet_pton(AF_INET, ip=\"%s\", &saddr.sin_addr)=%d:%d\n", ip, ret,
+ errno);
+ saddr.sin_port = htons (atoi (port));
+
+ ret = _bind (sfd, (struct sockaddr *) &saddr, sizeof (saddr));
+ ERR_GOTO (ret < 0, CLEAN_S, "bind(%d, %s, %ld)=%d:%d\n", sfd,
+ f_inaddr (&saddr), sizeof (saddr), ret, errno);
+
+ ret = _listen (sfd, 100);
+ ERR_GOTO (ret < 0, CLEAN_S, "listen(%d, 100)=%d:%d\n", sfd, ret, errno);
+
+ len = sizeof (aaddr);
+ afd = _accept (sfd, (struct sockaddr *) &aaddr, &len);
+ ERR_GOTO (ret < 0, CLEAN_S, "accept(%d, %s, %d)=%d:%d\n", sfd,
+ f_inaddr (&aaddr), len, ret, errno);
+
+ out ("accept(sfd=%d, addr=%s, len=%d)=%d\n", sfd, f_inaddr (&aaddr), len,
+ afd);
+ sleep (2);
+
+ ret = _shutdown (afd, SHUT_RD);
+ ERR_GOTO (ret != 0, CLEAN, "shutdown(afd=%d, SHUT_RD)=%d:%d\n", afd, ret,
+ errno);
+
+ out ("shutdown(afd=%d, SHUT_RD) ok --> sleep(10)\n", afd);
+ sleep (10);
+
+ out ("closing\n");
+
+ ret = _close (afd);
+ TEST_ASSERT (ret == 0);
+
+ ret = _close (sfd);
+ TEST_ASSERT (ret == 0);
+
+ return ret;
+
+CLEAN:
+ (void) _close (afd);
+CLEAN_S:
+ (void) _close (sfd);
+ return -1;
+}
+
+int
+v4_tcp_server_shutdown_wr (int argc, const char *argv[])
+{
+ int sfd = -1, afd = -1, ret;
+ struct sockaddr_in saddr = { 0 }, aaddr =
+ {
+ 0};
+ socklen_t len;
+ const char *ip = argv[1];
+ const char *port = argv[2];
+
+ sfd = _socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (sfd < 0, sfd,
+ "socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)=%d:%d\n", sfd,
+ errno);
+
+ saddr.sin_family = AF_INET;
+ ret = inet_pton (AF_INET, ip, &saddr.sin_addr);
+ ERR_GOTO (ret != 1, CLEAN_S,
+ "inet_pton(AF_INET, ip=\"%s\", &saddr.sin_addr)=%d:%d\n", ip, ret,
+ errno);
+ saddr.sin_port = htons (atoi (port));
+
+ ret = _bind (sfd, (struct sockaddr *) &saddr, sizeof (saddr));
+ ERR_GOTO (ret < 0, CLEAN_S, "bind(%d, %s, %ld)=%d:%d\n", sfd,
+ f_inaddr (&saddr), sizeof (saddr), ret, errno);
+
+ ret = _listen (sfd, 100);
+ ERR_GOTO (ret < 0, CLEAN_S, "listen(%d, 100)=%d:%d\n", sfd, ret, errno);
+
+ len = sizeof (aaddr);
+ afd = _accept (sfd, (struct sockaddr *) &aaddr, &len);
+ ERR_GOTO (ret < 0, CLEAN_S, "accept(%d, %s, %d)=%d:%d\n", sfd,
+ f_inaddr (&aaddr), len, ret, errno);
+ out ("accept(sfd=%d, addr=%s, len=%d)=%d\n", sfd, f_inaddr (&aaddr), len,
+ afd);
+
+ ret = _shutdown (afd, SHUT_WR);
+ ERR_GOTO (ret != 0, CLEAN, "shutdown(afd=%d, SHUT_RD)=%d:%d\n", afd, ret,
+ errno);
+ out ("shutdown(afd=%d, SHUT_WR) ok --> sleep(10)\n", afd);
+ sleep (10);
+
+ out ("closing\n");
+
+ ret = _close (afd);
+ TEST_ASSERT (ret == 0);
+
+ ret = _close (sfd);
+ TEST_ASSERT (ret == 0);
+
+ return ret;
+
+CLEAN:
+ (void) _close (afd);
+CLEAN_S:
+ (void) _close (sfd);
+ return -1;
+}
+
+int
+v4_tcp_client_s (int argc, const char *argv[])
+{
+ int cfd = -1, ret;
+ struct sockaddr_in saddr = { 0 };
+ socklen_t len;
+ char buf[10] = { 'X', 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ const char *ip = argv[1];
+ const char *port = argv[2];
+
+ cfd = _socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (cfd < 0, cfd,
+ "socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)=%d:%d\n", cfd,
+ errno);
+
+ saddr.sin_family = AF_INET;
+ ret = inet_pton (AF_INET, ip, &saddr.sin_addr);
+ ERR_GOTO (ret != 1, CLEAN,
+ "inet_pton(AF_INET, ip=\"%s\", &saddr.sin_addr)=%d:%d\n", ip, ret,
+ errno);
+ saddr.sin_port = htons (atoi (port));
+
+ ret = _connect (cfd, (struct sockaddr *) &saddr, sizeof (saddr));
+ ERR_GOTO (ret < 0, CLEAN, "connect(%d, %s, %d)=%d:%d\n", cfd,
+ f_inaddr (&saddr), len, ret, errno);
+ out ("connect ok --> sleep(5)\n");
+ sleep (5);
+
+ ret = _send (cfd, buf, 10, 0);
+ out ("send()=%d:%d --> sleep(5)\n", ret, errno);
+ sleep (5);
+
+ ret = _close (cfd);
+ TEST_ASSERT (ret == 0);
+
+ return ret;
+
+CLEAN:
+ (void) _close (cfd);
+ return -1;
+}
+
+int
+v6_tcp_server_close_select (int argc, const char *argv[])
+{
+ int sfd = -1, afd = -1, ret;
+ struct sockaddr_in6 saddr = { 0 }, aaddr =
+ {
+ 0};
+ socklen_t len;
+ const char *ip = argv[1];
+ const char *port = argv[2];
+
+ sfd = _socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ ERR_RETURN (sfd < 0, sfd,
+ "socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)=%d:%d\n", sfd,
+ errno);
+
+ saddr.sin6_family = AF_INET6;
+ ret = inet_pton (AF_INET6, ip, &saddr.sin6_addr);
+ ERR_GOTO (ret != 1, CLEAN_S,
+ "inet_pton(AF_INET6, ip=\"%s\", &saddr.sin6_addr)=%d:%d\n", ip,
+ ret, errno);
+ saddr.sin6_port = htons (atoi (port));
+
+ ret = _bind (sfd, (struct sockaddr *) &saddr, sizeof (saddr));
+ ERR_GOTO (ret < 0, CLEAN_S, "bind(%d, %s, %ld)=%d:%d\n", sfd,
+ f_in6addr (&saddr), sizeof (saddr), ret, errno);
+
+ ret = _listen (sfd, 100);
+ ERR_GOTO (ret < 0, CLEAN_S, "listen(%d, 100)=%d:%d\n", sfd, ret, errno);
+
+ len = sizeof (aaddr);
+ afd = _accept (sfd, (struct sockaddr *) &aaddr, &len);
+ ERR_GOTO (ret < 0, CLEAN_S, "accept(%d, %s, %d)=%d:%d\n", sfd,
+ f_in6addr (&aaddr), len, ret, errno);
+
+ out ("accept(sfd=%d, addr=%s, len=%d)=%d\n", sfd, f_in6addr (&aaddr), len,
+ afd);
+
+ ret = _close (afd);
+ ERR_GOTO (ret != 0, CLEAN_S, "close(afd=%d)=%d:%d\n", afd, ret, errno);
+ out ("close(afd=%d) ok --> sleep(2)\n", afd);
+ sleep (2);
+
+ {
+ fd_set rfds, wfds, efds;
+ int nfds = afd + 1;
+ FD_ZERO (&rfds);
+ FD_SET (afd, &rfds);
+ FD_ZERO (&wfds);
+ FD_SET (afd, &wfds);
+ FD_ZERO (&efds);
+ FD_SET (afd, &efds);
+ ret = select (nfds, &rfds, &wfds, &efds, NULL);
+ int err = errno;
+ TEST_ASSERT (ret == -1);
+ TEST_ASSERT (err == EBADF);
+ }
+
+ ret = _close (sfd);
+ TEST_ASSERT (ret == 0);
+
+ return ret;
+
+CLEAN:
+ (void) _close (afd);
+CLEAN_S:
+ (void) _close (sfd);
+ return -1;
+}
+
+struct config
+{
+ char opt;
+ const char *name;
+ const char *help;
+ int (*proc) (int argc, const char *argv[]);
+};
+
+struct config list[] = {
+ {'l', "v6_tcp_server_listen", "X::X PORT", v6_tcp_server_listen},
+ {'L', "v6_tcp_server_listen", "X::X PORT", v6_tcp_server_listen},
+ {'-', NULL, NULL, NULL},
+ {'c', "v6_tcp_client_s", "X::X PORT", v6_tcp_client_s},
+ {'s', "v6_tcp_server_shutdown_rd", "X::X PORT", v6_tcp_server_shutdown_rd},
+ {'d', "v6_tcp_server_shutdown_wr", "X::X PORT", v6_tcp_server_shutdown_wr},
+ {'f', "v6_tcp_server_shutdown_rdwr", "X::X PORT",
+ v6_tcp_server_shutdown_rdwr},
+ {'-', NULL, NULL, NULL},
+ {'1', "v4_tcp_client_s", "X.X.X.X PORT", v4_tcp_client_s},
+ {'2', "v4_tcp_server_shutdown_rd", "X.X.X.X PORT",
+ v4_tcp_server_shutdown_rd},
+ {'3', "v4_tcp_server_shutdown_wr", "X.X.X.X PORT",
+ v4_tcp_server_shutdown_wr},
+ {'-', NULL, NULL, NULL},
+ {'U', "test_v6_udp", "X::X", test_v6_udp},
+ {'u', "test_v4_udp", "X.X.X.X", test_v4_udp},
+ {'t', "test_v4_tcp", "X.X.X.X", test_v4_tcp},
+ {'-', NULL, NULL, NULL},
+ {'b', "v6_udp_close_select", "X::X PORT", v6_udp_close_select},
+};
+
+int
+usage ()
+{
+ int i;
+ for (i = 0; i < sizeof (list) / sizeof (list[0]); ++i)
+ {
+ if (list[i].opt == '-')
+ out ("\n");
+ else
+ out ("%c : %s ( %s )\n", list[i].opt, list[i].name, list[i].help);
+ }
+ return 0;
+}
+
+int
+main (int argc, const char *argv[])
+{
+ int i, ret;
+
+ argc--;
+ argv++;
+
+ if (argc <= 0)
+ return usage ();
+
+ for (i = 0; i < sizeof (list) / sizeof (list[0]); ++i)
+ {
+ if (list[i].opt == '-')
+ continue;
+ if (argv[0][0] != list[i].opt)
+ continue;
+
+ out ("Test %s%s%s begin\n", CH, list[i].name, CC);
+ ret = list[i].proc (argc, argv);
+ if (ret)
+ out ("%sFAILED%s: %s\n", FR__, CC, list[i].name);
+ else
+ out ("OK: %s\n", list[i].name);
+
+ out ("\n <<<< over <<<<\n");
+ return 0;
+ }
+
+ return usage ();
+}