3752 lines
156 KiB
Diff
3752 lines
156 KiB
Diff
From f599cc99be29c47a7765e3fae602f3474b30926a Mon Sep 17 00:00:00 2001
|
||
From: yinbin6 <yinbin8@huawei.com>
|
||
Date: Thu, 11 Jul 2024 10:30:31 +0800
|
||
Subject: [PATCH] example: sync example update
|
||
|
||
---
|
||
build/build.sh | 8 +
|
||
examples/FAULT_INJECT.md | 33 ++
|
||
examples/README.md | 79 +++-
|
||
examples/inc/bussiness.h | 16 +-
|
||
examples/inc/client.h | 44 +-
|
||
examples/inc/parameter.h | 80 +++-
|
||
examples/inc/server.h | 25 +-
|
||
examples/inc/utilities.h | 88 +++-
|
||
examples/main.c | 7 +-
|
||
examples/src/bussiness.c | 212 ++++++---
|
||
examples/src/client.c | 562 ++++++++++++++++++------
|
||
examples/src/parameter.c | 484 +++++++++++++++++---
|
||
examples/src/server.c | 512 ++++++++++++++++-----
|
||
examples/src/utilities.c | 386 +++++++++++-----
|
||
src/lstack/core/lstack_protocol_stack.c | 2 +-
|
||
15 files changed, 2006 insertions(+), 532 deletions(-)
|
||
create mode 100644 examples/FAULT_INJECT.md
|
||
|
||
diff --git a/build/build.sh b/build/build.sh
|
||
index 4464f8c..622e1cc 100755
|
||
--- a/build/build.sh
|
||
+++ b/build/build.sh
|
||
@@ -31,3 +31,11 @@ if [ $? -ne 0 ]; then
|
||
fi
|
||
|
||
cd -
|
||
+cd ../examples
|
||
+cmake .
|
||
+make
|
||
+if [ $? -ne 0 ]; then
|
||
+ echo "build examples failed"
|
||
+ exit 1
|
||
+fi
|
||
+cd -
|
||
diff --git a/examples/FAULT_INJECT.md b/examples/FAULT_INJECT.md
|
||
new file mode 100644
|
||
index 0000000..ff551a9
|
||
--- /dev/null
|
||
+++ b/examples/FAULT_INJECT.md
|
||
@@ -0,0 +1,33 @@
|
||
+# Gazelle 故障注入 说明
|
||
+
|
||
+## 需求
|
||
+1. example:构造黑盒故障
|
||
+ * 延迟类:accept|read:
|
||
+ * accept: 构造tcp_acceptmbox_full的情景.
|
||
+ * read: 构造tcp_refuse_count、recvmbox满
|
||
+ * 跳过类:跳过 read/write并close:
|
||
+ * read: 构造链接关闭时时4次挥手的情景,验证TCP状态机。
|
||
+2. gazelle/lwip: 构造白盒故障,支持注入故障报文、协议栈状态、事件设置、资源异常等
|
||
+ * 编译宏支持
|
||
+ * 提供接口:配置文件、env
|
||
+ * 故障报文注入:
|
||
+ * 类似内核tc工具:
|
||
+ * 内核TC工具qdisc指令原理:报文分组被添加到网卡队列(qdisc),该队列决定发包顺序。<br>
|
||
+ qdisc指令可以在队列层面实现延时、丢包、重复等故障。
|
||
+ * dpdk性能检测工具testpmd可以模拟实现类似的故障模拟,testpmd与gazelle不兼容,需要参考其中调用的dpdk接口来改gazelle代码。<br>
|
||
+ * 延时故障
|
||
+ * 丢包故障
|
||
+ - 思路:调整网卡队列,随机丢弃百分比的包,然后发送。
|
||
+ - 函数调用:rte_rand(),rte_eth_tx_burst()。
|
||
+ * 包重复故障
|
||
+ * 随机故障
|
||
+ * 乱序故障
|
||
+ * 协议栈状态故障
|
||
+ * ...
|
||
+ * 事件设置
|
||
+ * ...
|
||
+ * 资源异常
|
||
+ * 资源耗尽,无法申请。
|
||
+ * ...
|
||
+
|
||
+
|
||
diff --git a/examples/README.md b/examples/README.md
|
||
index 5a73ce0..77a0f85 100644
|
||
--- a/examples/README.md
|
||
+++ b/examples/README.md
|
||
@@ -7,6 +7,7 @@
|
||
* 支持多线程网络非对称模型,一个 listen 线程,若干个读写线程。listen 线程和读写线程使用 `poll` / `epoll` 监听事件。
|
||
* 支持 `recvmsg` 、`sendmsg` 、`recv` 、`send` 、`recvfrom`、`sendto`、`getpeername` 、`getsockopt` 、`epoll_ctl` 等 posix 接口。
|
||
* 网络通讯报文采用问答方式,丢包或者内容错误则报错并停止通讯。报文内容有变化,长度可配。
|
||
+* 支持网络故障注入,延迟进行(delay)、跳过(skip)read、write、accept等逻辑。
|
||
|
||
## 网络模型
|
||
|
||
@@ -103,15 +104,15 @@
|
||
* `-a, --as [server | client]`:作为服务端还是客户端。
|
||
* `server`:作为服务端。
|
||
* `client`:作为客户端。
|
||
-* `-i, --ip [xxx.xxx.xxx.xxx]`:IP地址。
|
||
-* `-g, --groupip [xxx.xxx.xxx.xxx]`:UDP组播地址。
|
||
+* `-i, --ip [xxx.xxx.xxx.xxx]`:server端IP地址。当v4与v6地址同时存在时,以","分隔。例如:`-i 192.168.1.88,aa22:bb11:1122:cdef:1234:aa99:7654:7410`
|
||
+* `-g, --groupip [xxx.xxx.xxx.xxx,xxx.xxx.xxx.xxx]`:配置UDP组播地址与interface地址,以','分隔,其中interface地址为可选项。例如:`-g 224.0.0.24,192.168.1.202`或`-g 224.0.0.24`
|
||
* `-p, --port [xxxx]`:端口。
|
||
* `-m, --model [mum | mud]`:采用的网络模型类型。
|
||
* `mum (multi thread, unblock, multiplexing IO)`:多线程非阻塞IO复用。
|
||
* `mud (multi thread, unblock, dissymmetric)`:多线程非阻塞非对称。
|
||
* `-t, --threadnum`:线程数设置。
|
||
* `-c, --connectnum`:连接数设置。当 `domain` 设置为 `udp` 时,`connectnum` 会被设置为1。
|
||
-* `-D, --domain [unix | tcp | udp]`:通信协议。
|
||
+* `-D, --domain [unix | tcp | udp]`:通信协议。当支持多个通信协议时以","分隔。例如:`-D tcp,udp`
|
||
* `unix`:基于 unix 协议实现。
|
||
* `tcp`:基于 tcp 协议实现。
|
||
* `udp`:基于 udp 协议实现。
|
||
@@ -132,6 +133,19 @@
|
||
* `-C, --accept`:accept的方式。
|
||
* `ac`:使用accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)通过套接口接受连接。
|
||
* `ac4`:使用accept4(int sockfd, struct sockaddr *addr,socklen_t *addrlen, int flags)通过套接口接受连接,flags=SOCK_CLOEXEC。
|
||
+* `-k, --keep_alive`:配置TCP keep_alive idle , keep_alive interval时间(second)。
|
||
+* `-I, --inject`: 配置故障注入类型。
|
||
+ * `delay`:
|
||
+ * `"delay 20 before_accept"`: 延迟20秒进行accept,时间可自定义,需大于0。可用于构造tcp_acceptmbox_full的情景
|
||
+ * `"delay 20 before_read"`: 延迟20秒进行read,时间可自定义,需大于0。
|
||
+ * `"delay 20 before_write"`: 延迟20秒进行write,时间可自定义,需大于0。
|
||
+ * `"delay 20 before_read_and_write"`: 延迟20秒进行read和write,时间可自定义,需大于0。
|
||
+ * `skip`:
|
||
+ * `"skip write"`: 跳过写过程,并关闭链接。
|
||
+ * `"skip read"`: 跳过读过程,并关闭链接。
|
||
+ * `"skip read_and_write"`: 跳过读写写过程,并关闭链接。
|
||
+
|
||
+
|
||
## 使用
|
||
|
||
* **环境配置**
|
||
@@ -235,12 +249,12 @@ make
|
||
* 创建udp组播服务端
|
||
|
||
```
|
||
-./example -A server -D udp -i 192.168.0.1 -g 225.0.0.1 -A recvfromsendto
|
||
+./example -A server -D udp -g 225.0.0.1,192.168.0.1 -A recvfromsendto
|
||
|
||
[program parameters]:
|
||
--> [as]: server
|
||
---> [server ip]: 192.168.0.1
|
||
--> [server group ip]: 225.0.0.1
|
||
+--> [server groupip_interface]: 192.168.0.1
|
||
--> [server port]: 5050
|
||
--> [model]: mum
|
||
--> [thread number]: 1
|
||
@@ -260,12 +274,12 @@ make
|
||
* 创建udp组播客户端
|
||
|
||
```
|
||
-./example -A client -D udp -i 192.168.0.1 -g 225.0.0.1 -A recvfromsendto
|
||
+./example -A client -D udp -g 225.0.0.1,192.168.0.1 -A recvfromsendto
|
||
|
||
[program parameters]:
|
||
---> [as]: server
|
||
---> [server ip]: 225.0.0.1
|
||
---> [client send ip]: 192.168.0.1
|
||
+--> [as]: client
|
||
+--> [client group ip]: 225.0.0.1
|
||
+--> [client groupip_interface]: 192.168.0.1
|
||
--> [server port]: 5050
|
||
--> [thread number]: 1
|
||
--> [connection number]: 1
|
||
@@ -280,3 +294,50 @@ make
|
||
[program informations]:
|
||
--> <client>: [connect num]: 0, [send]: 0.000 B/s
|
||
```
|
||
+
|
||
+* 混杂模式下server 与 client 配置
|
||
+```
|
||
+./example -a server -D tcp,udp -i 192.168.1.88 -p 33333 -g 224.0.0.24,192.168.1.188
|
||
+[program parameters]:
|
||
+--> [as]: server
|
||
+--> [server group ip]: 224.0.0.24
|
||
+--> [server groupip_interface]: 192.168.1.188
|
||
+--> [server ip]: 192.168.1.888
|
||
+--> [server port]: 33333
|
||
+--> [model]: mum
|
||
+--> [thread number]: 1
|
||
+--> [domain]: tcp,udp
|
||
+--> [api]: read & write
|
||
+--> [packet length]: 1024
|
||
+--> [verify]: off
|
||
+--> [ringpmd]: off
|
||
+--> [debug]: off
|
||
+--> [epoll create]: ec
|
||
+--> [accept]: ac
|
||
+--> [inject]: none
|
||
+
|
||
+[program informations]:
|
||
+```
|
||
+```
|
||
+./example -a client -D tcp,udp -i 192.168.1.188 -p 33333 -g 192.168.1.202,224.0.0.24
|
||
+[program parameters]:
|
||
+--> [as]: client
|
||
+--> [client group ip]: 224.0.0.24
|
||
+--> [client groupip_interface]: 192.168.1.202
|
||
+--> [server ip]: 192.168.1.188
|
||
+--> [server port]: 33333
|
||
+--> [thread number]: 1
|
||
+--> [connection number]: 1
|
||
+--> [domain]: tcp,udp
|
||
+--> [api]: read & write
|
||
+--> [packet length]: 1024
|
||
+--> [verify]: off
|
||
+--> [ringpmd]: off
|
||
+--> [debug]: off
|
||
+--> [epoll create]: ec
|
||
+--> [accept]: ac
|
||
+--> [inject]: none
|
||
+
|
||
+[program informations]:
|
||
+
|
||
+```
|
||
\ No newline at end of file
|
||
diff --git a/examples/inc/bussiness.h b/examples/inc/bussiness.h
|
||
index 83645ef..3a78b1f 100644
|
||
--- a/examples/inc/bussiness.h
|
||
+++ b/examples/inc/bussiness.h
|
||
@@ -28,7 +28,9 @@
|
||
*/
|
||
struct ServerHandler
|
||
{
|
||
+ int32_t listen_fd_array[PROTOCOL_MODE_MAX];
|
||
int32_t fd; ///< socket file descriptor
|
||
+ int32_t is_v6;
|
||
};
|
||
|
||
/**
|
||
@@ -39,6 +41,7 @@ struct ClientHandler
|
||
{
|
||
int32_t fd; ///< socket file descriptor
|
||
uint32_t msg_idx; ///< the start charactors index of message
|
||
+ int32_t sendtime_interverl; ///< udp send packet interverl
|
||
};
|
||
|
||
|
||
@@ -90,24 +93,21 @@ int32_t client_bussiness(char *out, const char *in, uint32_t size, bool verify,
|
||
/**
|
||
* @brief server checks the information and answers
|
||
* This function checks the information and answers.
|
||
- * @param server_handler server handler
|
||
+ * @param fd socket_fd
|
||
* @param pktlen the length of package
|
||
* @param api the api
|
||
* @return the result
|
||
*/
|
||
-int32_t server_ans(struct ServerHandler *server_handler, uint32_t pktlen, const char* api, const char* domain);
|
||
+int32_t server_ans(int32_t fd, uint32_t pktlen, const char* api, const char* domain);
|
||
|
||
/**
|
||
* @brief client asks server
|
||
* This function asks server.
|
||
* @param client_handler client handler
|
||
- * @param pktlen the length of package
|
||
- * @param api the api
|
||
- * @param domain the domain
|
||
+ * @param client_unit ClientUnit
|
||
* @return the result
|
||
*/
|
||
-int32_t client_ask(struct ClientHandler *client_handler, uint32_t pktlen, const char* api, const char* domain, in_addr_t ip, uint16_t port);
|
||
-
|
||
+int32_t client_ask(struct ClientHandler *client_handler, struct ClientUnit *client_unit);
|
||
/**
|
||
* @brief client checks the information and answers
|
||
* This function checks the information and answers.
|
||
@@ -119,7 +119,7 @@ int32_t client_ask(struct ClientHandler *client_handler, uint32_t pktlen, const
|
||
* @param ip the ip address of peer, maybe group ip
|
||
* @return the result
|
||
*/
|
||
-int32_t client_chkans(struct ClientHandler *client_handler, uint32_t pktlen, bool verify, const char* api, const char* domain, in_addr_t ip);
|
||
+int32_t client_chkans(struct ClientHandler *client_handler, uint32_t pktlen, bool verify, const char* api, const char* domain, ip_addr_t* ip);
|
||
|
||
|
||
#endif // __EXAMPLES_BUSSINESS_H__
|
||
diff --git a/examples/inc/client.h b/examples/inc/client.h
|
||
index 97af33f..0fe07aa 100644
|
||
--- a/examples/inc/client.h
|
||
+++ b/examples/inc/client.h
|
||
@@ -19,31 +19,8 @@
|
||
#include "parameter.h"
|
||
#include "bussiness.h"
|
||
|
||
-
|
||
-/**
|
||
- * @brief client unit
|
||
- * The information of each thread of client.
|
||
- */
|
||
-struct ClientUnit
|
||
-{
|
||
- struct ClientHandler *handlers; ///< the handlers
|
||
- int32_t epfd; ///< the connect epoll file descriptor
|
||
- struct epoll_event *epevs; ///< the epoll events
|
||
- uint32_t curr_connect; ///< current connection number
|
||
- uint64_t send_bytes; ///< total send bytes
|
||
- in_addr_t ip; ///< server ip
|
||
- in_addr_t groupip; ///< server groupip
|
||
- uint16_t port; ///< server port
|
||
- uint16_t sport; ///< client sport
|
||
- uint32_t connect_num; ///< total connection number
|
||
- uint32_t pktlen; ///< the length of peckage
|
||
- bool verify; ///< if we verify or not
|
||
- char* domain; ///< the communication domain
|
||
- char* api; ///< the type of api
|
||
- bool debug; ///< if we print the debug information
|
||
- char* epollcreate; ///< epoll_create method
|
||
- struct ClientUnit *next; ///< next pointer
|
||
-};
|
||
+#define TIME_SCAN_INTERVAL 1
|
||
+#define TIME_SEND_INTERVAL 1
|
||
|
||
/**
|
||
* @brief client
|
||
@@ -53,8 +30,14 @@ struct Client
|
||
{
|
||
struct ClientUnit *uints; ///< the server mum unit
|
||
bool debug; ///< if we print the debug information
|
||
+ uint32_t threadNum;
|
||
+ bool loop; ///< judge client info print while loop is open
|
||
};
|
||
|
||
+struct Client_domain_ip {
|
||
+ char *domain;
|
||
+ uint8_t ip_family;
|
||
+};
|
||
|
||
/**
|
||
* @brief the single thread, client prints informations
|
||
@@ -66,7 +49,7 @@ struct Client
|
||
* @param debug if debug or not
|
||
* @return the result pointer
|
||
*/
|
||
-void client_debug_print(const char *ch_str, const char *act_str, in_addr_t ip, uint16_t port, bool debug);
|
||
+void client_debug_print(const char *ch_str, const char *act_str, ip_addr_t *ip, uint16_t port, bool debug);
|
||
|
||
/**
|
||
* @brief the client prints informations
|
||
@@ -86,7 +69,7 @@ void client_info_print(struct Client *client);
|
||
* @param domain domain
|
||
* @return the result pointer
|
||
*/
|
||
-int32_t client_thread_try_connect(struct ClientHandler *client_handler, int32_t epoll_fd, in_addr_t ip, in_addr_t groupip, uint16_t port, uint16_t sport, const char *domain, const char *api);
|
||
+int32_t client_thread_try_connect(struct ClientHandler *client_handler, struct ClientUnit *client_unit);
|
||
|
||
/**
|
||
* @brief the single thread, client retry to connect to server, register to epoll
|
||
@@ -122,4 +105,11 @@ void *client_s_create_and_run(void *arg);
|
||
int32_t client_create_and_run(struct ProgramParams *params);
|
||
|
||
|
||
+/**
|
||
+ * @brief loop server info
|
||
+ * This function print loop mode server info.
|
||
+ */
|
||
+void loop_info_print();
|
||
+
|
||
+
|
||
#endif // __EXAMPLES_CLIENT_H__
|
||
diff --git a/examples/inc/parameter.h b/examples/inc/parameter.h
|
||
index 93e3672..ff2f114 100644
|
||
--- a/examples/inc/parameter.h
|
||
+++ b/examples/inc/parameter.h
|
||
@@ -20,6 +20,8 @@
|
||
|
||
#define PARAM_DEFAULT_AS ("server") ///< default type
|
||
#define PARAM_DEFAULT_IP ("127.0.0.1") ///< default IP
|
||
+#define PARAM_DEFAULT_IP_V6 ("0.0.0.0.0.0.0.0") ///< default IP
|
||
+#define PARAM_DEFAULT_ADDR_FAMILY (AF_INET) ///< default address family
|
||
#define PARAM_DEFAULT_PORT (5050) ///< default port
|
||
#define PARAM_DEFAULT_SPORT (0) ///< default sport
|
||
#define PARAM_DEFAULT_MODEL ("mum") ///< default model type
|
||
@@ -34,6 +36,9 @@
|
||
#define PARAM_DEFAULT_EPOLLCREATE ("ec") ///< default method of epoll_create
|
||
#define PARAM_DEFAULT_ACCEPT ("ac") ///< default method of accept method
|
||
#define PARAM_DEFAULT_GROUPIP ("0.0.0.0") ///< default group IP>
|
||
+#define PARAM_DEFAULT_KEEPALIVEIDLE (0) ///< default TCP_KEEPALIVE_IDLE_TIME>
|
||
+
|
||
+#define TCP_KEEPALIVE_IDLE_MAX (3600) // time: second
|
||
|
||
|
||
enum {
|
||
@@ -43,7 +48,7 @@ enum {
|
||
PARAM_NUM_IP = 'i',
|
||
#define PARAM_NAME_PORT ("port") ///< name of parameter port
|
||
PARAM_NUM_PORT = 'p',
|
||
-#define PARAM_NAME_SPORT ("sport") ///< name of parameter sport
|
||
+#define PARAM_NAME_SPORT ("sport") ///< name of parameter sport
|
||
PARAM_NUM_SPORT = 's',
|
||
#define PARAM_NAME_MODEL ("model") ///< name of parameter model type
|
||
PARAM_NUM_MODEL = 'm',
|
||
@@ -71,12 +76,27 @@ enum {
|
||
PARAM_NUM_ACCEPT = 'C',
|
||
#define PARAM_NAME_GROUPIP ("groupip") ///< name of parameter group ip
|
||
PARAM_NUM_GROUPIP = 'g',
|
||
+#define PARAM_NAME_KEEPALIVE ("keep_alive") ///< name of parameter keep_alive
|
||
+ PARAM_NUM_KEEPALIVE = 'k',
|
||
+#define PARAM_NAME_INJECT ("inject") ///< name of parameter fault inject
|
||
+ PARAM_NUM_INJECT = 'I',
|
||
};
|
||
|
||
#define NO_ARGUMENT 0 ///< options takes no arguments
|
||
#define REQUIRED_ARGUMETN 1 ///< options requires arguments
|
||
#define OPTIONAL_ARGUMETN 2 ///< options arguments are optional
|
||
|
||
+uint8_t getbit_num(uint8_t mode, uint8_t index);
|
||
+uint8_t setbitnum_on(uint8_t mode, uint8_t index);
|
||
+uint8_t setbitnum_off(uint8_t mode, uint8_t index);
|
||
+
|
||
+uint8_t program_get_protocol_mode_by_domain_ip(char* domain, char* ipv4, char* ipv6, char* group_ip);
|
||
+
|
||
+struct ServerBaseCfgInfo {
|
||
+ const char *domain;
|
||
+ const char *api;
|
||
+ uint32_t pktlen;
|
||
+};
|
||
|
||
/**
|
||
* @brief program option description
|
||
@@ -96,12 +116,13 @@ struct ProgramOption {
|
||
struct ProgramParams {
|
||
char* as; ///< as server or client
|
||
char* ip; ///< IP address
|
||
- uint32_t port; ///< port
|
||
- uint32_t sport; ///< sport
|
||
+ char* ipv6;
|
||
+ bool port[UNIX_TCP_PORT_MAX]; ///< index:port list; value:port is set or not
|
||
+ bool sport[UNIX_TCP_PORT_MAX]; ///< index:sport list; value:sport is set or not
|
||
char* model; ///< model type
|
||
uint32_t thread_num; ///< the number of threads
|
||
uint32_t connect_num; ///< the connection number
|
||
- char* domain; ///< the communication dimain
|
||
+ char* domain; ///< the communication domain
|
||
char* api; ///< the type of api
|
||
uint32_t pktlen; ///< the packet length
|
||
bool verify; ///< if we verify the message or not
|
||
@@ -110,8 +131,58 @@ struct ProgramParams {
|
||
char* accept; ///< accept connections method
|
||
bool ringpmd; ///< if we use ring PMD or not
|
||
char* groupip; ///< group IP address>
|
||
+ char* groupip_interface; ///< udp multicast interface address>
|
||
+ uint32_t addr_family; ///< IP address family
|
||
+ int32_t tcp_keepalive_idle; ///< tcp keepalive idle time
|
||
+ int32_t tcp_keepalive_interval; ///< tcp keepalive interval time
|
||
+#define INJECT_TYPE_IDX (0) ///< the index of inject type
|
||
+#define INJECT_TIME_IDX (1) ///< the index of delay time
|
||
+#define INJECT_SKIP_IDX (1) ///< the index of skip location
|
||
+#define INJECT_LOCATION_IDX (2) ///< the index of delay location
|
||
+#define FAULT_INJECT_PARA_COUNT (3) ///< the count of fault injection parameters
|
||
+ char* inject[FAULT_INJECT_PARA_COUNT]; /// < fault inject
|
||
};
|
||
|
||
+typedef enum {
|
||
+ INJECT_DELAY_ACCEPT = 0,
|
||
+ INJECT_DELAY_READ,
|
||
+ INJECT_DELAY_WRITE,
|
||
+ INJECT_DELAY_MAX,
|
||
+}delay_type;
|
||
+
|
||
+typedef enum {
|
||
+ INJECT_SKIP_READ = 0,
|
||
+ INJECT_SKIP_WRITE,
|
||
+ INJECT_SKIP_MAX,
|
||
+} skip_type;
|
||
+
|
||
+typedef enum {
|
||
+ V4_TCP,
|
||
+ V6_TCP,
|
||
+ V4_UDP,
|
||
+ V6_UDP,
|
||
+ UDP_MULTICAST,
|
||
+ UNIX,
|
||
+ PROTOCOL_MODE_MAX
|
||
+} PROTOCOL_MODE_ENUM_TYPE;
|
||
+
|
||
+#define FAULT_INJECT_SKIP_BEGIN(skip_type) \
|
||
+ if (get_g_inject_skip((skip_type))) {} \
|
||
+ else {
|
||
+#define FAULT_INJECT_SKIP_END }
|
||
+
|
||
+/**
|
||
+ * @brief return g_inject_skip value
|
||
+ * This function return g_inject_skip value to deside if excute skip
|
||
+ */
|
||
+int32_t get_g_inject_skip(skip_type type);
|
||
+
|
||
+/**
|
||
+ * @brief function execute delay inject
|
||
+ * This function delay execute following program.
|
||
+ */
|
||
+void fault_inject_delay(delay_type type);
|
||
+
|
||
/**
|
||
* @brief initialize the parameters
|
||
* This function initializes the parameters of main function.
|
||
@@ -142,5 +213,6 @@ int32_t program_params_parse(struct ProgramParams *params, uint32_t argc, char *
|
||
*/
|
||
void program_params_print(struct ProgramParams *params);
|
||
|
||
+bool ip_is_v6(const char *ip);
|
||
|
||
#endif // __EXAMPLES_PARAMETER_H__
|
||
diff --git a/examples/inc/server.h b/examples/inc/server.h
|
||
index a3affef..4631a28 100644
|
||
--- a/examples/inc/server.h
|
||
+++ b/examples/inc/server.h
|
||
@@ -31,8 +31,7 @@ struct ServerMumUnit
|
||
struct epoll_event *epevs; ///< the epoll events
|
||
uint32_t curr_connect; ///< current connection number
|
||
uint64_t recv_bytes; ///< total receive bytes
|
||
- in_addr_t ip; ///< server ip
|
||
- in_addr_t groupip; ///< server group ip
|
||
+ struct ServerIpInfo server_ip_info;
|
||
uint16_t port; ///< server port
|
||
uint32_t pktlen; ///< the length of peckage
|
||
char* domain; ///< communication domain
|
||
@@ -40,6 +39,9 @@ struct ServerMumUnit
|
||
bool debug; ///< if we print the debug information
|
||
char* epollcreate; ///< epoll_create method
|
||
char* accept; ///< accept connections method
|
||
+ int32_t tcp_keepalive_idle; ///< tcp keepalive idle time
|
||
+ int32_t tcp_keepalive_interval; ///< tcp keepalive interval time
|
||
+ uint8_t protocol_type_mode; ///< tcp/udp ipv4/ipv6 protocol mode
|
||
struct ServerMumUnit *next; ///< next pointer
|
||
};
|
||
|
||
@@ -64,11 +66,13 @@ struct ServerMudWorker
|
||
struct epoll_event *epevs; ///< the epoll events
|
||
uint64_t recv_bytes; ///< total receive bytes
|
||
uint32_t pktlen; ///< the length of peckage
|
||
- in_addr_t ip; ///< client ip
|
||
+ ip_addr_t ip; ///< client ip
|
||
uint16_t port; ///< client port
|
||
char* api; ///< the type of api
|
||
bool debug; ///< if we print the debug information
|
||
char* epollcreate; ///< epoll_create method
|
||
+ char* domain;
|
||
+ uint32_t curr_connect;
|
||
struct ServerMudWorker *next; ///< next pointer
|
||
};
|
||
|
||
@@ -82,16 +86,17 @@ struct ServerMud
|
||
struct ServerMudWorker *workers; ///< the workers
|
||
int32_t epfd; ///< the listen epoll file descriptor
|
||
struct epoll_event *epevs; ///< the epoll events
|
||
- uint32_t curr_connect; ///< current connection number
|
||
- in_addr_t ip; ///< server ip
|
||
- in_addr_t groupip; ///< server group ip
|
||
- uint16_t port; ///< server port
|
||
+ struct ServerIpInfo server_ip_info;
|
||
+ bool* port; ///< server port point to parameter's port
|
||
uint32_t pktlen; ///< the length of peckage
|
||
char* domain; ///< communication domain
|
||
char* api; ///< the type of api
|
||
bool debug; ///< if we print the debug information
|
||
char* accept; ///< accept connections method
|
||
char* epollcreate; ///< epoll_create method
|
||
+ int32_t tcp_keepalive_idle; ///< tcp keepalive idle time
|
||
+ int32_t tcp_keepalive_interval; ///< tcp keepalive interval time
|
||
+ uint8_t protocol_type_mode; ///< tcp/udp ipv4/ipv6 protocol mode
|
||
};
|
||
|
||
|
||
@@ -105,7 +110,7 @@ struct ServerMud
|
||
* @param debug if debug or not
|
||
* @return the result pointer
|
||
*/
|
||
-void server_debug_print(const char *ch_str, const char *act_str, in_addr_t ip, uint16_t port, bool debug);
|
||
+void server_debug_print(const char *ch_str, const char *act_str, ip_addr_t *ip, uint16_t port, bool debug);
|
||
|
||
/**
|
||
* @brief the multi thread, unblock, dissymmetric server prints informations
|
||
@@ -136,7 +141,7 @@ int32_t sermud_listener_create_epfd_and_reg(struct ServerMud *server_mud);
|
||
* @param server_mud the server unit
|
||
* @return the result pointer
|
||
*/
|
||
-int32_t sermud_listener_accept_connects(struct ServerMud *server_mud);
|
||
+int32_t sermud_listener_accept_connects(struct epoll_event *curr_epev, struct ServerMud *server_mud);
|
||
|
||
/**
|
||
* @brief the worker thread, unblock, dissymmetric server processes the events
|
||
@@ -200,7 +205,7 @@ int32_t sersum_create_epfd_and_reg(struct ServerMumUnit *server_unit);
|
||
* @param server_handler the server handler
|
||
* @return the result pointer
|
||
*/
|
||
-int32_t sersum_accept_connects(struct ServerMumUnit *server_unit, struct ServerHandler *server_handler);
|
||
+int32_t sersum_accept_connects(struct epoll_event *cur_epev, struct ServerMumUnit *server_unit);
|
||
|
||
/**
|
||
* @brief the single thread, unblock, mutliplexing IO server processes the events
|
||
diff --git a/examples/inc/utilities.h b/examples/inc/utilities.h
|
||
index 0f9db4e..262481a 100644
|
||
--- a/examples/inc/utilities.h
|
||
+++ b/examples/inc/utilities.h
|
||
@@ -27,6 +27,7 @@
|
||
#include <errno.h>
|
||
#include <fcntl.h>
|
||
#include <pthread.h>
|
||
+#include <signal.h>
|
||
|
||
#include <sys/types.h>
|
||
#include <sys/socket.h>
|
||
@@ -36,6 +37,7 @@
|
||
#include <sys/un.h>
|
||
|
||
#include <netinet/in.h>
|
||
+#include <netinet/tcp.h>
|
||
#include <arpa/inet.h>
|
||
|
||
#include "securec.h"
|
||
@@ -47,7 +49,7 @@
|
||
{ \
|
||
printf("\n[error]: "); \
|
||
printf(format, ##__VA_ARGS__); \
|
||
- printf("\n"); \
|
||
+ printf("\n\n"); \
|
||
} while (0)
|
||
#define PRINT_WARNNING(format, ...) do \
|
||
{ \
|
||
@@ -76,7 +78,7 @@
|
||
} while(0)
|
||
#define PRINT_CLIENT_DATAFLOW(format, ...) do \
|
||
{ \
|
||
- printf("\033[?25l\033[A\033[K"); \
|
||
+ printf(" "); \
|
||
printf("--> <client>: "); \
|
||
printf(format, ##__VA_ARGS__); \
|
||
printf("\033[?25h\n"); \
|
||
@@ -90,24 +92,94 @@
|
||
#define PROGRAM_INPROGRESS (-2) ///< program in progress flag
|
||
|
||
#define UNIX_TCP_PORT_MIN (1024) ///< TCP minimum port number in unix
|
||
-#define UNIX_TCP_PORT_MAX (65535) ///< TCP minimum port number in unix
|
||
+#define UNIX_TCP_PORT_MAX (65535) ///< TCP maximum port number in unix
|
||
#define THREAD_NUM_MIN (1) ///< minimum number of thead
|
||
#define THREAD_NUM_MAX (1000) ///< maximum number of thead
|
||
#define MESSAGE_PKTLEN_MIN (2) ///< minimum length of message (1 byte)
|
||
#define MESSAGE_PKTLEN_MAX (1024 * 1024 * 10) ///< maximum length of message (10 Mb)
|
||
+#define UDP_PKTLEN_MAX (65507) ///< maximum length of udp message
|
||
|
||
-#define SERVER_SOCKET_LISTEN_BACKLOG (128) ///< the queue of socket
|
||
+#define SERVER_SOCKET_LISTEN_BACKLOG (4096) ///< the queue of socket
|
||
#define SERVER_EPOLL_SIZE_MAX (10000) ///< the max wait event of epoll
|
||
#define SERVER_EPOLL_WAIT_TIMEOUT (-1) ///< the timeout value of epoll
|
||
|
||
#define CLIENT_EPOLL_SIZE_MAX (10000) ///< the max wait event of epoll
|
||
#define CLIENT_EPOLL_WAIT_TIMEOUT (-1) ///< the timeout value of epoll
|
||
|
||
-#define TERMINAL_REFRESH_MS (100) ///< the time cut off between of terminal refresh
|
||
+#define TERMINAL_REFRESH_MS (500) ///< the time cut off between of terminal refresh
|
||
|
||
#define SOCKET_UNIX_DOMAIN_FILE "unix_domain_file" ///< socket unix domain file
|
||
|
||
+#define IPV4_STR "V4"
|
||
+#define IPV6_STR "V6"
|
||
+#define IPV4_MULTICAST "Multicast"
|
||
+#define INVAILD_STR "STR_NULL"
|
||
+
|
||
+#define TIMES_CONVERSION_RATE (1000)
|
||
+#define KB (1024)
|
||
+#define MB (KB * KB)
|
||
+#define GB (MB * MB)
|
||
+
|
||
+struct ThreadUintInfo {
|
||
+ uint64_t send_bytes; ///< total send bytes
|
||
+ uint32_t cur_connect_num; ///< total connection number
|
||
+ char* domain;
|
||
+ char* ip_type_info;
|
||
+ pthread_t thread_id;
|
||
+};
|
||
+
|
||
+typedef struct ip_addr {
|
||
+ struct {
|
||
+ struct in_addr ip4;
|
||
+ struct in6_addr ip6;
|
||
+ } u_addr;
|
||
+ uint32_t addr_family;
|
||
+} ip_addr_t;
|
||
+
|
||
+typedef union sockaddr_union {
|
||
+ struct sockaddr sa;
|
||
+ struct sockaddr_in in;
|
||
+ struct sockaddr_in6 in6;
|
||
+} sockaddr_t;
|
||
|
||
+/**
|
||
+ * @brief client unit
|
||
+ * The information of each thread of client.
|
||
+ */
|
||
+struct ClientUnit {
|
||
+ struct ClientHandler *handlers; ///< the handlers
|
||
+ int32_t epfd; ///< the connect epoll file descriptor
|
||
+ struct epoll_event *epevs; ///< the epoll events
|
||
+ uint32_t curr_connect; ///< current connection number
|
||
+ ip_addr_t ip; ///< server ip
|
||
+ ip_addr_t groupip; ///< server groupip
|
||
+ uint32_t port; ///< server port
|
||
+ ip_addr_t groupip_interface; ///< udp multicast interface address>
|
||
+ uint32_t sport; ///< client sport
|
||
+ uint32_t connect_num; ///< total connection number
|
||
+ uint32_t pktlen; ///< the length of peckage
|
||
+ uint32_t loop; ///< the packet send to loop
|
||
+ bool verify; ///< if we verify or not
|
||
+ char* domain; ///< the communication domain
|
||
+ char* api; ///< the type of api
|
||
+ bool debug; ///< if we print the debug information
|
||
+ char* epollcreate; ///< epoll_create method
|
||
+ uint8_t protocol_type_mode; ///< tcp/udp ipv4/ipv6 protocol mode
|
||
+ struct ThreadUintInfo threadVolume;
|
||
+ struct ClientUnit *next; ///< next pointer
|
||
+};
|
||
+struct ServerIpInfo {
|
||
+ ip_addr_t ip; ///< server ip
|
||
+ ip_addr_t groupip; ///< server group ip
|
||
+ ip_addr_t groupip_interface; ///< server group interface ip
|
||
+};
|
||
+
|
||
+struct LoopInfo {
|
||
+ char* model;
|
||
+ struct ServerMud *server_mud_info;
|
||
+ struct ServerMum *server_mum_info;
|
||
+};
|
||
+extern struct LoopInfo loopmod;
|
||
/**
|
||
* @brief create the socket and listen
|
||
* Thi function creates the socket and listen.
|
||
@@ -118,7 +190,8 @@
|
||
* @param domain domain
|
||
* @return the result
|
||
*/
|
||
-int32_t create_socket_and_listen(int32_t *socket_fd, in_addr_t ip, in_addr_t groupip, uint16_t port, const char *domain);
|
||
+int32_t create_socket_and_listen(int32_t *listen_fd_array, struct ServerIpInfo *server_ip_info, uint16_t port,
|
||
+ uint8_t protocol_mode);
|
||
|
||
/**
|
||
* @brief create the socket and connect
|
||
@@ -131,7 +204,7 @@ int32_t create_socket_and_listen(int32_t *socket_fd, in_addr_t ip, in_addr_t gro
|
||
* @param api api
|
||
* @return the result
|
||
*/
|
||
-int32_t create_socket_and_connect(int32_t *socket_fd, in_addr_t ip, in_addr_t groupip, uint16_t port, uint16_t sport, const char *domain, const char *api);
|
||
+int32_t create_socket_and_connect(int32_t *socket_fd, struct ClientUnit *client_unit);
|
||
|
||
/**
|
||
* @brief set the socket to unblock
|
||
@@ -140,6 +213,7 @@ int32_t create_socket_and_connect(int32_t *socket_fd, in_addr_t ip, in_addr_t gr
|
||
* @return the result
|
||
*/
|
||
int32_t set_socket_unblock(int32_t socket_fd);
|
||
+int32_t set_tcp_keep_alive_info(int32_t sockfd, int32_t tcp_keepalive_idle, int32_t tcp_keepalive_interval);
|
||
|
||
|
||
#endif // __EXAMPLES_UTILITIES_H__
|
||
diff --git a/examples/main.c b/examples/main.c
|
||
index 5338572..dfee2db 100644
|
||
--- a/examples/main.c
|
||
+++ b/examples/main.c
|
||
@@ -31,7 +31,12 @@ int32_t main(int argc, char *argv[])
|
||
|
||
if (strcmp(prog_params.as, "server") == 0) {
|
||
server_create_and_run(&prog_params);
|
||
- } else {
|
||
+ } else if (strcmp(prog_params.as, "client") == 0) {
|
||
+ client_create_and_run(&prog_params);
|
||
+ } else if (strcmp(prog_params.as, "loop") == 0) {
|
||
+ server_create_and_run(&prog_params);
|
||
+ /* sleep to wait server creating */
|
||
+ sleep(1);
|
||
client_create_and_run(&prog_params);
|
||
}
|
||
|
||
diff --git a/examples/src/bussiness.c b/examples/src/bussiness.c
|
||
index 7263371..46c99fe 100644
|
||
--- a/examples/src/bussiness.c
|
||
+++ b/examples/src/bussiness.c
|
||
@@ -11,8 +11,9 @@
|
||
*/
|
||
|
||
|
||
-#include "bussiness.h"
|
||
+#include "parameter.h"
|
||
#include "client.h"
|
||
+#include "bussiness.h"
|
||
|
||
|
||
static const char bussiness_messages_low[] = "abcdefghijklmnopqrstuvwxyz"; // the lower charactors of business message
|
||
@@ -135,41 +136,41 @@ int32_t client_bussiness(char *out, const char *in, uint32_t size, bool verify,
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
-// server answers
|
||
-int32_t server_ans(struct ServerHandler *server_handler, uint32_t pktlen, const char* api, const char* domain)
|
||
+static void server_ans_free_buff(char *buff_in, char *buff_out)
|
||
{
|
||
- const uint32_t length = pktlen;
|
||
- char *buffer_in = (char *)malloc(length * sizeof(char));
|
||
- char *buffer_out = (char *)malloc(length * sizeof(char));
|
||
+ if (buff_in) {
|
||
+ free(buff_in);
|
||
+ }
|
||
+ if (buff_out) {
|
||
+ free(buff_out);
|
||
+ }
|
||
+}
|
||
+
|
||
+// server_ans_read
|
||
+static int32_t server_ans_read(int32_t socket_fd, struct ServerBaseCfgInfo *server_base_info, char *buffer_in,
|
||
+ struct sockaddr *client_addr)
|
||
+{
|
||
+ const uint32_t length = server_base_info->pktlen;
|
||
+ const char *api = server_base_info->api;
|
||
+ const char *domain = server_base_info->domain;
|
||
|
||
int32_t cread = 0;
|
||
int32_t sread = length;
|
||
int32_t nread = 0;
|
||
- struct sockaddr_in client_addr;
|
||
- socklen_t len = sizeof(client_addr);
|
||
|
||
- if (strcmp(domain, "udp") == 0 && strncmp(api, "recvfrom", strlen("recvfrom")) != 0) {
|
||
- if (getpeername(server_handler->fd, (struct sockaddr *)&client_addr, &len) < 0) {
|
||
- if (recvfrom(server_handler->fd, buffer_in, length, MSG_PEEK, (struct sockaddr *)&client_addr, &len) < 0) {
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- if (connect(server_handler->fd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr_in)) < 0) {
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- }
|
||
- }
|
||
+ socklen_t len = sizeof(sockaddr_t);
|
||
|
||
while (cread < sread) {
|
||
if (strcmp(domain, "udp") == 0 && strcmp(api, "recvfromsendto") == 0) {
|
||
- nread = recvfrom(server_handler->fd, buffer_in, length, 0, (struct sockaddr *)&client_addr, &len);
|
||
+ nread = recvfrom(socket_fd, buffer_in, length, 0, client_addr, &len);
|
||
} else {
|
||
- nread = read_api(server_handler->fd, buffer_in, length, api);
|
||
+ nread = read_api(socket_fd, buffer_in, length, api);
|
||
}
|
||
-
|
||
if (nread == 0) {
|
||
return PROGRAM_ABORT;
|
||
} else if (nread < 0) {
|
||
if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN) {
|
||
+ PRINT_ERROR("nread =%d, errno=%d", nread, errno);
|
||
return PROGRAM_FAULT;
|
||
}
|
||
} else {
|
||
@@ -177,66 +178,152 @@ int32_t server_ans(struct ServerHandler *server_handler, uint32_t pktlen, const
|
||
continue;
|
||
}
|
||
}
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
|
||
- if (strcmp(api, "recvfrom") == 0) {
|
||
- free(buffer_in);
|
||
- free(buffer_out);
|
||
- return PROGRAM_OK;
|
||
- }
|
||
-
|
||
- server_bussiness(buffer_out, buffer_in, length);
|
||
+static int32_t server_ans_write(int32_t socket_fd, struct ServerBaseCfgInfo *server_base_info, char *buffer_out,
|
||
+ struct sockaddr *client_addr)
|
||
+{
|
||
+ const uint32_t length = server_base_info->pktlen;
|
||
+ const char *api = server_base_info->api;
|
||
+ const char *domain = server_base_info->domain;
|
||
|
||
int32_t cwrite = 0;
|
||
int32_t swrite = length;
|
||
int32_t nwrite = 0;
|
||
+ socklen_t len = sizeof(sockaddr_t);
|
||
+
|
||
while (cwrite < swrite) {
|
||
if (strcmp(domain, "udp") == 0 && strcmp(api, "recvfromsendto") == 0) {
|
||
- nwrite = sendto(server_handler->fd, buffer_out, length, 0, (struct sockaddr *)&client_addr, len);
|
||
+ nwrite = sendto(socket_fd, buffer_out, swrite - cwrite, 0, client_addr, len);
|
||
} else {
|
||
- nwrite = write_api(server_handler->fd, buffer_out, length, api);
|
||
+ nwrite = write_api(socket_fd, buffer_out, swrite - cwrite, api);
|
||
}
|
||
|
||
if (nwrite == 0) {
|
||
return PROGRAM_ABORT;
|
||
} else if (nwrite < 0) {
|
||
- if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN) {
|
||
+ if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN) {
|
||
+ PRINT_ERROR("nwrite =%d, errno=%d", nwrite, errno);
|
||
return PROGRAM_FAULT;
|
||
- }
|
||
+ }
|
||
} else {
|
||
cwrite += nwrite;
|
||
continue;
|
||
}
|
||
}
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
|
||
- free(buffer_in);
|
||
- free(buffer_out);
|
||
+// server answers
|
||
+int32_t server_ans(int32_t fd, uint32_t pktlen, const char* api, const char* domain)
|
||
+{
|
||
+ const uint32_t length = pktlen;
|
||
+ char *buffer_in = (char *)calloc(length, sizeof(char));
|
||
+ char *buffer_out = (char *)calloc(length, sizeof(char));
|
||
+ if (buffer_in == NULL || buffer_out == NULL) {
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+
|
||
+ struct ServerBaseCfgInfo server_base_info;
|
||
+ server_base_info.domain = domain;
|
||
+ server_base_info.api = api;
|
||
+ server_base_info.pktlen = pktlen;
|
||
+
|
||
+ sockaddr_t client_addr;
|
||
+ socklen_t len = sizeof(sockaddr_t);
|
||
+
|
||
+ if (strcmp(domain, "udp") == 0 && strncmp(api, "recvfrom", strlen("recvfrom")) != 0) {
|
||
+ if (getpeername(fd, (struct sockaddr *)&client_addr, &len) < 0) {
|
||
+ if (recvfrom(fd, buffer_in, length, MSG_PEEK, (struct sockaddr *)&client_addr, &len) < 0) {
|
||
+ server_ans_free_buff(buffer_in, buffer_out);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ if (connect(fd, (struct sockaddr *)&client_addr, len) < 0) {
|
||
+ server_ans_free_buff(buffer_in, buffer_out);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ fault_inject_delay(INJECT_DELAY_READ);
|
||
+ FAULT_INJECT_SKIP_BEGIN(INJECT_SKIP_READ)
|
||
+
|
||
+ if (server_ans_read(fd, &server_base_info, buffer_in, (struct sockaddr *)&client_addr) != PROGRAM_OK) {
|
||
+ server_ans_free_buff(buffer_in, buffer_out);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+
|
||
+ FAULT_INJECT_SKIP_END
|
||
+
|
||
+ if (strcmp(api, "recvfrom") == 0) {
|
||
+ server_ans_free_buff(buffer_in, buffer_out);
|
||
+ return PROGRAM_OK;
|
||
+ }
|
||
+
|
||
+ server_bussiness(buffer_out, buffer_in, length);
|
||
+
|
||
+ fault_inject_delay(INJECT_DELAY_WRITE);
|
||
+ FAULT_INJECT_SKIP_BEGIN(INJECT_SKIP_WRITE)
|
||
+
|
||
+ if (server_ans_write(fd, &server_base_info, buffer_out, (struct sockaddr *)&client_addr) != PROGRAM_OK) {
|
||
+ server_ans_free_buff(buffer_in, buffer_out);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+
|
||
+ FAULT_INJECT_SKIP_END
|
||
+
|
||
+ server_ans_free_buff(buffer_in, buffer_out);
|
||
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
// client asks
|
||
-int32_t client_ask(struct ClientHandler *client_handler, uint32_t pktlen, const char* api, const char* domain, in_addr_t ip, uint16_t port)
|
||
+int32_t client_ask(struct ClientHandler *client_handler, struct ClientUnit *client_unit)
|
||
{
|
||
- const uint32_t length = pktlen;
|
||
- char *buffer_in = (char *)malloc(length * sizeof(char));
|
||
- char *buffer_out = (char *)malloc(length * sizeof(char));
|
||
- struct sockaddr_in server_addr;
|
||
- socklen_t len = sizeof(server_addr);
|
||
- memset_s(&server_addr, sizeof(server_addr), 0, sizeof(server_addr));
|
||
- server_addr.sin_family = AF_INET;
|
||
- server_addr.sin_addr.s_addr = ip;
|
||
- server_addr.sin_port = port;
|
||
+ const char *api = client_unit->api;
|
||
+ const char *domain = client_unit->domain;
|
||
+
|
||
+ ip_addr_t *ip = client_unit->protocol_type_mode == UDP_MULTICAST ? &client_unit->groupip : &client_unit->ip;
|
||
+ uint16_t port = client_unit->port;
|
||
+
|
||
+ const uint32_t length = client_unit->pktlen;
|
||
+ char *buffer_in = (char *)calloc(length, sizeof(char));
|
||
+ char *buffer_out = (char *)calloc(length, sizeof(char));
|
||
+ if (buffer_in == NULL || buffer_out == NULL) {
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ sockaddr_t server_addr;
|
||
+ socklen_t len = 0;
|
||
+
|
||
+ if (ip->addr_family == AF_INET6) {
|
||
+ memset_s(&server_addr, sizeof(struct sockaddr_in6), 0, sizeof(struct sockaddr_in6));
|
||
+ ((struct sockaddr_in6 *)&server_addr)->sin6_family = AF_INET6;
|
||
+ ((struct sockaddr_in6 *)&server_addr)->sin6_addr = ip->u_addr.ip6;
|
||
+ ((struct sockaddr_in6 *)&server_addr)->sin6_port = port;
|
||
+ len = sizeof(struct sockaddr_in6);
|
||
+ } else if (ip->addr_family == AF_INET) {
|
||
+ memset_s(&server_addr, sizeof(struct sockaddr_in), 0, sizeof(struct sockaddr_in));
|
||
+ ((struct sockaddr_in *)&server_addr)->sin_family = AF_INET;
|
||
+ ((struct sockaddr_in *)&server_addr)->sin_addr = ip->u_addr.ip4;
|
||
+ ((struct sockaddr_in *)&server_addr)->sin_port = port;
|
||
+ len = sizeof(struct sockaddr_in);
|
||
+ }
|
||
|
||
client_bussiness(buffer_out, buffer_in, length, false, &(client_handler->msg_idx));
|
||
|
||
int32_t cwrite = 0;
|
||
int32_t swrite = length;
|
||
int32_t nwrite = 0;
|
||
+
|
||
+ fault_inject_delay(INJECT_DELAY_WRITE);
|
||
+ FAULT_INJECT_SKIP_BEGIN(INJECT_SKIP_WRITE)
|
||
+
|
||
while (cwrite < swrite) {
|
||
if (strcmp(domain, "udp") == 0 && strcmp(api, "recvfromsendto") == 0) {
|
||
- nwrite = sendto(client_handler->fd, buffer_out, length, 0, (struct sockaddr *)&server_addr, len);
|
||
+ nwrite = sendto(client_handler->fd, buffer_out, swrite - cwrite, 0, (struct sockaddr *)&server_addr, len);
|
||
} else {
|
||
- nwrite = write_api(client_handler->fd, buffer_out, length, api);
|
||
+ nwrite = write_api(client_handler->fd, buffer_out, swrite - cwrite, api);
|
||
}
|
||
if (nwrite == 0) {
|
||
return PROGRAM_ABORT;
|
||
@@ -250,6 +337,8 @@ int32_t client_ask(struct ClientHandler *client_handler, uint32_t pktlen, const
|
||
}
|
||
}
|
||
|
||
+ FAULT_INJECT_SKIP_END
|
||
+
|
||
free(buffer_in);
|
||
free(buffer_out);
|
||
|
||
@@ -257,18 +346,24 @@ int32_t client_ask(struct ClientHandler *client_handler, uint32_t pktlen, const
|
||
}
|
||
|
||
// client checks
|
||
-int32_t client_chkans(struct ClientHandler *client_handler, uint32_t pktlen, bool verify, const char* api, const char* domain, in_addr_t ip)
|
||
+int32_t client_chkans(struct ClientHandler *client_handler, uint32_t pktlen, bool verify, const char* api, const char* domain, ip_addr_t* ip)
|
||
{
|
||
const uint32_t length = pktlen;
|
||
- char *buffer_in = (char *)malloc(length * sizeof(char));
|
||
- char *buffer_out = (char *)malloc(length * sizeof(char));
|
||
+ char *buffer_in = (char *)calloc(length, sizeof(char));
|
||
+ char *buffer_out = (char *)calloc(length, sizeof(char));
|
||
+ if (buffer_in == NULL || buffer_out == NULL) {
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
|
||
int32_t cread = 0;
|
||
int32_t sread = length;
|
||
int32_t nread = 0;
|
||
- struct sockaddr_in server_addr;
|
||
- socklen_t len = sizeof(server_addr);
|
||
+ sockaddr_t server_addr;
|
||
+ socklen_t len = ip->addr_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||
|
||
+ fault_inject_delay(INJECT_DELAY_READ);
|
||
+ FAULT_INJECT_SKIP_BEGIN(INJECT_SKIP_READ)
|
||
+
|
||
while (cread < sread) {
|
||
if (strcmp(domain, "udp") == 0 && strcmp(api, "recvfromsendto") == 0) {
|
||
nread = recvfrom(client_handler->fd, buffer_in, length, 0, (struct sockaddr *)&server_addr, &len);
|
||
@@ -287,6 +382,8 @@ int32_t client_chkans(struct ClientHandler *client_handler, uint32_t pktlen, boo
|
||
}
|
||
}
|
||
|
||
+ FAULT_INJECT_SKIP_END
|
||
+
|
||
if (client_bussiness(buffer_out, buffer_in, length, verify, &(client_handler->msg_idx)) < 0) {
|
||
PRINT_ERROR("message verify fault! ");
|
||
getchar();
|
||
@@ -295,15 +392,18 @@ int32_t client_chkans(struct ClientHandler *client_handler, uint32_t pktlen, boo
|
||
int32_t cwrite = 0;
|
||
int32_t swrite = length;
|
||
int32_t nwrite = 0;
|
||
- if (ip >= inet_addr("224.0.0.0") && ip <= inet_addr("239.255.255.255")) {
|
||
- server_addr.sin_addr.s_addr = ip;
|
||
+ if (ip->addr_family == AF_INET && ip->u_addr.ip4.s_addr >= inet_addr("224.0.0.0") && ip->u_addr.ip4.s_addr <= inet_addr("239.255.255.255")) {
|
||
+ ((struct sockaddr_in*)&server_addr)->sin_addr = ip->u_addr.ip4;
|
||
}
|
||
|
||
+ fault_inject_delay(INJECT_DELAY_WRITE);
|
||
+ FAULT_INJECT_SKIP_BEGIN(INJECT_SKIP_WRITE)
|
||
+
|
||
while (cwrite < swrite) {
|
||
if (strcmp(domain, "udp") == 0 && strcmp(api, "recvfromsendto") == 0) {
|
||
- nwrite = sendto(client_handler->fd, buffer_out, length, 0, (struct sockaddr *)&server_addr, len);
|
||
+ nwrite = sendto(client_handler->fd, buffer_out, swrite - cwrite, 0, (struct sockaddr *)&server_addr, len);
|
||
} else {
|
||
- nwrite = write_api(client_handler->fd, buffer_out, length, api);
|
||
+ nwrite = write_api(client_handler->fd, buffer_out, swrite - cwrite, api);
|
||
}
|
||
if (nwrite == 0) {
|
||
return PROGRAM_ABORT;
|
||
@@ -317,6 +417,8 @@ int32_t client_chkans(struct ClientHandler *client_handler, uint32_t pktlen, boo
|
||
}
|
||
}
|
||
|
||
+ FAULT_INJECT_SKIP_END
|
||
+
|
||
free(buffer_in);
|
||
free(buffer_out);
|
||
|
||
diff --git a/examples/src/client.c b/examples/src/client.c
|
||
index 1366924..43fbd0e 100644
|
||
--- a/examples/src/client.c
|
||
+++ b/examples/src/client.c
|
||
@@ -12,24 +12,61 @@
|
||
|
||
|
||
#include "client.h"
|
||
-
|
||
+#include "server.h"
|
||
|
||
static pthread_mutex_t client_debug_mutex; // the client mutex for printf
|
||
+struct Client *g_client_begin = NULL;
|
||
+
|
||
+static int32_t client_process_ask(struct ClientHandler *client_handler, struct ClientUnit *client_unit);
|
||
+static void client_get_domain_ipversion(uint8_t protocol_type, struct ClientUnit *client_unit);
|
||
|
||
+static void timer_handle(int signum)
|
||
+{
|
||
+ if (g_client_begin == NULL) {
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ struct ClientUnit *begin_client_unit = g_client_begin->uints;
|
||
+ while (begin_client_unit != NULL) {
|
||
+ if (begin_client_unit->domain != NULL && strcmp(begin_client_unit->domain, "udp") != 0) {
|
||
+ begin_client_unit = begin_client_unit->next;
|
||
+ continue;
|
||
+ }
|
||
+ for (int32_t i = 0; i < begin_client_unit->connect_num; i++) {
|
||
+ struct ClientHandler *handle = begin_client_unit->handlers + i;
|
||
+ if (handle->sendtime_interverl == TIME_SEND_INTERVAL) {
|
||
+ client_process_ask(handle, begin_client_unit);
|
||
+ } else {
|
||
+ handle->sendtime_interverl++;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ begin_client_unit = begin_client_unit->next;
|
||
+ }
|
||
+ alarm(TIME_SCAN_INTERVAL);
|
||
+}
|
||
+
|
||
+static struct Client_domain_ip g_cfgmode_map[PROTOCOL_MODE_MAX] = {
|
||
+ [V4_TCP] = {"tcp", AF_INET},
|
||
+ [V6_TCP] = {"tcp", AF_INET6},
|
||
+ [V4_UDP] = {"udp", AF_INET},
|
||
+ [V6_UDP] = {"udp", AF_INET6},
|
||
+ [UDP_MULTICAST] = {"udp", AF_INET}};
|
||
|
||
// the single thread, client prints informations
|
||
-void client_debug_print(const char *ch_str, const char *act_str, in_addr_t ip, uint16_t port, bool debug)
|
||
+void client_debug_print(const char *ch_str, const char *act_str, ip_addr_t *ip, uint16_t port, bool debug)
|
||
{
|
||
if (debug == true) {
|
||
pthread_mutex_lock(&client_debug_mutex);
|
||
- struct in_addr sin_addr;
|
||
- sin_addr.s_addr = ip;
|
||
+ uint8_t str_len = ip->addr_family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
|
||
+ char str_ip[str_len];
|
||
+ inet_ntop(ip->addr_family, &ip->u_addr, str_ip, str_len);
|
||
PRINT_CLIENT("[%s] [pid: %d] [tid: %ld] [%s <- %s:%d]. ", \
|
||
ch_str, \
|
||
getpid(), \
|
||
pthread_self(), \
|
||
act_str, \
|
||
- inet_ntoa(sin_addr), \
|
||
+ str_ip, \
|
||
ntohs(port));
|
||
pthread_mutex_unlock(&client_debug_mutex);
|
||
}
|
||
@@ -41,7 +78,8 @@ void client_info_print(struct Client *client)
|
||
if (client->debug == false) {
|
||
struct timeval begin;
|
||
gettimeofday(&begin, NULL);
|
||
- uint64_t begin_time = (uint64_t)begin.tv_sec * 1000 + (uint64_t)begin.tv_usec / 1000;
|
||
+ uint64_t begin_time = (uint64_t)begin.tv_sec * TIMES_CONVERSION_RATE +
|
||
+ (uint64_t)begin.tv_usec / TIMES_CONVERSION_RATE;
|
||
|
||
uint32_t curr_connect = 0;
|
||
double bytes_ps = 0;
|
||
@@ -49,45 +87,164 @@ void client_info_print(struct Client *client)
|
||
struct ClientUnit *begin_uint = client->uints;
|
||
while (begin_uint != NULL) {
|
||
curr_connect += begin_uint->curr_connect;
|
||
- begin_send_bytes += begin_uint->send_bytes;
|
||
+ begin_send_bytes += begin_uint->threadVolume.send_bytes;
|
||
begin_uint = begin_uint->next;
|
||
}
|
||
|
||
struct timeval delay;
|
||
delay.tv_sec = 0;
|
||
- delay.tv_usec = TERMINAL_REFRESH_MS * 1000;
|
||
+ delay.tv_usec = TERMINAL_REFRESH_MS * TIMES_CONVERSION_RATE;
|
||
select(0, NULL, NULL, NULL, &delay);
|
||
|
||
uint64_t end_send_bytes = 0;
|
||
struct ClientUnit *end_uint = client->uints;
|
||
while (end_uint != NULL) {
|
||
- end_send_bytes += end_uint->send_bytes;
|
||
+ end_send_bytes += end_uint->threadVolume.send_bytes;
|
||
end_uint = end_uint->next;
|
||
}
|
||
|
||
struct timeval end;
|
||
gettimeofday(&end, NULL);
|
||
- uint64_t end_time = (uint64_t)end.tv_sec * 1000 + (uint64_t)end.tv_usec / 1000;
|
||
-
|
||
+ uint64_t end_time = (uint64_t)end.tv_sec * TIMES_CONVERSION_RATE +
|
||
+ (uint64_t)end.tv_usec / TIMES_CONVERSION_RATE;
|
||
+
|
||
double bytes_sub = end_send_bytes > begin_send_bytes ? (double)(end_send_bytes - begin_send_bytes) : 0;
|
||
- double time_sub = end_time > begin_time ? (double)(end_time - begin_time) / 1000 : 0;
|
||
+ double time_sub = end_time > begin_time ? (double)(end_time - begin_time) / TIMES_CONVERSION_RATE : 0;
|
||
|
||
bytes_ps = bytes_sub / time_sub;
|
||
|
||
- if (bytes_ps < 1024) {
|
||
+ if (bytes_ps < KB) {
|
||
PRINT_CLIENT_DATAFLOW("[connect num]: %d, [send]: %.3f B/s", curr_connect, bytes_ps);
|
||
- } else if (bytes_ps < (1024 * 1024)) {
|
||
- PRINT_CLIENT_DATAFLOW("[connect num]: %d, [send]: %.3f KB/s", curr_connect, bytes_ps / 1024);
|
||
+ } else if (bytes_ps < MB) {
|
||
+ PRINT_CLIENT_DATAFLOW("[connect num]: %d, [send]: %.3f KB/s", curr_connect, bytes_ps / KB);
|
||
} else {
|
||
- PRINT_CLIENT_DATAFLOW("[connect num]: %d, [send]: %.3f MB/s", curr_connect, bytes_ps / (1024 * 1024));
|
||
+ PRINT_CLIENT_DATAFLOW("[connect num]: %d, [send]: %.3f MB/s", curr_connect, bytes_ps / MB);
|
||
+ }
|
||
+
|
||
+ if (client->loop) {
|
||
+ printf("\033[2A\033[120C\033[K\n");
|
||
+ return;
|
||
+ }
|
||
+ printf("\033[A\033[K");
|
||
+ }
|
||
+}
|
||
+
|
||
+static int32_t client_process_ask(struct ClientHandler *client_handler, struct ClientUnit *client_unit)
|
||
+{
|
||
+ // not support udp+v6 currently
|
||
+ if (strcmp(client_unit->domain, "udp") == 0 && client_unit->ip.addr_family == AF_INET6) {
|
||
+ return PROGRAM_OK;
|
||
+ }
|
||
+
|
||
+ int32_t client_ask_ret = client_ask(client_handler, client_unit);
|
||
+ if (client_ask_ret == PROGRAM_FAULT) {
|
||
+ --client_unit->curr_connect;
|
||
+ struct epoll_event ep_ev;
|
||
+ if (client_handler->fd > 0 && epoll_ctl(client_unit->epfd, EPOLL_CTL_DEL, (client_handler)->fd, &ep_ev) < 0) {
|
||
+ PRINT_ERROR("client can't delete socket '%d' to control epoll %d! ", (client_handler)->fd, errno);
|
||
+ return PROGRAM_FAULT;
|
||
}
|
||
+ } else if (client_ask_ret == PROGRAM_ABORT) {
|
||
+ --client_unit->curr_connect;
|
||
+ if (close((client_handler)->fd) < 0) {
|
||
+ PRINT_ERROR("client can't close the socket! ");
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ client_debug_print("client unit", "close", &client_unit->ip, client_unit->port, client_unit->debug);
|
||
+ } else {
|
||
+ client_unit->threadVolume.send_bytes += client_unit->pktlen;
|
||
+ client_handler->sendtime_interverl = 0;
|
||
+ client_debug_print("client unit", "send", &client_unit->ip, client_unit->port, client_unit->debug);
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static void client_get_thread_volume(struct Client *client, struct ThreadUintInfo *threadVolume)
|
||
+{
|
||
+ int index = 0;
|
||
+ struct ClientUnit *curUint = client->uints;
|
||
+ while (curUint != NULL && index < client->threadNum) {
|
||
+ threadVolume[index].send_bytes = curUint->threadVolume.send_bytes;
|
||
+
|
||
+ threadVolume[index].cur_connect_num = curUint->curr_connect;
|
||
+ threadVolume[index].thread_id = curUint->threadVolume.thread_id;
|
||
+ threadVolume[index].domain = curUint->threadVolume.domain;
|
||
+ threadVolume[index].ip_type_info = curUint->threadVolume.ip_type_info;
|
||
+ curUint = curUint->next;
|
||
+ index++;
|
||
+ }
|
||
+}
|
||
+
|
||
+void client_info_print_mixed(struct Client *client, struct ThreadUintInfo *threadVolume,
|
||
+ struct ThreadUintInfo *endThreadVolume)
|
||
+{
|
||
+ if (client->debug == true) {
|
||
+ return;
|
||
+ }
|
||
+ int32_t pthread_num = client->threadNum;
|
||
+ int32_t not_support_thread = 0;
|
||
+ struct timeval cur = {0};
|
||
+
|
||
+ gettimeofday(&cur, NULL);
|
||
+ uint64_t begin_time = (uint64_t)cur.tv_sec * TIMES_CONVERSION_RATE + (uint64_t)cur.tv_usec / TIMES_CONVERSION_RATE;
|
||
+
|
||
+ client_get_thread_volume(client, threadVolume);
|
||
+
|
||
+ struct timeval delay;
|
||
+ delay.tv_sec = 0;
|
||
+ delay.tv_usec = TERMINAL_REFRESH_MS * TIMES_CONVERSION_RATE;
|
||
+ select(0, NULL, NULL, NULL, &delay);
|
||
+
|
||
+ client_get_thread_volume(client, endThreadVolume);
|
||
+
|
||
+ gettimeofday(&cur, NULL);
|
||
+ uint64_t end_time = (uint64_t)cur.tv_sec * TIMES_CONVERSION_RATE + (uint64_t)cur.tv_usec / TIMES_CONVERSION_RATE;
|
||
+
|
||
+ for (int i = 0; i < pthread_num; i++) {
|
||
+ uint64_t begin_send_bytes = threadVolume[i].send_bytes;
|
||
+ uint64_t end_send_bytes = endThreadVolume[i].send_bytes;
|
||
+ pthread_t thread_id = endThreadVolume[i].thread_id;
|
||
+ uint32_t connect_num = endThreadVolume[i].cur_connect_num;
|
||
+ char *domain = endThreadVolume[i].domain;
|
||
+ char *ip_ver = endThreadVolume[i].ip_type_info;
|
||
+
|
||
+ if (thread_id == 0) {
|
||
+ not_support_thread++;
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ double bytes_sub = end_send_bytes > begin_send_bytes ? (double)(end_send_bytes - begin_send_bytes) : 0;
|
||
+ double time_sub = end_time > begin_time ? (double)(end_time - begin_time) / TIMES_CONVERSION_RATE : 0;
|
||
+ double bytes_ps = bytes_sub / time_sub;
|
||
+
|
||
+ if (bytes_ps < KB) {
|
||
+ PRINT_CLIENT_DATAFLOW("threadID=%-15lu, %s_%-9s [connect num]: %u, [send]: %.3f B/s",
|
||
+ thread_id, domain, ip_ver, connect_num, bytes_ps);
|
||
+ } else if (bytes_ps < MB) {
|
||
+ PRINT_CLIENT_DATAFLOW("threadID=%-15lu, %s_%-9s [connect num]: %u, [send]: %.3f kB/s",
|
||
+ thread_id, domain, ip_ver, connect_num, bytes_ps / KB);
|
||
+ } else {
|
||
+ PRINT_CLIENT_DATAFLOW("threadID=%-15lu, %s_%-9s [connect num]: %u, [send]: %.3f MB/s",
|
||
+ thread_id, domain, ip_ver, connect_num, bytes_ps / MB);
|
||
+ }
|
||
+ }
|
||
+ printf("\033[%dA\033[K", pthread_num - not_support_thread);
|
||
+}
|
||
+
|
||
+void loop_info_print()
|
||
+{
|
||
+ printf(" ");
|
||
+ if (strcmp(loopmod.model, "mum") == 0) {
|
||
+ sermum_info_print(loopmod.server_mum_info);
|
||
+ } else {
|
||
+ sermud_info_print(loopmod.server_mud_info);
|
||
}
|
||
}
|
||
|
||
// the single thread, client try to connect to server, register to epoll
|
||
-int32_t client_thread_try_connect(struct ClientHandler *client_handler, int32_t epoll_fd, in_addr_t ip, in_addr_t groupip, uint16_t port, uint16_t sport, const char *domain, const char *api)
|
||
+int32_t client_thread_try_connect(struct ClientHandler *client_handler, struct ClientUnit *client_unit)
|
||
{
|
||
- int32_t create_socket_and_connect_ret = create_socket_and_connect(&(client_handler->fd), ip, groupip, port, sport, domain, api);
|
||
+ int32_t create_socket_and_connect_ret = create_socket_and_connect(&(client_handler->fd), client_unit);
|
||
if (create_socket_and_connect_ret == PROGRAM_INPROGRESS) {
|
||
return PROGRAM_OK;
|
||
}
|
||
@@ -97,7 +254,7 @@ int32_t client_thread_try_connect(struct ClientHandler *client_handler, int32_t
|
||
// the single thread, client retry to connect to server, register to epoll
|
||
int32_t client_thread_retry_connect(struct ClientUnit *client_unit, struct ClientHandler *client_handler)
|
||
{
|
||
- int32_t clithd_try_cnntask_ret = client_thread_try_connect(client_handler, client_unit->epfd, client_unit->ip, client_unit->groupip, client_unit->port, client_unit->sport, client_unit->domain, client_unit->api);
|
||
+ int32_t clithd_try_cnntask_ret = client_thread_try_connect(client_handler, client_unit);
|
||
if (clithd_try_cnntask_ret < 0) {
|
||
if (clithd_try_cnntask_ret == PROGRAM_INPROGRESS) {
|
||
return PROGRAM_OK;
|
||
@@ -114,35 +271,27 @@ int32_t client_thread_retry_connect(struct ClientUnit *client_unit, struct Clien
|
||
|
||
++(client_unit->curr_connect);
|
||
|
||
- struct sockaddr_in server_addr;
|
||
- socklen_t server_addr_len = sizeof(server_addr);
|
||
+ sockaddr_t server_addr;
|
||
+ socklen_t server_addr_len = client_unit->ip.addr_family ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||
if (getpeername(client_handler->fd, (struct sockaddr *)&server_addr, &server_addr_len) < 0) {
|
||
PRINT_ERROR("client can't socket peername %d! ", errno);
|
||
return PROGRAM_FAULT;
|
||
}
|
||
- client_debug_print("client unit", "connect", server_addr.sin_addr.s_addr, server_addr.sin_port, client_unit->debug);
|
||
|
||
- int32_t client_ask_ret = client_ask(client_handler, client_unit->pktlen, client_unit->api, client_unit->domain, client_unit->groupip ? client_unit->groupip:client_unit->ip, client_unit->port);
|
||
- if (client_ask_ret == PROGRAM_FAULT) {
|
||
- --client_unit->curr_connect;
|
||
- struct epoll_event ep_ev;
|
||
- if (epoll_ctl(client_unit->epfd, EPOLL_CTL_DEL, client_handler->fd, &ep_ev) < 0) {
|
||
- PRINT_ERROR("client can't delete socket '%d' to control epoll %d! ", client_handler->fd, errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- } else if (client_ask_ret == PROGRAM_ABORT) {
|
||
- --client_unit->curr_connect;
|
||
- if (close(client_handler->fd) < 0) {
|
||
- PRINT_ERROR("client can't close the socket %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- client_debug_print("client unit", "close", server_addr.sin_addr.s_addr, server_addr.sin_port, client_unit->debug);
|
||
- } else {
|
||
- client_unit->send_bytes += client_unit->pktlen;
|
||
- client_debug_print("client unit", "send", server_addr.sin_addr.s_addr, server_addr.sin_port, client_unit->debug);
|
||
+ // sockaddr to ip, port
|
||
+ ip_addr_t remote_ip;
|
||
+ uint16_t remote_port = ((struct sockaddr_in*)&server_addr)->sin_port;
|
||
+ if (((struct sockaddr *)&server_addr)->sa_family == AF_INET) {
|
||
+ remote_ip.addr_family = AF_INET;
|
||
+ remote_ip.u_addr.ip4 = ((struct sockaddr_in *)&server_addr)->sin_addr;
|
||
+ } else if (((struct sockaddr *)&server_addr)->sa_family == AF_INET6) {
|
||
+ remote_ip.addr_family = AF_INET6;
|
||
+ remote_ip.u_addr.ip6 = ((struct sockaddr_in6 *)&server_addr)->sin6_addr;
|
||
}
|
||
|
||
- return PROGRAM_OK;
|
||
+ client_debug_print("client unit", "connect", &remote_ip, remote_port, client_unit->debug);
|
||
+
|
||
+ return client_process_ask(client_handler, client_unit);
|
||
}
|
||
|
||
// the single thread, client connects and gets epoll feature descriptors
|
||
@@ -162,7 +311,7 @@ int32_t client_thread_create_epfd_and_reg(struct ClientUnit *client_unit)
|
||
}
|
||
|
||
for (uint32_t i = 0; i < connect_num; ++i) {
|
||
- int32_t clithd_try_cnntask_ret = client_thread_try_connect(client_unit->handlers + i, client_unit->epfd, client_unit->ip, client_unit->groupip, client_unit->port, client_unit->sport, client_unit->domain, client_unit->api);
|
||
+ int32_t clithd_try_cnntask_ret = client_thread_try_connect(client_unit->handlers + i, client_unit);
|
||
if (clithd_try_cnntask_ret < 0) {
|
||
if (clithd_try_cnntask_ret == PROGRAM_INPROGRESS) {
|
||
continue;
|
||
@@ -179,26 +328,11 @@ int32_t client_thread_create_epfd_and_reg(struct ClientUnit *client_unit)
|
||
|
||
++(client_unit->curr_connect);
|
||
|
||
- client_debug_print("client unit", "connect", client_unit->ip, client_unit->port, client_unit->debug);
|
||
-
|
||
- int32_t client_ask_ret = client_ask(client_unit->handlers + i, client_unit->pktlen, client_unit->api, client_unit->domain, client_unit->groupip ? client_unit->groupip:client_unit->ip, client_unit->port);
|
||
- if (client_ask_ret == PROGRAM_FAULT) {
|
||
- --client_unit->curr_connect;
|
||
- struct epoll_event ep_ev;
|
||
- if (epoll_ctl(client_unit->epfd, EPOLL_CTL_DEL, (client_unit->handlers + i)->fd, &ep_ev) < 0) {
|
||
- PRINT_ERROR("client can't delete socket '%d' to control epoll %d! ", client_unit->epevs[i].data.fd, errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- } else if (client_ask_ret == PROGRAM_ABORT) {
|
||
- --client_unit->curr_connect;
|
||
- if (close((client_unit->handlers + i)->fd) < 0) {
|
||
- PRINT_ERROR("client can't close the socket! ");
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- client_debug_print("client unit", "close", client_unit->ip, client_unit->port, client_unit->debug);
|
||
- } else {
|
||
- client_unit->send_bytes += client_unit->pktlen;
|
||
- client_debug_print("client unit", "send", client_unit->ip, client_unit->port, client_unit->debug);
|
||
+ client_debug_print("client unit", "connect", &client_unit->ip, client_unit->port, client_unit->debug);
|
||
+
|
||
+ int32_t client_ask_ret = client_process_ask(client_unit->handlers + i, client_unit);
|
||
+ if (client_ask_ret != PROGRAM_OK) {
|
||
+ return client_ask_ret;
|
||
}
|
||
}
|
||
}
|
||
@@ -206,15 +340,97 @@ int32_t client_thread_create_epfd_and_reg(struct ClientUnit *client_unit)
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
+
|
||
+static int32_t clithd_proc_epevs_epollout(struct epoll_event *curr_epev, struct ClientUnit *client_unit)
|
||
+{
|
||
+ int32_t connect_error = 0;
|
||
+ socklen_t connect_error_len = sizeof(connect_error);
|
||
+ struct ClientHandler *client_handler = (struct ClientHandler *)curr_epev->data.ptr;
|
||
+ if (getsockopt(client_handler->fd, SOL_SOCKET, SO_ERROR, (void *)(&connect_error), &connect_error_len) < 0) {
|
||
+ PRINT_ERROR("client can't get socket option %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ if (connect_error < 0) {
|
||
+ if (connect_error == ETIMEDOUT) {
|
||
+ if (client_thread_retry_connect(client_unit, client_handler) < 0) {
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+ }
|
||
+ PRINT_ERROR("client connect error %d! ", connect_error);
|
||
+ return PROGRAM_FAULT;
|
||
+ } else {
|
||
+ ++(client_unit->curr_connect);
|
||
+
|
||
+ sockaddr_t server_addr;
|
||
+ socklen_t server_addr_len =
|
||
+ client_unit->ip.addr_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||
+ if (getpeername(client_handler->fd, (struct sockaddr *)&server_addr, &server_addr_len) < 0) {
|
||
+ PRINT_ERROR("client can't socket peername %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+
|
||
+ // sockaddr to ip, port
|
||
+ ip_addr_t remote_ip;
|
||
+ uint16_t remote_port = ((struct sockaddr_in *)&server_addr)->sin_port;
|
||
+ if (((struct sockaddr *)&server_addr)->sa_family == AF_INET) {
|
||
+ remote_ip.addr_family = AF_INET;
|
||
+ remote_ip.u_addr.ip4 = ((struct sockaddr_in *)&server_addr)->sin_addr;
|
||
+ } else if (((struct sockaddr *)&server_addr)->sa_family == AF_INET6) {
|
||
+ remote_ip.addr_family = AF_INET6;
|
||
+ remote_ip.u_addr.ip6 = ((struct sockaddr_in6 *)&server_addr)->sin6_addr;
|
||
+ }
|
||
+
|
||
+ client_debug_print("client unit", "connect", &remote_ip, remote_port, client_unit->debug);
|
||
+
|
||
+ int32_t client_ask_ret = client_process_ask(client_handler, client_unit);
|
||
+ if (client_ask_ret != PROGRAM_OK) {
|
||
+ return client_ask_ret;
|
||
+ }
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static int32_t clithd_proc_epevs_epollin(struct epoll_event *curr_epev, struct ClientUnit *client_unit)
|
||
+{
|
||
+ ip_addr_t *chkans_ip = client_unit->protocol_type_mode == UDP_MULTICAST ? &client_unit->groupip : &client_unit->ip;
|
||
+ int32_t client_chkans_ret = client_chkans((struct ClientHandler *)curr_epev->data.ptr, client_unit->pktlen,
|
||
+ client_unit->verify, client_unit->api, client_unit->domain, chkans_ip);
|
||
+ struct ClientHandler *client_handler = (struct ClientHandler *)curr_epev->data.ptr;
|
||
+ int32_t fd = client_handler->fd;
|
||
+ if (client_chkans_ret == PROGRAM_FAULT) {
|
||
+ --client_unit->curr_connect;
|
||
+ struct epoll_event ep_ev;
|
||
+ if (epoll_ctl(client_unit->epfd, EPOLL_CTL_DEL, fd, &ep_ev) < 0) {
|
||
+ PRINT_ERROR("client can't delete socket '%d' to control epoll %d! ", fd, errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ } else if (client_chkans_ret == PROGRAM_ABORT) {
|
||
+ --client_unit->curr_connect;
|
||
+ if (close(fd) < 0) {
|
||
+ PRINT_ERROR("client can't close the socket %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ client_debug_print("client unit", "close", &client_unit->ip, client_unit->port, client_unit->debug);
|
||
+ } else {
|
||
+ client_unit->threadVolume.send_bytes += client_unit->pktlen;
|
||
+ client_handler->sendtime_interverl = 0;
|
||
+ client_debug_print("client unit", "receive", &client_unit->ip, client_unit->port, client_unit->debug);
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
// the single thread, client processes epoll events
|
||
int32_t clithd_proc_epevs(struct ClientUnit *client_unit)
|
||
{
|
||
int32_t epoll_nfds = epoll_wait(client_unit->epfd, client_unit->epevs, CLIENT_EPOLL_SIZE_MAX, CLIENT_EPOLL_WAIT_TIMEOUT);
|
||
+ int ret = 0;
|
||
if (epoll_nfds < 0) {
|
||
PRINT_ERROR("client epoll wait error %d! ", errno);
|
||
return PROGRAM_FAULT;
|
||
}
|
||
|
||
+
|
||
for (int32_t i = 0; i < epoll_nfds; ++i) {
|
||
struct epoll_event *curr_epev = client_unit->epevs + i;
|
||
|
||
@@ -222,76 +438,17 @@ int32_t clithd_proc_epevs(struct ClientUnit *client_unit)
|
||
PRINT_ERROR("client epoll wait error! %d", curr_epev->events);
|
||
return PROGRAM_FAULT;
|
||
} else if (curr_epev->events == EPOLLOUT) {
|
||
- int32_t connect_error = 0;
|
||
- socklen_t connect_error_len = sizeof(connect_error);
|
||
- struct ClientHandler *client_handler = (struct ClientHandler *)curr_epev->data.ptr;
|
||
- if (getsockopt(client_handler->fd, SOL_SOCKET, SO_ERROR, (void *)(&connect_error), &connect_error_len) < 0) {
|
||
- PRINT_ERROR("client can't get socket option %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- if (connect_error < 0) {
|
||
- if (connect_error == ETIMEDOUT) {
|
||
- if (client_thread_retry_connect(client_unit, client_handler) < 0) {
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- continue;
|
||
- }
|
||
- PRINT_ERROR("client connect error %d! ", connect_error);
|
||
- return PROGRAM_FAULT;
|
||
- } else {
|
||
- ++(client_unit->curr_connect);
|
||
-
|
||
- struct sockaddr_in server_addr;
|
||
- socklen_t server_addr_len = sizeof(server_addr);
|
||
- if (getpeername(client_handler->fd, (struct sockaddr *)&server_addr, &server_addr_len) < 0) {
|
||
- PRINT_ERROR("client can't socket peername %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- client_debug_print("client unit", "connect", server_addr.sin_addr.s_addr, server_addr.sin_port, client_unit->debug);
|
||
-
|
||
- int32_t client_ask_ret = client_ask(client_handler, client_unit->pktlen, client_unit->api, client_unit->domain, client_unit->groupip ? client_unit->groupip:client_unit->ip, client_unit->port);
|
||
- if (client_ask_ret == PROGRAM_FAULT) {
|
||
- --client_unit->curr_connect;
|
||
- struct epoll_event ep_ev;
|
||
- if (epoll_ctl(client_unit->epfd, EPOLL_CTL_DEL, curr_epev->data.fd, &ep_ev) < 0) {
|
||
- PRINT_ERROR("client can't delete socket '%d' to control epoll %d! ", curr_epev->data.fd, errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- } else if (client_ask_ret == PROGRAM_ABORT) {
|
||
- --client_unit->curr_connect;
|
||
- if (close(curr_epev->data.fd) < 0) {
|
||
- PRINT_ERROR("client can't close the socket! ");
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- client_debug_print("client unit", "close", server_addr.sin_addr.s_addr, server_addr.sin_port, client_unit->debug);
|
||
- } else {
|
||
- client_unit->send_bytes += client_unit->pktlen;
|
||
- client_debug_print("client unit", "send", server_addr.sin_addr.s_addr, server_addr.sin_port, client_unit->debug);
|
||
- }
|
||
+ ret = clithd_proc_epevs_epollout(curr_epev, client_unit);
|
||
+ if (ret != PROGRAM_OK) {
|
||
+ return ret;
|
||
}
|
||
} else if (curr_epev->events == EPOLLIN) {
|
||
- int32_t client_chkans_ret = client_chkans((struct ClientHandler *)curr_epev->data.ptr, client_unit->pktlen, client_unit->verify, client_unit->api, client_unit->domain, client_unit->groupip ? client_unit->groupip:client_unit->ip);
|
||
- if (client_chkans_ret == PROGRAM_FAULT) {
|
||
- --client_unit->curr_connect;
|
||
- struct epoll_event ep_ev;
|
||
- if (epoll_ctl(client_unit->epfd, EPOLL_CTL_DEL, curr_epev->data.fd, &ep_ev) < 0) {
|
||
- PRINT_ERROR("client can't delete socket '%d' to control epoll %d! ", curr_epev->data.fd, errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- } else if (client_chkans_ret == PROGRAM_ABORT) {
|
||
- --client_unit->curr_connect;
|
||
- if (close(curr_epev->data.fd) < 0) {
|
||
- PRINT_ERROR("client can't close the socket %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- client_debug_print("client unit", "close", client_unit->ip, client_unit->port, client_unit->debug);
|
||
- } else {
|
||
- client_unit->send_bytes += client_unit->pktlen;
|
||
- client_debug_print("client unit", "receive", client_unit->ip, client_unit->port, client_unit->debug);
|
||
+ ret = clithd_proc_epevs_epollin(curr_epev, client_unit);
|
||
+ if (ret != PROGRAM_OK) {
|
||
+ return ret;
|
||
}
|
||
}
|
||
}
|
||
-
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
@@ -299,6 +456,17 @@ int32_t clithd_proc_epevs(struct ClientUnit *client_unit)
|
||
void *client_s_create_and_run(void *arg)
|
||
{
|
||
struct ClientUnit *client_unit = (struct ClientUnit *)arg;
|
||
+ // update domain ip info.
|
||
+ client_get_domain_ipversion(client_unit->protocol_type_mode, client_unit);
|
||
+
|
||
+ if (client_unit->protocol_type_mode == UDP_MULTICAST) {
|
||
+ client_unit->threadVolume.ip_type_info = IPV4_MULTICAST;
|
||
+ } else {
|
||
+ client_unit->threadVolume.ip_type_info = (client_unit->ip.addr_family == AF_INET ? IPV4_STR : IPV6_STR);
|
||
+ }
|
||
+ client_unit->threadVolume.thread_id = pthread_self();
|
||
+
|
||
+ client_unit->threadVolume.domain = client_unit->domain;
|
||
|
||
if (client_thread_create_epfd_and_reg(client_unit) < 0) {
|
||
exit(PROGRAM_FAULT);
|
||
@@ -316,6 +484,42 @@ void *client_s_create_and_run(void *arg)
|
||
return (void *)PROGRAM_OK;
|
||
}
|
||
|
||
+// prase the specific supported TCP IP types by cfg_mode.
|
||
+static void client_get_protocol_type_by_cfgmode(uint8_t mode, int32_t *support_type_array, int32_t buff_len,
|
||
+ int32_t *actual_len)
|
||
+{
|
||
+ int32_t index = 0;
|
||
+ for (uint8_t i = V4_TCP; i < PROTOCOL_MODE_MAX; i++) {
|
||
+ if (i == V6_UDP) {
|
||
+ continue;
|
||
+ }
|
||
+ if (getbit_num(mode, i) == 1) {
|
||
+ if (index >= buff_len) {
|
||
+ PRINT_ERROR("index is over, index =%d", index);
|
||
+ return;
|
||
+ }
|
||
+ support_type_array[index] = i;
|
||
+ index++;
|
||
+ }
|
||
+ }
|
||
+ *actual_len = index;
|
||
+}
|
||
+
|
||
+static void client_get_domain_ipversion(uint8_t protocol_type, struct ClientUnit *client_unit)
|
||
+{
|
||
+ client_unit->domain = g_cfgmode_map[protocol_type].domain;
|
||
+ client_unit->ip.addr_family = g_cfgmode_map[protocol_type].ip_family;
|
||
+}
|
||
+
|
||
+static void alarm_init()
|
||
+{
|
||
+ struct sigaction sa;
|
||
+ memset(&sa, 0, sizeof(sa));
|
||
+ sa.sa_handler = &timer_handle;
|
||
+ sigaction(SIGALRM, &sa, NULL);
|
||
+ alarm(TIME_SCAN_INTERVAL);
|
||
+}
|
||
+
|
||
// create client and run
|
||
int32_t client_create_and_run(struct ProgramParams *params)
|
||
{
|
||
@@ -323,16 +527,44 @@ int32_t client_create_and_run(struct ProgramParams *params)
|
||
const uint32_t thread_num = params->thread_num;
|
||
pthread_t *tids = (pthread_t *)malloc(thread_num * sizeof(pthread_t));
|
||
struct Client *client = (struct Client *)malloc(sizeof(struct Client));
|
||
+ g_client_begin = client;
|
||
+ client->threadNum = thread_num;
|
||
+
|
||
struct ClientUnit *client_unit = (struct ClientUnit *)malloc(sizeof(struct ClientUnit));
|
||
+ memset_s(client_unit, sizeof(struct ClientUnit), 0, sizeof(struct ClientUnit));
|
||
+ int32_t protocol_support_array[PROTOCOL_MODE_MAX] = {0};
|
||
+ int32_t number_of_support_type = 1;
|
||
|
||
if (pthread_mutex_init(&client_debug_mutex, NULL) < 0) {
|
||
PRINT_ERROR("client can't init posix mutex %d! ", errno);
|
||
return PROGRAM_FAULT;
|
||
}
|
||
|
||
+ bool v4_cfg_flag = (strcmp(params->ip, PARAM_DEFAULT_IP) != 0);
|
||
+ bool v6_cfg_flag = (strcmp(params->ipv6, PARAM_DEFAULT_IP_V6) != 0);
|
||
+ bool multcact_cfg_flag = (strcmp(params->groupip, PARAM_DEFAULT_GROUPIP) != 0);
|
||
+
|
||
+ bool mixed_mode_flag = false;
|
||
+ if ((strchr(params->domain, ',') != NULL) || (v4_cfg_flag && v6_cfg_flag) ||
|
||
+ (multcact_cfg_flag && (v4_cfg_flag || v6_cfg_flag))) {
|
||
+ mixed_mode_flag = true;
|
||
+ }
|
||
+
|
||
client->uints = client_unit;
|
||
client->debug = params->debug;
|
||
|
||
+ uint8_t protocol_type_mode = program_get_protocol_mode_by_domain_ip(params->domain, params->ip, params->ipv6,
|
||
+ params->groupip);
|
||
+
|
||
+ client_get_protocol_type_by_cfgmode(protocol_type_mode, protocol_support_array, PROTOCOL_MODE_MAX,
|
||
+ &number_of_support_type);
|
||
+
|
||
+ uint32_t port = UNIX_TCP_PORT_MIN;
|
||
+ uint32_t sport = 0;
|
||
+ uint32_t sp = 0;
|
||
+
|
||
+ alarm_init();
|
||
+
|
||
for (uint32_t i = 0; i < thread_num; ++i) {
|
||
client_unit->handlers = (struct ClientHandler *)malloc(connect_num * sizeof(struct ClientHandler));
|
||
for (uint32_t j = 0; j < connect_num; ++j) {
|
||
@@ -342,13 +574,42 @@ int32_t client_create_and_run(struct ProgramParams *params)
|
||
client_unit->epfd = -1;
|
||
client_unit->epevs = (struct epoll_event *)malloc(CLIENT_EPOLL_SIZE_MAX * sizeof(struct epoll_event));
|
||
client_unit->curr_connect = 0;
|
||
- client_unit->send_bytes = 0;
|
||
- client_unit->ip = inet_addr(params->ip);
|
||
- client_unit->groupip = inet_addr(params->groupip);
|
||
- client_unit->port = htons(params->port);
|
||
- client_unit->sport = htons(params->sport);
|
||
+
|
||
+ client_unit->threadVolume.cur_connect_num = 0;
|
||
+ client_unit->threadVolume.thread_id = 0;
|
||
+ client_unit->threadVolume.send_bytes = 0;
|
||
+ client_unit->threadVolume.ip_type_info = INVAILD_STR;
|
||
+ client_unit->threadVolume.domain = INVAILD_STR;
|
||
+
|
||
+ client_unit->ip.addr_family = params->addr_family;
|
||
+ inet_pton(AF_INET, params->ip, &client_unit->ip.u_addr.ip4);
|
||
+ inet_pton(AF_INET6, params->ipv6, &client_unit->ip.u_addr.ip6);
|
||
+ client_unit->groupip.addr_family = AF_INET;
|
||
+ inet_pton(AF_INET, params->groupip, &client_unit->groupip.u_addr);
|
||
+ client_unit->groupip_interface.addr_family = params->addr_family;
|
||
+ inet_pton(AF_INET, params->groupip_interface, &client_unit->groupip_interface.u_addr);
|
||
+
|
||
+ /* loop to set ports to each client_units */
|
||
+ while (!((params->port)[port])) {
|
||
+ port = (port + 1) % UNIX_TCP_PORT_MAX;
|
||
+ }
|
||
+ client_unit->port = htons(port++);
|
||
+
|
||
+ sp = sport;
|
||
+ sport++;
|
||
+ while (!((params->sport)[sport]) && (sport != sp)) {
|
||
+ sport = (sport + 1) % UNIX_TCP_PORT_MAX;
|
||
+ }
|
||
+
|
||
+ client_unit->sport = htons(sport);
|
||
client_unit->connect_num = params->connect_num;
|
||
client_unit->pktlen = params->pktlen;
|
||
+ if (strcmp(params->as, "loop") == 0) {
|
||
+ client_unit->loop = 1;
|
||
+ } else {
|
||
+ client_unit->loop = 0;
|
||
+ }
|
||
+
|
||
client_unit->verify = params->verify;
|
||
client_unit->domain = params->domain;
|
||
client_unit->api = params->api;
|
||
@@ -357,6 +618,16 @@ int32_t client_create_and_run(struct ProgramParams *params)
|
||
client_unit->next = (struct ClientUnit *)malloc(sizeof(struct ClientUnit));
|
||
memset_s(client_unit->next, sizeof(struct ClientUnit), 0, sizeof(struct ClientUnit));
|
||
|
||
+ if (number_of_support_type > 0) {
|
||
+ int32_t index = i % number_of_support_type;
|
||
+ client_unit->protocol_type_mode = protocol_support_array[index];
|
||
+ }
|
||
+ if (client_unit->protocol_type_mode == V4_UDP || client_unit->protocol_type_mode == V6_UDP ||
|
||
+ client_unit->protocol_type_mode == UDP_MULTICAST) {
|
||
+ client_unit->pktlen = params->pktlen > UDP_PKTLEN_MAX ? UDP_PKTLEN_MAX : params->pktlen;
|
||
+ } else {
|
||
+ client_unit->pktlen = params->pktlen;
|
||
+ }
|
||
if (pthread_create((tids + i), NULL, client_s_create_and_run, client_unit) < 0) {
|
||
PRINT_ERROR("client can't create thread of poisx %d! ", errno);
|
||
return PROGRAM_FAULT;
|
||
@@ -367,9 +638,34 @@ int32_t client_create_and_run(struct ProgramParams *params)
|
||
if (client->debug == false) {
|
||
printf("[program informations]: \n\n");
|
||
}
|
||
+
|
||
+ struct ThreadUintInfo *beginVolume = (struct ThreadUintInfo *)malloc(thread_num * sizeof(struct ThreadUintInfo));
|
||
+ if (beginVolume == NULL) {
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ memset_s(beginVolume, thread_num * sizeof(struct ThreadUintInfo), 0, thread_num * sizeof(struct ThreadUintInfo));
|
||
+ struct ThreadUintInfo *endVolume = (struct ThreadUintInfo *)malloc(thread_num * sizeof(struct ThreadUintInfo));
|
||
+ if (endVolume == NULL) {
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ memset_s(endVolume, thread_num * sizeof(struct ThreadUintInfo), 0, thread_num * sizeof(struct ThreadUintInfo));
|
||
+
|
||
+ if (strcmp(params->as, "loop") == 0) {
|
||
+ client->loop = true;
|
||
+ }
|
||
+
|
||
while (true) {
|
||
- client_info_print(client);
|
||
+ if (strcmp(params->as, "loop") == 0) {
|
||
+ loop_info_print();
|
||
+ }
|
||
+ if (mixed_mode_flag == true) {
|
||
+ client_info_print_mixed(client, beginVolume, endVolume);
|
||
+ } else {
|
||
+ client_info_print(client);
|
||
+ }
|
||
}
|
||
+ free(beginVolume);
|
||
+ free(endVolume);
|
||
|
||
pthread_mutex_destroy(&client_debug_mutex);
|
||
|
||
diff --git a/examples/src/parameter.c b/examples/src/parameter.c
|
||
index 1bb6858..7f519e7 100644
|
||
--- a/examples/src/parameter.c
|
||
+++ b/examples/src/parameter.c
|
||
@@ -13,6 +13,8 @@
|
||
|
||
#include "parameter.h"
|
||
|
||
+static int32_t g_inject_delay[INJECT_DELAY_MAX] = {0};
|
||
+static int32_t g_inject_skip[INJECT_SKIP_MAX];
|
||
|
||
// program short options
|
||
const char prog_short_opts[] = \
|
||
@@ -30,9 +32,11 @@ const char prog_short_opts[] = \
|
||
"r" // ringpmd
|
||
"d" // debug
|
||
"h" // help
|
||
- "E" // epollcreate
|
||
- "C" // accept
|
||
+ "E:" // epollcreate
|
||
+ "C:" // accept
|
||
"g:" // group address
|
||
+ "k:" // tcp keep_alive
|
||
+ "I:" // fault inject
|
||
;
|
||
|
||
// program long options
|
||
@@ -55,17 +59,72 @@ const struct ProgramOption prog_long_opts[] = \
|
||
{PARAM_NAME_EPOLLCREATE, REQUIRED_ARGUMETN, NULL, PARAM_NUM_EPOLLCREATE},
|
||
{PARAM_NAME_ACCEPT, REQUIRED_ARGUMETN, NULL, PARAM_NUM_ACCEPT},
|
||
{PARAM_NAME_GROUPIP, REQUIRED_ARGUMETN, NULL, PARAM_NUM_GROUPIP},
|
||
+ {PARAM_NAME_KEEPALIVE, REQUIRED_ARGUMETN, NULL, PARAM_NUM_KEEPALIVE},
|
||
+ {PARAM_NAME_INJECT, REQUIRED_ARGUMETN, NULL, PARAM_NUM_INJECT},
|
||
};
|
||
|
||
|
||
// get long options
|
||
int getopt_long(int argc, char * const argv[], const char *optstring, const struct ProgramOption *long_opts, int *long_idx);
|
||
+// index [0,7)
|
||
+uint8_t getbit_num(uint8_t mode, uint8_t index)
|
||
+{
|
||
+ return (mode & ((uint8_t)1 << index)) != 0;
|
||
+}
|
||
+
|
||
+uint8_t setbitnum_on(uint8_t mode, uint8_t index)
|
||
+{
|
||
+ mode |= ((uint8_t)1 << index);
|
||
+ return mode;
|
||
+}
|
||
+
|
||
+uint8_t setbitnum_off(uint8_t mode, uint8_t index)
|
||
+{
|
||
+ mode &= ~((uint8_t)1 << index);
|
||
+ return mode;
|
||
+}
|
||
+
|
||
+static uint8_t program_set_protocol_mode(uint8_t protocol_mode, char *ipv4, char *ipv6, uint8_t index_v4,
|
||
+ uint8_t index_v6)
|
||
+{
|
||
+ uint8_t protocol_mode_temp = protocol_mode;
|
||
+ if (strcmp(ipv4, PARAM_DEFAULT_IP) != 0) {
|
||
+ protocol_mode_temp = setbitnum_on(protocol_mode_temp, index_v4);
|
||
+ }
|
||
+ if (strcmp(ipv6, PARAM_DEFAULT_IP_V6) != 0) {
|
||
+ protocol_mode_temp = setbitnum_on(protocol_mode_temp, index_v6);
|
||
+ }
|
||
+ return protocol_mode_temp;
|
||
+}
|
||
+
|
||
+uint8_t program_get_protocol_mode_by_domain_ip(char* domain, char* ipv4, char* ipv6, char* groupip)
|
||
+{
|
||
+ uint8_t protocol_mode = 0;
|
||
+ char *cur_ptr = NULL;
|
||
+ char *next_Ptr = NULL;
|
||
+ cur_ptr = strtok_s(domain, ",", &next_Ptr);
|
||
+ while (cur_ptr) {
|
||
+ if (strcmp(cur_ptr, "tcp") == 0) {
|
||
+ protocol_mode = program_set_protocol_mode(protocol_mode, ipv4, ipv6, V4_TCP, V6_TCP);
|
||
+ } else if (strcmp(cur_ptr, "udp") == 0) {
|
||
+ protocol_mode = program_set_protocol_mode(protocol_mode, ipv4, ipv6, V4_UDP, V6_UDP);
|
||
+ } else if (strcmp(cur_ptr, "unix") == 0) {
|
||
+ protocol_mode = setbitnum_on(protocol_mode, UNIX);
|
||
+ }
|
||
+ cur_ptr = strtok_s(NULL, ",", &next_Ptr);
|
||
+ }
|
||
+
|
||
+ if (strcmp(groupip, PARAM_DEFAULT_GROUPIP) != 0) {
|
||
+ protocol_mode = setbitnum_on(protocol_mode, UDP_MULTICAST);
|
||
+ }
|
||
|
||
+ return protocol_mode;
|
||
+}
|
||
|
||
// set `as` parameter
|
||
void program_param_parse_as(struct ProgramParams *params)
|
||
{
|
||
- if (strcmp(optarg, "server") == 0 || strcmp(optarg, "client") == 0) {
|
||
+ if (strcmp(optarg, "server") == 0 || strcmp(optarg, "client") == 0 || strcmp(optarg, "loop") == 0) {
|
||
params->as = optarg;
|
||
} else {
|
||
PRINT_ERROR("illigal argument -- %s \n", optarg);
|
||
@@ -73,40 +132,113 @@ void program_param_parse_as(struct ProgramParams *params)
|
||
}
|
||
}
|
||
|
||
-// set `ip` parameter
|
||
-void program_param_parse_ip(struct ProgramParams *params)
|
||
+bool ip_is_v6(const char *cp)
|
||
+{
|
||
+ if (cp != NULL) {
|
||
+ const char *c;
|
||
+ for (c = cp; *c != 0; c++) {
|
||
+ if (*c == ':') {
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+static bool program_ipv4_check(char *ipv4)
|
||
{
|
||
- if (inet_addr(optarg) != INADDR_NONE) {
|
||
- params->ip = optarg;
|
||
+ in_addr_t ip = ntohl(inet_addr(ipv4));
|
||
+ if (ip == INADDR_NONE) {
|
||
+ PRINT_ERROR("illigal argument -- %s \n", ipv4);
|
||
+ return false;
|
||
+ }
|
||
+ if ((ip >= ntohl(inet_addr("1.0.0.1")) && ip <= ntohl(inet_addr("126.255.255.254"))) ||
|
||
+ (ip >= ntohl(inet_addr("127.0.0.1")) && ip <= ntohl(inet_addr("127.255.255.254"))) ||
|
||
+ (ip >= ntohl(inet_addr("128.0.0.1")) && ip <= ntohl(inet_addr("191.255.255.254"))) ||
|
||
+ (ip >= ntohl(inet_addr("192.0.0.1")) && ip <= ntohl(inet_addr("223.255.255.254"))) ||
|
||
+ (ip >= ntohl(inet_addr("224.0.0.1")) && ip <= ntohl(inet_addr("224.255.255.255"))) ) { // Broadcast IP
|
||
+ return true;
|
||
+ }
|
||
+
|
||
+ PRINT_ERROR("illigal argument -- %s \n", ipv4);
|
||
+ return false;
|
||
+}
|
||
+
|
||
+static void program_param_parse_ipv4_addr(char* v4ip_addr, struct ProgramParams *params)
|
||
+{
|
||
+ struct in6_addr ip_tmp;
|
||
+ params->addr_family = AF_INET;
|
||
+ if (inet_pton(params->addr_family, v4ip_addr, &ip_tmp) > 0 && program_ipv4_check(v4ip_addr) == true) {
|
||
+ params->ip = v4ip_addr;
|
||
} else {
|
||
- PRINT_ERROR("illigal argument -- %s \n", optarg);
|
||
+ PRINT_ERROR("illegal ipv4 addr -- %s \n", v4ip_addr);
|
||
exit(PROGRAM_ABORT);
|
||
}
|
||
}
|
||
|
||
-// set `port` parameter
|
||
-void program_param_parse_port(struct ProgramParams *params)
|
||
+static void program_param_parse_ipv6_addr(char* v6ip_add, struct ProgramParams *params)
|
||
{
|
||
- int32_t port_arg = strtol(optarg, NULL, 0);
|
||
- printf("%d\n", port_arg);
|
||
- if (CHECK_VAL_RANGE(port_arg, UNIX_TCP_PORT_MIN, UNIX_TCP_PORT_MAX) == true) {
|
||
- params->port = (uint32_t)port_arg;
|
||
+ struct in6_addr ip_tmp;
|
||
+ params->addr_family = AF_INET6;
|
||
+ if (inet_pton(AF_INET6, v6ip_add, &ip_tmp) > 0) {
|
||
+ params->ipv6 = v6ip_add;
|
||
} else {
|
||
- PRINT_ERROR("illigal argument -- %s \n", optarg);
|
||
+ PRINT_ERROR("illegal ipv6 addr -- %s \n", v6ip_add);
|
||
exit(PROGRAM_ABORT);
|
||
}
|
||
}
|
||
+// set `ip` parameter,支持同时配置 ipv4 和 ipv6 地址,格式为 ipv4,ipv6
|
||
+void program_param_parse_ip(struct ProgramParams *params)
|
||
+{
|
||
+ char *cur_ptr = NULL;
|
||
+ char *next_ptr = NULL;
|
||
+
|
||
+ cur_ptr = strtok_s(optarg, ",", &next_ptr);
|
||
+ while (cur_ptr) {
|
||
+ if (ip_is_v6(cur_ptr)) {
|
||
+ program_param_parse_ipv6_addr(cur_ptr, params);
|
||
+ } else {
|
||
+ program_param_parse_ipv4_addr(cur_ptr, params);
|
||
+ }
|
||
+ cur_ptr = strtok_s(NULL, ",", &next_ptr);
|
||
+ }
|
||
+}
|
||
+
|
||
+// set `port` parameter
|
||
+void program_param_parse_port(struct ProgramParams *params)
|
||
+{
|
||
+ char* port_list = optarg;
|
||
+ char* token = NULL;
|
||
+ int32_t port_arg = 0;
|
||
+ params->port[PARAM_DEFAULT_PORT] = 0;
|
||
+
|
||
+ while ((token = strtok_r(port_list, ",", &port_list))) {
|
||
+ port_arg = strtol(token, NULL, 0);
|
||
+ if (CHECK_VAL_RANGE(port_arg, UNIX_TCP_PORT_MIN, UNIX_TCP_PORT_MAX) == true) {
|
||
+ params->port[port_arg] = 1;
|
||
+ } else {
|
||
+ PRINT_ERROR("illigal argument -- %s \n", optarg);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+ }
|
||
+}
|
||
|
||
// set `sport` parameter
|
||
void program_param_parse_sport(struct ProgramParams *params)
|
||
{
|
||
- int32_t sport_arg = strtol(optarg, NULL, 0);
|
||
- printf("%d\n", sport_arg);
|
||
- if (CHECK_VAL_RANGE(sport_arg, UNIX_TCP_PORT_MIN, UNIX_TCP_PORT_MAX) == true) {
|
||
- params->sport = (uint32_t)sport_arg;
|
||
- } else {
|
||
- PRINT_ERROR("illigal argument -- %s \n", optarg);
|
||
- exit(PROGRAM_ABORT);
|
||
+ char* port_list = optarg;
|
||
+ char* token = NULL;
|
||
+ int32_t port_arg = 0;
|
||
+
|
||
+ while ((token = strtok_r(port_list, ",", &port_list))) {
|
||
+ port_arg = strtol(token, NULL, 0);
|
||
+ if (CHECK_VAL_RANGE(port_arg, UNIX_TCP_PORT_MIN, UNIX_TCP_PORT_MAX) == true) {
|
||
+ params->sport[port_arg] = 1;
|
||
+ } else {
|
||
+ PRINT_ERROR("illigal argument -- %s \n", optarg);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
}
|
||
}
|
||
|
||
@@ -148,12 +280,23 @@ void program_param_parse_threadnum(struct ProgramParams *params)
|
||
// set `domain` parameter
|
||
void program_param_parse_domain(struct ProgramParams *params)
|
||
{
|
||
- if (strcmp(optarg, "unix") == 0 || strcmp(optarg, "tcp") == 0 || strcmp(optarg, "udp") == 0) {
|
||
- params->domain = optarg;
|
||
- } else {
|
||
- PRINT_ERROR("illigal argument -- %s \n", optarg);
|
||
+ char temp[100] = {0};
|
||
+ int32_t ret = strcpy_s(temp, sizeof(temp) / sizeof(char), optarg);
|
||
+ if (ret != 0) {
|
||
+ PRINT_ERROR("strcpy_s fail ret=%d \n", ret);
|
||
exit(PROGRAM_ABORT);
|
||
}
|
||
+ char *cur_ptr = temp;
|
||
+ char *next_ptr = NULL;
|
||
+ cur_ptr = strtok_s(cur_ptr, ",", &next_ptr);
|
||
+ while (cur_ptr) {
|
||
+ if (strcmp(cur_ptr, "tcp") != 0 && strcmp(cur_ptr, "udp") != 0 && strcmp(cur_ptr, "unix") != 0) {
|
||
+ PRINT_ERROR("illigal argument -- %s \n", cur_ptr);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+ cur_ptr = strtok_s(NULL, ",", &next_ptr);
|
||
+ }
|
||
+ params->domain = optarg;
|
||
}
|
||
|
||
// set `api` parameter
|
||
@@ -174,6 +317,9 @@ void program_param_parse_pktlen(struct ProgramParams *params)
|
||
int32_t pktlen_arg = strtol(optarg, NULL, 0);
|
||
if (CHECK_VAL_RANGE(pktlen_arg, MESSAGE_PKTLEN_MIN, MESSAGE_PKTLEN_MAX) == true) {
|
||
params->pktlen = (uint32_t)pktlen_arg;
|
||
+ if (strstr(params->domain, "udp") && params->pktlen > UDP_PKTLEN_MAX) {
|
||
+ PRINT_WARNNING("udp message too long, change it to %d \n", UDP_PKTLEN_MAX);
|
||
+ }
|
||
} else {
|
||
PRINT_ERROR("illigal argument -- %s \n", optarg);
|
||
exit(PROGRAM_ABORT);
|
||
@@ -202,16 +348,196 @@ void program_param_parse_accept(struct ProgramParams *params)
|
||
}
|
||
}
|
||
|
||
+// set `tcp_keepalive_idle` parameter
|
||
+void program_param_parse_keepalive(struct ProgramParams *params)
|
||
+{
|
||
+ char *token = NULL;
|
||
+ char *next_token = NULL;
|
||
+ token = strtok_s(optarg, ",", &next_token);
|
||
+ if (token == NULL) {
|
||
+ PRINT_ERROR("parse keep_alive idle null, illigal argument(%s) \n", optarg);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+
|
||
+ int32_t keep_alive_idle = strtol(optarg, NULL, 0);
|
||
+ if (keep_alive_idle > 0 && keep_alive_idle <= TCP_KEEPALIVE_IDLE_MAX) {
|
||
+ params->tcp_keepalive_idle = keep_alive_idle;
|
||
+ } else {
|
||
+ PRINT_ERROR("keep_alive_idle=%d,illigal argument -- %s \n", keep_alive_idle, optarg);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+
|
||
+ token = strtok_s(NULL, ",", &next_token);
|
||
+ if (token == NULL) {
|
||
+ PRINT_ERROR("parse keep_alive interval null, illigal argument(%s) \n", optarg);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+ int32_t keep_alive_interval = strtol(token, NULL, 0);
|
||
+ if (keep_alive_interval > 0 && keep_alive_interval <= TCP_KEEPALIVE_IDLE_MAX) {
|
||
+ params->tcp_keepalive_interval = keep_alive_interval;
|
||
+ } else {
|
||
+ PRINT_ERROR("keep_alive_interval=%d,illigal argument -- %s \n", keep_alive_interval, optarg);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+}
|
||
+
|
||
// set `group ip` parameter
|
||
void program_param_parse_groupip(struct ProgramParams *params)
|
||
{
|
||
- in_addr_t ip = inet_addr(optarg);
|
||
- if (ip != INADDR_NONE && ip >= inet_addr("224.0.0.0") && ip <= inet_addr("239.255.255.255")) {
|
||
- params->groupip = optarg;
|
||
+ char *cur_ptr = NULL;
|
||
+ char *next_ptr = NULL;
|
||
+
|
||
+ cur_ptr = strtok_s(optarg, ",", &next_ptr);
|
||
+ if (program_ipv4_check(cur_ptr) == false) {
|
||
+ PRINT_ERROR("illigal argument -- %s \n", cur_ptr);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+
|
||
+ in_addr_t ip = ntohl(inet_addr(cur_ptr));
|
||
+ if (ip != INADDR_NONE && ip >= ntohl(inet_addr("224.0.0.0")) && ip <= ntohl(inet_addr("239.255.255.255"))) {
|
||
+ params->groupip = cur_ptr;
|
||
} else {
|
||
- PRINT_ERROR("illigal argument -- %s \n", optarg);
|
||
+ PRINT_ERROR("illigal argument -- %s \n", cur_ptr);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+
|
||
+ if (*next_ptr) {
|
||
+ if (program_ipv4_check(next_ptr)) {
|
||
+ params->groupip_interface = next_ptr;
|
||
+ } else {
|
||
+ PRINT_ERROR("illigal argument -- %s \n", next_ptr);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+void fault_inject_delay(delay_type type)
|
||
+{
|
||
+ if (g_inject_delay[type]) {
|
||
+ printf("FAULT INJECT: Delay begin, sleep %d seconds.\n", g_inject_delay[type]);
|
||
+ sleep(g_inject_delay[type]);
|
||
+ g_inject_delay[type] = 0;
|
||
+ printf("FAULT INJECT: Delay finished.\n");
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+// apply fault inject type of delay
|
||
+static void delay_param_parse(struct ProgramParams *params)
|
||
+{
|
||
+ int32_t time = 0;
|
||
+ if (params->inject[INJECT_TIME_IDX] != NULL) {
|
||
+ time = atoi(params->inject[INJECT_TIME_IDX]);
|
||
+ }
|
||
+ if (time <= 0) {
|
||
+ PRINT_ERROR("FAULT INJECT: delay time input error! receive: \"%s\"\n", params->inject[INJECT_TIME_IDX]);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+
|
||
+ char *location = params->inject[INJECT_LOCATION_IDX];
|
||
+ if (location == NULL) {
|
||
+ PRINT_ERROR("FAULT INJECT: Lack param for delay fault inject, The location is not appointed.\n");
|
||
exit(PROGRAM_ABORT);
|
||
}
|
||
+
|
||
+ if (strcmp("before_accept", location) == 0) {
|
||
+ g_inject_delay[INJECT_DELAY_ACCEPT] = time;
|
||
+ return;
|
||
+ }
|
||
+ if (strcmp("before_read", location) == 0) {
|
||
+ g_inject_delay[INJECT_DELAY_READ] = time;
|
||
+ return;
|
||
+ }
|
||
+ if (strcmp("before_write", location) == 0) {
|
||
+ g_inject_delay[INJECT_DELAY_WRITE] = time;
|
||
+ return;
|
||
+ }
|
||
+ if (strcmp("before_read_and_write", location) == 0) {
|
||
+ g_inject_delay[INJECT_DELAY_READ] = time;
|
||
+ g_inject_delay[INJECT_DELAY_WRITE] = time;
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ PRINT_ERROR("FAULT INJECT: Unidentified fault inject location -- %s \n", location);
|
||
+ exit(PROGRAM_ABORT);
|
||
+}
|
||
+
|
||
+// apply fault inject type of skip
|
||
+static void skip_param_parse(struct ProgramParams *params)
|
||
+{
|
||
+ char* location = params->inject[INJECT_SKIP_IDX];
|
||
+ if (location == NULL) {
|
||
+ PRINT_ERROR("FAULT INJECT: Lack param for skip fault inject, location is not appointed.\n");
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+
|
||
+ if (strcmp("read", location) == 0) {
|
||
+ g_inject_skip[INJECT_SKIP_READ] = 1;
|
||
+ return;
|
||
+ }
|
||
+ if (strcmp("write", location) == 0) {
|
||
+ g_inject_skip[INJECT_SKIP_WRITE] = 1;
|
||
+ return;
|
||
+ }
|
||
+ if (strcmp("read_and_write", location) == 0) {
|
||
+ g_inject_skip[INJECT_SKIP_READ] = 1;
|
||
+ g_inject_skip[INJECT_SKIP_WRITE] = 1;
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ PRINT_ERROR("FAULT INJECT: Unidentified fault inject location -- %s \n", location);
|
||
+ exit(PROGRAM_ABORT);
|
||
+}
|
||
+
|
||
+// judge if need skip fault inject
|
||
+int32_t get_g_inject_skip(skip_type type)
|
||
+{
|
||
+ return g_inject_skip[type];
|
||
+}
|
||
+
|
||
+// check legitimacy of fault injection and apply it.
|
||
+static void apply_fault_inject(struct ProgramParams *params)
|
||
+{
|
||
+ char *inject_type = params->inject[INJECT_TYPE_IDX];
|
||
+ if (strcmp("delay", inject_type) == 0) {
|
||
+ delay_param_parse(params);
|
||
+ return;
|
||
+ }
|
||
+ if (strcmp("skip", inject_type) == 0) {
|
||
+ skip_param_parse(params);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ PRINT_ERROR("FAULT INJCET: Unidentified fault inject -- %s \n", inject_type);
|
||
+ exit(PROGRAM_ABORT);
|
||
+}
|
||
+
|
||
+// set `fault injection` parameter
|
||
+static void program_param_parse_inject(struct ProgramParams *params)
|
||
+{
|
||
+ int32_t inject_idx = 0;
|
||
+ char *inject_input = strdup(optarg);
|
||
+ if (inject_input == NULL) {
|
||
+ PRINT_ERROR("FAULT INJCET: Insufficient memory, strdup failed.\n");
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+
|
||
+ char *context = NULL;
|
||
+ char *elem = strtok_s(inject_input, " ", &context);
|
||
+ if (elem == NULL) {
|
||
+ PRINT_ERROR("FAULT INJECT: Input error. -- %s \n", inject_input);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+ while (elem != NULL) {
|
||
+ if (inject_idx == FAULT_INJECT_PARA_COUNT) {
|
||
+ PRINT_ERROR("FAULT INJECT: Exceed the max count (3) of fault inject params. -- %s\n", optarg);
|
||
+ exit(PROGRAM_ABORT);
|
||
+ }
|
||
+ params->inject[inject_idx++] = elem;
|
||
+ elem = strtok_s(NULL, " ", &context);
|
||
+ }
|
||
+
|
||
+ apply_fault_inject(params);
|
||
}
|
||
|
||
// initialize the parameters
|
||
@@ -219,8 +545,11 @@ void program_params_init(struct ProgramParams *params)
|
||
{
|
||
params->as = PARAM_DEFAULT_AS;
|
||
params->ip = PARAM_DEFAULT_IP;
|
||
- params->port = PARAM_DEFAULT_PORT;
|
||
- params->sport = PARAM_DEFAULT_SPORT;
|
||
+ params->ipv6 = PARAM_DEFAULT_IP_V6;
|
||
+ params->addr_family = PARAM_DEFAULT_ADDR_FAMILY;
|
||
+ memset_s(params->port, sizeof(bool)*UNIX_TCP_PORT_MAX, 0, sizeof(bool)*UNIX_TCP_PORT_MAX);
|
||
+ memset_s(params->sport, sizeof(bool)*UNIX_TCP_PORT_MAX, 0, sizeof(bool)*UNIX_TCP_PORT_MAX);
|
||
+ (params->port)[PARAM_DEFAULT_PORT] = 1;
|
||
params->model = PARAM_DEFAULT_MODEL;
|
||
params->thread_num = PARAM_DEFAULT_THREAD_NUM;
|
||
params->connect_num = PARAM_DEFAULT_CONNECT_NUM;
|
||
@@ -233,15 +562,19 @@ void program_params_init(struct ProgramParams *params)
|
||
params->epollcreate = PARAM_DEFAULT_EPOLLCREATE;
|
||
params->accept = PARAM_DEFAULT_ACCEPT;
|
||
params->groupip = PARAM_DEFAULT_GROUPIP;
|
||
+ params->groupip_interface = PARAM_DEFAULT_GROUPIP;
|
||
+ params->tcp_keepalive_idle = PARAM_DEFAULT_KEEPALIVEIDLE;
|
||
+ params->tcp_keepalive_interval = PARAM_DEFAULT_KEEPALIVEIDLE;
|
||
}
|
||
|
||
// print program helps
|
||
void program_params_help(void)
|
||
{
|
||
printf("\n");
|
||
- printf("-a, --as [server | client]: set programas server or client. \n");
|
||
+ printf("-a, --as [server | client | loop]: set programas server, client or loop. \n");
|
||
printf(" server: as server. \n");
|
||
printf(" client: as client. \n");
|
||
+ printf(" loop: as server and client. \n");
|
||
printf("-i, --ip [???.???.???.???]: set ip address. \n");
|
||
printf("-g, --groupip [???.???.???.???]: set group ip address. \n");
|
||
printf("-p, --port [????]: set port number in range of %d - %d. \n", UNIX_TCP_PORT_MIN, UNIX_TCP_PORT_MAX);
|
||
@@ -268,6 +601,16 @@ void program_params_help(void)
|
||
printf("-h, --help: see helps. \n");
|
||
printf("-E, --epollcreate [ec | ec1]: epoll_create method. \n");
|
||
printf("-C, --accept [ac | ac4]: accept method. \n");
|
||
+ printf("-k, --keep_alive [keep_alive_idle:keep_alive_interval]: set tcp-alive info in range of %d-%d. \n",
|
||
+ PARAM_DEFAULT_KEEPALIVEIDLE, TCP_KEEPALIVE_IDLE_MAX);
|
||
+ printf("-I, --inject [\"fault_inject_param0 fault_inject_param1 fault_inject_param2\"]: fault inject\n");
|
||
+ printf(" for example: \"delay 20 before_accept\"\n");
|
||
+ printf(" \"delay 20 before_read\"\n");
|
||
+ printf(" \"delay 20 before_write\"\n");
|
||
+ printf(" \"delay 20 before_read_and_write\"\n");
|
||
+ printf(" \"skip read\"\n");
|
||
+ printf(" \"skip write\"\n");
|
||
+ printf(" \"skip read_and_write\"\n");
|
||
printf("\n");
|
||
}
|
||
|
||
@@ -295,7 +638,7 @@ int32_t program_params_parse(struct ProgramParams *params, uint32_t argc, char *
|
||
case (PARAM_NUM_PORT):
|
||
program_param_parse_port(params);
|
||
break;
|
||
- case (PARAM_NUM_SPORT):
|
||
+ case (PARAM_NUM_SPORT):
|
||
program_param_parse_sport(params);
|
||
break;
|
||
case (PARAM_NUM_MODEL):
|
||
@@ -331,9 +674,15 @@ int32_t program_params_parse(struct ProgramParams *params, uint32_t argc, char *
|
||
case (PARAM_NUM_ACCEPT):
|
||
program_param_parse_accept(params);
|
||
break;
|
||
- case (PARAM_NUM_GROUPIP):
|
||
- program_param_parse_groupip(params);
|
||
- break;
|
||
+ case (PARAM_NUM_GROUPIP):
|
||
+ program_param_parse_groupip(params);
|
||
+ break;
|
||
+ case (PARAM_NUM_KEEPALIVE):
|
||
+ program_param_parse_keepalive(params);
|
||
+ break;
|
||
+ case (PARAM_NUM_INJECT):
|
||
+ program_param_parse_inject(params);
|
||
+ break;
|
||
case (PARAM_NUM_HELP):
|
||
program_params_help();
|
||
return PROGRAM_ABORT;
|
||
@@ -345,11 +694,6 @@ int32_t program_params_parse(struct ProgramParams *params, uint32_t argc, char *
|
||
}
|
||
}
|
||
|
||
- if (strcmp(params->domain, "tcp") != 0) {
|
||
- params->thread_num = 1;
|
||
- params->connect_num = 1;
|
||
- }
|
||
-
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
@@ -361,22 +705,47 @@ void program_params_print(struct ProgramParams *params)
|
||
printf("--> [as]: %s \n", params->as);
|
||
if (strcmp(params->groupip, PARAM_DEFAULT_GROUPIP) != 0) {
|
||
if (strcmp(params->as, "server") == 0) {
|
||
- printf("--> [server ip]: %s \n", params->ip);
|
||
printf("--> [server group ip]: %s \n", params->groupip);
|
||
+ printf("--> [server groupip_interface]: %s \n", params->groupip_interface);
|
||
} else {
|
||
- printf("--> [server ip]: %s \n", params->groupip);
|
||
- printf("--> [client send ip]: %s \n", params->ip);
|
||
+ printf("--> [client group ip]: %s \n", params->groupip);
|
||
+ printf("--> [client groupip_interface]: %s \n", params->groupip_interface);
|
||
}
|
||
- } else {
|
||
- printf("--> [server ip]: %s \n", params->ip);
|
||
}
|
||
- if ((strcmp(params->as, "server") == 0 && strcmp(params->groupip, PARAM_DEFAULT_GROUPIP)) != 0) {
|
||
- printf("--> [server group ip]: %s \n", params->groupip);
|
||
+ printf("--> [server ip]: %s \n", params->ip);
|
||
+ if (strcmp(params->ipv6, PARAM_DEFAULT_IP_V6) != 0) {
|
||
+ printf("--> [server ipv6]: %s \n", params->ipv6);
|
||
+ }
|
||
+
|
||
+ printf("--> [server port]: ");
|
||
+ uint32_t comma = 0;
|
||
+ uint32_t sport = 0;
|
||
+
|
||
+ /* use comma to print port list */
|
||
+ for (uint32_t i = UNIX_TCP_PORT_MIN; i < UNIX_TCP_PORT_MAX; i++) {
|
||
+ if ((params->port)[i]) {
|
||
+ printf("%s%u", comma?",":"", i);
|
||
+ comma = 1;
|
||
+ }
|
||
+ if ((params->sport)[i]) {
|
||
+ sport = i;
|
||
+ }
|
||
}
|
||
- printf("--> [server port]: %u \n", params->port);
|
||
- if (params->sport && strcmp(params->as, "client") == 0) {
|
||
- printf("--> [client sport]: %u \n", params->sport);
|
||
+ printf(" \n");
|
||
+
|
||
+ /* use comma to print sport list */
|
||
+ if (sport && strcmp(params->as, "client") == 0) {
|
||
+ printf("--> [client sport]: ");
|
||
+ comma = 0;
|
||
+ for (uint32_t i = UNIX_TCP_PORT_MIN; i < sport + 1; i++) {
|
||
+ if ((params->sport)[i]) {
|
||
+ printf("%s%u", comma?",":"", i);
|
||
+ comma = 1;
|
||
+ }
|
||
+ }
|
||
+ printf(" \n");
|
||
}
|
||
+
|
||
if (strcmp(params->as, "server") == 0) {
|
||
printf("--> [model]: %s \n", params->model);
|
||
}
|
||
@@ -404,5 +773,16 @@ void program_params_print(struct ProgramParams *params)
|
||
printf("--> [debug]: %s \n", (params->debug == true) ? "on" : "off");
|
||
printf("--> [epoll create]: %s \n", params->epollcreate);
|
||
printf("--> [accept]: %s \n", params->accept);
|
||
+ printf("--> [inject]: ");
|
||
+ if (params->inject[INJECT_TYPE_IDX] == NULL) {
|
||
+ printf("none \n");
|
||
+ } else {
|
||
+ for (int32_t i = 0; i < FAULT_INJECT_PARA_COUNT; ++i) {
|
||
+ if (params->inject[i] != NULL) {
|
||
+ printf("%s ", params->inject[i]);
|
||
+ }
|
||
+ }
|
||
+ printf("\n");
|
||
+ }
|
||
printf("\n");
|
||
}
|
||
diff --git a/examples/src/server.c b/examples/src/server.c
|
||
index 8634dde..7bc7d9e 100644
|
||
--- a/examples/src/server.c
|
||
+++ b/examples/src/server.c
|
||
@@ -14,20 +14,22 @@
|
||
#include "server.h"
|
||
|
||
static pthread_mutex_t server_debug_mutex; // the server mutex for debug
|
||
+struct LoopInfo loopmod;
|
||
|
||
// server debug information print
|
||
-void server_debug_print(const char *ch_str, const char *act_str, in_addr_t ip, uint16_t port, bool debug)
|
||
+void server_debug_print(const char *ch_str, const char *act_str, ip_addr_t *ip, uint16_t port, bool debug)
|
||
{
|
||
if (debug == true) {
|
||
pthread_mutex_lock(&server_debug_mutex);
|
||
- struct in_addr sin_addr;
|
||
- sin_addr.s_addr = ip;
|
||
+ uint8_t str_len = ip->addr_family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
|
||
+ char str_ip[str_len];
|
||
+ inet_ntop(ip->addr_family, &ip->u_addr, str_ip, str_len);
|
||
PRINT_SERVER("[%s] [pid: %d] [tid: %ld] [%s <- %s:%d]. ", \
|
||
ch_str, \
|
||
getpid(), \
|
||
pthread_self(), \
|
||
act_str, \
|
||
- inet_ntoa(sin_addr), \
|
||
+ str_ip, \
|
||
ntohs(port));
|
||
pthread_mutex_unlock(&server_debug_mutex);
|
||
}
|
||
@@ -37,7 +39,7 @@ void server_debug_print(const char *ch_str, const char *act_str, in_addr_t ip, u
|
||
void sermud_info_print(struct ServerMud *server_mud)
|
||
{
|
||
if (server_mud->debug == false) {
|
||
- uint32_t curr_connect = server_mud->curr_connect;
|
||
+ uint32_t curr_connect = 0;
|
||
|
||
struct timeval begin;
|
||
gettimeofday(&begin, NULL);
|
||
@@ -48,6 +50,7 @@ void sermud_info_print(struct ServerMud *server_mud)
|
||
struct ServerMudWorker *begin_uint = server_mud->workers;
|
||
while (begin_uint != NULL) {
|
||
begin_recv_bytes += begin_uint->recv_bytes;
|
||
+ curr_connect += begin_uint->curr_connect;
|
||
begin_uint = begin_uint->next;
|
||
}
|
||
|
||
@@ -122,45 +125,82 @@ int32_t sermud_listener_create_epfd_and_reg(struct ServerMud *server_mud)
|
||
}
|
||
|
||
struct epoll_event ep_ev;
|
||
- ep_ev.data.ptr = (void *)&(server_mud->listener);
|
||
ep_ev.events = EPOLLIN | EPOLLET;
|
||
- if (epoll_ctl(server_mud->epfd, EPOLL_CTL_ADD, server_mud->listener.fd, &ep_ev) < 0) {
|
||
- PRINT_ERROR("server can't control epoll %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
+ for (int i = 0; i < PROTOCOL_MODE_MAX; i++) {
|
||
+ if (server_mud->listener.listen_fd_array[i] != -1) {
|
||
+ struct ServerHandler *server_handler = (struct ServerHandler *)malloc(sizeof(struct ServerHandler));
|
||
+ memset_s(server_handler, sizeof(struct ServerHandler), 0, sizeof(struct ServerHandler));
|
||
+ server_handler->fd = server_mud->listener.listen_fd_array[i];
|
||
+ ep_ev.data.ptr = (void *)server_handler;
|
||
+ if (epoll_ctl(server_mud->epfd, EPOLL_CTL_ADD, server_mud->listener.listen_fd_array[i], &ep_ev) < 0) {
|
||
+ PRINT_ERROR("epoll_ctl failed %d! listen_fd=%d ", errno, server_mud->listener.listen_fd_array[i]);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static void sermud_accept_get_remote_ip(sockaddr_t *accept_addr, ip_addr_t *remote_ip, bool is_tcp_v6_flag)
|
||
+{
|
||
+ remote_ip->addr_family = is_tcp_v6_flag ? AF_INET6 : AF_INET;
|
||
+ if (is_tcp_v6_flag == false) {
|
||
+ remote_ip->u_addr.ip4 = ((struct sockaddr_in *)accept_addr)->sin_addr;
|
||
+ } else {
|
||
+ remote_ip->u_addr.ip6 = ((struct sockaddr_in6 *)accept_addr)->sin6_addr;
|
||
}
|
||
+}
|
||
|
||
- server_debug_print("server mud listener", "waiting", server_mud->ip, server_mud->port, server_mud->debug);
|
||
+int32_t sermud_set_socket_opt(int32_t accept_fd, struct ServerMud *server_mud)
|
||
+{
|
||
+ if (set_tcp_keep_alive_info(accept_fd, server_mud->tcp_keepalive_idle, server_mud->tcp_keepalive_interval) < 0) {
|
||
+ PRINT_ERROR("cant't set_tcp_keep_alive_info! ");
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
|
||
+ if (set_socket_unblock(accept_fd) < 0) {
|
||
+ PRINT_ERROR("server can't set the connect socket to unblock! ");
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
// the listener thread, unblock, dissymmetric server accepts the connections
|
||
-int32_t sermud_listener_accept_connects(struct ServerMud *server_mud)
|
||
+int32_t sermud_listener_accept_connects(struct epoll_event *curr_epev, struct ServerMud *server_mud)
|
||
{
|
||
+ int32_t fd = ((struct ServerHandler*)(curr_epev->data.ptr))->fd;
|
||
+ fault_inject_delay(INJECT_DELAY_ACCEPT);
|
||
+
|
||
while (true) {
|
||
- struct sockaddr_in accept_addr;
|
||
- uint32_t sockaddr_in_len = sizeof(struct sockaddr_in);
|
||
+ sockaddr_t accept_addr;
|
||
+ bool is_tcp_v6_flag = (fd == server_mud->listener.listen_fd_array[V6_TCP]) ? true : false;
|
||
+
|
||
+ uint32_t sockaddr_in_len = is_tcp_v6_flag ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
|
||
+
|
||
int32_t accept_fd;
|
||
- if (strcmp(server_mud->domain, "udp") == 0) {
|
||
- break;
|
||
- }
|
||
+
|
||
+ int32_t listen_fd_index = is_tcp_v6_flag ? V6_TCP : V4_TCP;
|
||
+ int32_t listen_fd = server_mud->listener.listen_fd_array[listen_fd_index];
|
||
|
||
if (strcmp(server_mud->accept, "ac4") == 0) {
|
||
- accept_fd = accept4(server_mud->listener.fd, (struct sockaddr *)&accept_addr, &sockaddr_in_len, SOCK_CLOEXEC);
|
||
+ accept_fd = accept4(listen_fd, (struct sockaddr *)&accept_addr, &sockaddr_in_len, SOCK_CLOEXEC);
|
||
} else {
|
||
- accept_fd = accept(server_mud->listener.fd, (struct sockaddr *)&accept_addr, &sockaddr_in_len);
|
||
+ accept_fd = accept(listen_fd, (struct sockaddr *)&accept_addr, &sockaddr_in_len);
|
||
}
|
||
-
|
||
+
|
||
if (accept_fd < 0) {
|
||
break;
|
||
}
|
||
|
||
- if (set_socket_unblock(accept_fd) < 0) {
|
||
- PRINT_ERROR("server can't set the connect socket to unblock! ");
|
||
+ if (sermud_set_socket_opt(accept_fd, server_mud) < 0) {
|
||
return PROGRAM_FAULT;
|
||
}
|
||
|
||
- ++(server_mud->curr_connect);
|
||
+ // sockaddr to ip, port
|
||
+ ip_addr_t remote_ip;
|
||
+ uint16_t remote_port = ((struct sockaddr_in *)&accept_addr)->sin_port;
|
||
+ sermud_accept_get_remote_ip(&accept_addr, &remote_ip, is_tcp_v6_flag);
|
||
|
||
pthread_t *tid = (pthread_t *)malloc(sizeof(pthread_t));
|
||
struct ServerMudWorker *worker = (struct ServerMudWorker *)malloc(sizeof(struct ServerMudWorker));
|
||
@@ -169,26 +209,50 @@ int32_t sermud_listener_accept_connects(struct ServerMud *server_mud)
|
||
worker->epevs = (struct epoll_event *)malloc(sizeof(struct epoll_event));
|
||
worker->recv_bytes = 0;
|
||
worker->pktlen = server_mud->pktlen;
|
||
- worker->ip = accept_addr.sin_addr.s_addr;
|
||
- worker->port = accept_addr.sin_port;
|
||
+ worker->ip = remote_ip;
|
||
+ worker->port = remote_port;
|
||
worker->api = server_mud->api;
|
||
worker->debug = server_mud->debug;
|
||
worker->next = server_mud->workers;
|
||
worker->epollcreate = server_mud->epollcreate;
|
||
+ worker->worker.is_v6 = is_tcp_v6_flag ? 1 : 0;
|
||
+ worker->domain = server_mud->domain;
|
||
+ worker->curr_connect = 1;
|
||
|
||
server_mud->workers = worker;
|
||
|
||
- if (pthread_create(tid, NULL, sermud_worker_create_and_run, server_mud) < 0) {
|
||
+ if (pthread_create(tid, NULL, sermud_worker_create_and_run, worker) < 0) {
|
||
PRINT_ERROR("server can't create poisx thread %d! ", errno);
|
||
return PROGRAM_FAULT;
|
||
}
|
||
|
||
- server_debug_print("server mud listener", "accept", accept_addr.sin_addr.s_addr, accept_addr.sin_port, server_mud->debug);
|
||
+ server_debug_print("server mud listener", "accept", &remote_ip, remote_port, server_mud->debug);
|
||
}
|
||
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
+static int32_t server_handler_close(int32_t epfd, struct ServerHandler *server_handler)
|
||
+{
|
||
+ int32_t fd = server_handler->fd;
|
||
+ struct epoll_event ep_ev;
|
||
+ if (server_handler) {
|
||
+ free(server_handler);
|
||
+ }
|
||
+
|
||
+ if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ep_ev) < 0) {
|
||
+ PRINT_ERROR("server can't delete socket '%d' to control epoll %d! ", fd, errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+
|
||
+ if (close(fd) < 0) {
|
||
+ PRINT_ERROR("server can't close the socket %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
// the worker thread, unblock, dissymmetric server processes the events
|
||
int32_t sermud_worker_proc_epevs(struct ServerMudWorker *worker_unit, const char* domain)
|
||
{
|
||
@@ -201,32 +265,60 @@ int32_t sermud_worker_proc_epevs(struct ServerMudWorker *worker_unit, const char
|
||
for (int32_t i = 0; i < epoll_nfds; ++i) {
|
||
struct epoll_event *curr_epev = worker_unit->epevs + i;
|
||
|
||
- if (curr_epev->events == EPOLLERR || curr_epev->events == EPOLLHUP || curr_epev->events == EPOLLRDHUP) {
|
||
+ if (curr_epev->events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
|
||
+ worker_unit->curr_connect--;
|
||
PRINT_ERROR("server epoll wait error %d! ", curr_epev->events);
|
||
- return PROGRAM_FAULT;
|
||
+ if (server_handler_close(worker_unit->epfd, (struct ServerHandler *)curr_epev->data.ptr) != 0) {
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
}
|
||
|
||
if (curr_epev->events == EPOLLIN) {
|
||
struct ServerHandler *server_handler = (struct ServerHandler *)curr_epev->data.ptr;
|
||
|
||
- int32_t server_ans_ret = server_ans(server_handler, worker_unit->pktlen, worker_unit->api, domain);
|
||
+ int32_t server_ans_ret = server_ans(server_handler->fd, worker_unit->pktlen, worker_unit->api, "tcp");
|
||
if (server_ans_ret == PROGRAM_FAULT) {
|
||
- struct epoll_event ep_ev;
|
||
- if (epoll_ctl(worker_unit->epfd, EPOLL_CTL_DEL, server_handler->fd, &ep_ev) < 0) {
|
||
- PRINT_ERROR("server can't delete socket '%d' to control epoll %d! ", server_handler->fd, errno);
|
||
+ worker_unit->curr_connect--;
|
||
+ if (server_handler_close(worker_unit->epfd, server_handler) != 0) {
|
||
return PROGRAM_FAULT;
|
||
}
|
||
} else if (server_ans_ret == PROGRAM_ABORT) {
|
||
- if (close(server_handler->fd) < 0) {
|
||
- PRINT_ERROR("server can't close the socket %d! ", errno);
|
||
+ worker_unit->curr_connect--;
|
||
+ server_debug_print("server mud worker", "close", &worker_unit->ip, worker_unit->port, worker_unit->debug);
|
||
+ if (server_handler_close(worker_unit->epfd, server_handler) != 0) {
|
||
return PROGRAM_FAULT;
|
||
}
|
||
- server_debug_print("server mud worker", "close", worker_unit->ip, worker_unit->port, worker_unit->debug);
|
||
} else {
|
||
worker_unit->recv_bytes += worker_unit->pktlen;
|
||
- server_debug_print("server mud worker", "receive", worker_unit->ip, worker_unit->port, worker_unit->debug);
|
||
+ server_debug_print("server mud worker", "receive", &worker_unit->ip, worker_unit->port, worker_unit->debug);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static int32_t sermud_process_epollin_event(struct epoll_event *curr_epev, struct ServerMud *server_mud)
|
||
+{
|
||
+ struct ServerHandler *server_handler = (struct ServerHandler *)curr_epev->data.ptr;
|
||
+
|
||
+ if (server_handler->fd == server_mud->listener.listen_fd_array[V4_UDP] ||
|
||
+ server_handler->fd == server_mud->listener.listen_fd_array[UDP_MULTICAST]) {
|
||
+ uint32_t pktlen = server_mud->pktlen > UDP_PKTLEN_MAX ? UDP_PKTLEN_MAX : server_mud->pktlen;
|
||
+ int32_t server_ans_ret = server_ans(server_handler->fd, pktlen, server_mud->api, "udp");
|
||
+ if (server_ans_ret != PROGRAM_OK) {
|
||
+ if (server_handler_close(server_mud->epfd, server_handler) != 0) {
|
||
+ PRINT_ERROR("server_handler_close server_ans_ret %d! \n", server_ans_ret);
|
||
+ return PROGRAM_FAULT;
|
||
}
|
||
}
|
||
+ server_mud->workers->recv_bytes += pktlen;
|
||
+ } else {
|
||
+ int32_t sermud_listener_accept_connects_ret = sermud_listener_accept_connects(curr_epev, server_mud);
|
||
+ if (sermud_listener_accept_connects_ret < 0) {
|
||
+ PRINT_ERROR("server try accept error %d! ", sermud_listener_accept_connects_ret);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
}
|
||
|
||
return PROGRAM_OK;
|
||
@@ -244,15 +336,14 @@ int32_t sermud_listener_proc_epevs(struct ServerMud *server_mud)
|
||
for (int32_t i = 0; i < epoll_nfds; ++i) {
|
||
struct epoll_event *curr_epev = server_mud->epevs + i;
|
||
|
||
- if (curr_epev->events == EPOLLERR || curr_epev->events == EPOLLHUP || curr_epev->events == EPOLLRDHUP) {
|
||
+ if (curr_epev->events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
|
||
PRINT_ERROR("server epoll wait error %d! ", curr_epev->events);
|
||
- return PROGRAM_FAULT;
|
||
+ server_handler_close(server_mud->epfd, (struct ServerHandler *)curr_epev->data.ptr);
|
||
+ return PROGRAM_OK;
|
||
}
|
||
|
||
if (curr_epev->events == EPOLLIN) {
|
||
- int32_t sermud_listener_accept_connects_ret = sermud_listener_accept_connects(server_mud);
|
||
- if (sermud_listener_accept_connects_ret < 0) {
|
||
- PRINT_ERROR("server try accept error %d! ", sermud_listener_accept_connects_ret);
|
||
+ if (sermud_process_epollin_event(curr_epev, server_mud) < 0) {
|
||
return PROGRAM_FAULT;
|
||
}
|
||
}
|
||
@@ -266,15 +357,15 @@ void *sermud_worker_create_and_run(void *arg)
|
||
{
|
||
pthread_detach(pthread_self());
|
||
|
||
- struct ServerMudWorker *worker_unit = ((struct ServerMud *)arg)->workers;
|
||
- char* domain = ((struct ServerMud *)arg)->domain;
|
||
+ struct ServerMudWorker *worker_unit = (struct ServerMudWorker *)arg;
|
||
+ char *domain = worker_unit->domain;
|
||
|
||
if (sermud_worker_create_epfd_and_reg(worker_unit) < 0) {
|
||
- exit(PROGRAM_FAULT);
|
||
+ return (void *)PROGRAM_OK;
|
||
}
|
||
while (true) {
|
||
if (sermud_worker_proc_epevs(worker_unit, domain) < 0) {
|
||
- exit(PROGRAM_FAULT);
|
||
+ return (void *)PROGRAM_OK;
|
||
}
|
||
}
|
||
|
||
@@ -284,26 +375,60 @@ void *sermud_worker_create_and_run(void *arg)
|
||
return (void *)PROGRAM_OK;
|
||
}
|
||
|
||
+void sermud_memory_recycle(struct ServerMud *server_mud)
|
||
+{
|
||
+ // recycle mem of epevs
|
||
+ if (server_mud->epevs) {
|
||
+ free(server_mud->epevs);
|
||
+ }
|
||
+ struct ServerMudWorker *head = server_mud->workers;
|
||
+ while (head) {
|
||
+ if (head->epevs) {
|
||
+ free(head->epevs);
|
||
+ }
|
||
+ struct ServerMudWorker *next = head->next;
|
||
+ free(head);
|
||
+ head = next;
|
||
+ }
|
||
+}
|
||
+
|
||
// create the listener thread, unblock, dissymmetric server and run
|
||
void *sermud_listener_create_and_run(void *arg)
|
||
{
|
||
struct ServerMud *server_mud = (struct ServerMud *)arg;
|
||
|
||
- if (create_socket_and_listen(&(server_mud->listener.fd), server_mud->ip, server_mud->groupip, server_mud->port, server_mud->domain) < 0) {
|
||
- exit(PROGRAM_FAULT);
|
||
+ uint32_t port = 0;
|
||
+ for (; port < UNIX_TCP_PORT_MAX; port++) {
|
||
+ if ((server_mud->port)[port]) {
|
||
+ if (create_socket_and_listen(server_mud->listener.listen_fd_array, &(server_mud->server_ip_info),
|
||
+ htons(port), server_mud->protocol_type_mode) < 0) {
|
||
+ PRINT_ERROR("create_socket_and_listen err");
|
||
+ sermud_memory_recycle(server_mud);
|
||
+ exit(PROGRAM_FAULT);
|
||
+ }
|
||
+ }
|
||
}
|
||
+
|
||
if (sermud_listener_create_epfd_and_reg(server_mud) < 0) {
|
||
- exit(PROGRAM_FAULT);
|
||
+ sermud_memory_recycle(server_mud);
|
||
+ exit(PROGRAM_FAULT);
|
||
}
|
||
while (true) {
|
||
if (sermud_listener_proc_epevs(server_mud) < 0) {
|
||
+ sermud_memory_recycle(server_mud);
|
||
exit(PROGRAM_FAULT);
|
||
}
|
||
}
|
||
- if (close(server_mud->listener.fd) < 0 || close(server_mud->epfd) < 0) {
|
||
- exit(PROGRAM_FAULT);
|
||
- }
|
||
|
||
+ for (int i = 0; i < PROTOCOL_MODE_MAX; i++) {
|
||
+ if (server_mud->listener.listen_fd_array[i] == -1)
|
||
+ continue;
|
||
+ if (close(server_mud->listener.listen_fd_array[i]) < 0) {
|
||
+ sermud_memory_recycle(server_mud);
|
||
+ exit(PROGRAM_FAULT);
|
||
+ }
|
||
+ }
|
||
+ sermud_memory_recycle(server_mud);
|
||
return (void *)PROGRAM_OK;
|
||
}
|
||
|
||
@@ -319,19 +444,44 @@ int32_t sermud_create_and_run(struct ProgramParams *params)
|
||
}
|
||
|
||
server_mud->listener.fd = -1;
|
||
- server_mud->workers = NULL;
|
||
+ for (int32_t i = 0; i < PROTOCOL_MODE_MAX; i++) {
|
||
+ server_mud->listener.listen_fd_array[i] = -1;
|
||
+ }
|
||
+
|
||
+ struct ServerMudWorker *workers = (struct ServerMudWorker *)malloc(sizeof(struct ServerMudWorker));
|
||
+ if (workers == NULL) {
|
||
+ PRINT_ERROR("malloc truct ServerMudWorker failed ");
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ memset_s(workers, sizeof(struct ServerMudWorker), 0, sizeof(struct ServerMudWorker));
|
||
+ workers->next = NULL;
|
||
+ server_mud->workers = workers;
|
||
+
|
||
server_mud->epfd = -1;
|
||
server_mud->epevs = (struct epoll_event *)malloc(SERVER_EPOLL_SIZE_MAX * sizeof(struct epoll_event));
|
||
- server_mud->curr_connect = 0;
|
||
- server_mud->ip = inet_addr(params->ip);
|
||
- server_mud->groupip = inet_addr(params->groupip);
|
||
- server_mud->port = htons(params->port);
|
||
+ server_mud->server_ip_info.ip.addr_family = params->addr_family;
|
||
+
|
||
+ inet_pton(AF_INET, params->ip, &server_mud->server_ip_info.ip.u_addr.ip4);
|
||
+ inet_pton(AF_INET6, params->ipv6, &server_mud->server_ip_info.ip.u_addr.ip6);
|
||
+
|
||
+ server_mud->server_ip_info.groupip.addr_family = params->addr_family;
|
||
+ inet_pton(AF_INET, params->groupip, &server_mud->server_ip_info.groupip.u_addr);
|
||
+
|
||
+ server_mud->server_ip_info.groupip_interface.addr_family = params->addr_family;
|
||
+ inet_pton(AF_INET, params->groupip_interface, &server_mud->server_ip_info.groupip_interface.u_addr);
|
||
+
|
||
+ server_mud->port = params->port;
|
||
server_mud->pktlen = params->pktlen;
|
||
- server_mud->domain = params->domain;
|
||
+
|
||
+ server_mud->protocol_type_mode = program_get_protocol_mode_by_domain_ip(params->domain, params->ip, params->ipv6,
|
||
+ params->groupip);
|
||
+
|
||
server_mud->api = params->api;
|
||
server_mud->debug = params->debug;
|
||
server_mud->epollcreate = params->epollcreate;
|
||
server_mud->accept = params->accept;
|
||
+ server_mud->tcp_keepalive_idle = params->tcp_keepalive_idle;
|
||
+ server_mud->tcp_keepalive_interval = params->tcp_keepalive_interval;
|
||
|
||
if (pthread_create(tid, NULL, sermud_listener_create_and_run, server_mud) < 0) {
|
||
PRINT_ERROR("server can't create poisx thread %d! ", errno);
|
||
@@ -341,10 +491,17 @@ int32_t sermud_create_and_run(struct ProgramParams *params)
|
||
if (server_mud->debug == false) {
|
||
printf("[program informations]: \n\n");
|
||
}
|
||
- while (true) {
|
||
- sermud_info_print(server_mud);
|
||
+
|
||
+ if (strcmp(params->as, "server") == 0) {
|
||
+ while (true) {
|
||
+ sermud_info_print(server_mud);
|
||
+ }
|
||
+ } else if (strcmp(params->as, "loop") == 0) {
|
||
+ loopmod.model = params->model;
|
||
+ loopmod.server_mud_info = server_mud;
|
||
}
|
||
|
||
+
|
||
pthread_mutex_destroy(&server_debug_mutex);
|
||
|
||
return PROGRAM_OK;
|
||
@@ -413,39 +570,62 @@ int32_t sersum_create_epfd_and_reg(struct ServerMumUnit *server_unit)
|
||
return PROGRAM_FAULT;
|
||
}
|
||
|
||
- struct epoll_event ep_ev;
|
||
- ep_ev.data.ptr = (void *)&(server_unit->listener);
|
||
+ struct epoll_event ep_ev = {0};
|
||
ep_ev.events = EPOLLIN | EPOLLET;
|
||
- if (epoll_ctl(server_unit->epfd, EPOLL_CTL_ADD, server_unit->listener.fd, &ep_ev) < 0) {
|
||
- PRINT_ERROR("server can't control epoll %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
+
|
||
+ for (int32_t i = 0; i < PROTOCOL_MODE_MAX; i++) {
|
||
+ if (server_unit->listener.listen_fd_array[i] != -1) {
|
||
+ struct ServerHandler *server_handler = (struct ServerHandler *)malloc(sizeof(struct ServerHandler));
|
||
+ memset_s(server_handler, sizeof(struct ServerHandler), 0, sizeof(struct ServerHandler));
|
||
+ server_handler->fd = server_unit->listener.listen_fd_array[i];
|
||
+
|
||
+ ep_ev.data.ptr = (void *)server_handler;
|
||
+ if (epoll_ctl(server_unit->epfd, EPOLL_CTL_ADD, server_unit->listener.listen_fd_array[i], &ep_ev) < 0) {
|
||
+ PRINT_ERROR("epoll_ctl failed %d! listen_fd=%d ", errno, server_unit->listener.listen_fd_array[i]);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ }
|
||
}
|
||
|
||
- server_debug_print("server mum unit", "waiting", server_unit->ip, server_unit->port, server_unit->debug);
|
||
+ server_debug_print("server mum unit", "waiting", &server_unit->server_ip_info.ip, server_unit->port,
|
||
+ server_unit->debug);
|
||
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
// the single thread, unblock, mutliplexing IO server accepts the connections
|
||
-int32_t sersum_accept_connects(struct ServerMumUnit *server_unit, struct ServerHandler *server_handler)
|
||
+int32_t sersum_accept_connects(struct epoll_event *cur_epev, struct ServerMumUnit *server_unit)
|
||
{
|
||
+ fault_inject_delay(INJECT_DELAY_ACCEPT);
|
||
+ int32_t fd = ((struct ServerHandler*)(cur_epev->data.ptr))->fd;
|
||
while (true) {
|
||
- struct sockaddr_in accept_addr;
|
||
- uint32_t sockaddr_in_len = sizeof(struct sockaddr_in);
|
||
+ sockaddr_t accept_addr;
|
||
+ bool is_tcp_v6 = (fd == (server_unit->listener.listen_fd_array[V6_TCP])) ? true : false;
|
||
+
|
||
+ socklen_t sockaddr_in_len = is_tcp_v6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
|
||
int32_t accept_fd;
|
||
- if (strcmp(server_unit->domain, "udp") == 0) {
|
||
- break;
|
||
- }
|
||
+ int32_t ret = 0;
|
||
+
|
||
+ int32_t listen_index = (is_tcp_v6) ? V6_TCP : V4_TCP;
|
||
+ int32_t listen_fd = server_unit->listener.listen_fd_array[listen_index];
|
||
|
||
if (strcmp(server_unit->accept, "ac4") == 0) {
|
||
- accept_fd = accept4(server_unit->listener.fd, (struct sockaddr *)&accept_addr, &sockaddr_in_len, SOCK_CLOEXEC);
|
||
+ accept_fd = accept4(listen_fd, (struct sockaddr *)&accept_addr, &sockaddr_in_len, SOCK_CLOEXEC);
|
||
} else {
|
||
- accept_fd = accept(server_unit->listener.fd, (struct sockaddr *)&accept_addr, &sockaddr_in_len);
|
||
+ accept_fd = accept(listen_fd, (struct sockaddr *)&accept_addr, &sockaddr_in_len);
|
||
}
|
||
-
|
||
+
|
||
if (accept_fd < 0) {
|
||
+ if (errno != EWOULDBLOCK && errno != EAGAIN){
|
||
+ PRINT_ERROR("accept_fd=%d , errno=%d ", accept_fd, errno);
|
||
+ }
|
||
break;
|
||
}
|
||
+ ret = set_tcp_keep_alive_info(accept_fd, server_unit->tcp_keepalive_idle, server_unit->tcp_keepalive_interval);
|
||
+ if (ret < 0) {
|
||
+ PRINT_ERROR("set_tcp_keep_alive_info ret=%d \n", ret);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
|
||
if (set_socket_unblock(accept_fd) < 0) {
|
||
PRINT_ERROR("server can't set the connect socket to unblock! ");
|
||
@@ -454,6 +634,8 @@ int32_t sersum_accept_connects(struct ServerMumUnit *server_unit, struct ServerH
|
||
|
||
struct ServerHandler *server_handler = (struct ServerHandler *)malloc(sizeof(struct ServerHandler));
|
||
server_handler->fd = accept_fd;
|
||
+ server_handler->is_v6 = (is_tcp_v6) ? 1 : 0;
|
||
+
|
||
struct epoll_event ep_ev;
|
||
ep_ev.data.ptr = (void *)server_handler;
|
||
ep_ev.events = EPOLLIN | EPOLLET;
|
||
@@ -463,13 +645,98 @@ int32_t sersum_accept_connects(struct ServerMumUnit *server_unit, struct ServerH
|
||
}
|
||
|
||
++server_unit->curr_connect;
|
||
-
|
||
- server_debug_print("server mum unit", "accept", accept_addr.sin_addr.s_addr, accept_addr.sin_port, server_unit->debug);
|
||
+
|
||
+ // sockaddr tp ip, port
|
||
+ ip_addr_t remote_ip;
|
||
+ uint16_t remote_port = ((struct sockaddr_in*)&accept_addr)->sin_port;
|
||
+ remote_ip.addr_family = (is_tcp_v6) ? AF_INET6 : AF_INET;
|
||
+ if (is_tcp_v6 == false) {
|
||
+ remote_ip.u_addr.ip4 = ((struct sockaddr_in *)&accept_addr)->sin_addr;
|
||
+ } else {
|
||
+ remote_ip.u_addr.ip6 = ((struct sockaddr_in6 *)&accept_addr)->sin6_addr;
|
||
+ }
|
||
+
|
||
+ server_debug_print("server mum unit", "accept", &remote_ip, remote_port, server_unit->debug);
|
||
}
|
||
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
+static int sersum_get_remote_ip(struct ServerHandler *server_handler, ip_addr_t *remote_ip, uint16_t *remote_port)
|
||
+{
|
||
+ sockaddr_t connect_addr;
|
||
+ socklen_t connect_addr_len = server_handler->is_v6 == 0 ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||
+ if (getpeername(server_handler->fd, (struct sockaddr *)&connect_addr, &connect_addr_len) < 0) {
|
||
+ PRINT_ERROR("server can't socket peername %d! ", errno);
|
||
+ return PROGRAM_ABORT;
|
||
+ }
|
||
+
|
||
+ *remote_port = ((struct sockaddr_in *)&connect_addr)->sin_port;
|
||
+ if (((struct sockaddr *)&connect_addr)->sa_family == AF_INET) {
|
||
+ remote_ip->addr_family = AF_INET;
|
||
+ remote_ip->u_addr.ip4 = ((struct sockaddr_in *)&connect_addr)->sin_addr;
|
||
+ } else if (((struct sockaddr *)&connect_addr)->sa_family == AF_INET6) {
|
||
+ remote_ip->addr_family = AF_INET6;
|
||
+ remote_ip->u_addr.ip6 = ((struct sockaddr_in6 *)&connect_addr)->sin6_addr;
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static int sersum_process_tcp_accept_event(struct ServerMumUnit *server_unit, struct epoll_event *curr_epev)
|
||
+{
|
||
+ struct ServerHandler *server_handler = (struct ServerHandler *)curr_epev->data.ptr;
|
||
+ ip_addr_t remote_ip;
|
||
+ uint16_t remote_port;
|
||
+
|
||
+ if (sersum_get_remote_ip(server_handler, &remote_ip, &remote_port) != PROGRAM_OK) {
|
||
+ return PROGRAM_ABORT;
|
||
+ }
|
||
+
|
||
+ int32_t server_ans_ret = server_ans(server_handler->fd, server_unit->pktlen, server_unit->api, "tcp");
|
||
+ if (server_ans_ret == PROGRAM_FAULT) {
|
||
+ --server_unit->curr_connect;
|
||
+ server_handler_close(server_unit->epfd, server_handler);
|
||
+ } else if (server_ans_ret == PROGRAM_ABORT) {
|
||
+ --server_unit->curr_connect;
|
||
+ server_debug_print("server mum unit", "close", &remote_ip, remote_port, server_unit->debug);
|
||
+ server_handler_close(server_unit->epfd, server_handler);
|
||
+ } else {
|
||
+ server_unit->recv_bytes += server_unit->pktlen;
|
||
+ server_debug_print("server mum unit", "receive", &remote_ip, remote_port, server_unit->debug);
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static int sersum_process_epollin_event(struct ServerMumUnit *server_unit, struct epoll_event *curr_epev)
|
||
+{
|
||
+ struct ServerHandler *server_handler = (struct ServerHandler *)curr_epev->data.ptr;
|
||
+ int32_t fd = server_handler->fd;
|
||
+ if (fd == (server_unit->listener.listen_fd_array[V4_TCP]) ||
|
||
+ fd == (server_unit->listener.listen_fd_array[V6_TCP])) {
|
||
+ int32_t sersum_accept_connects_ret = sersum_accept_connects(curr_epev, server_unit);
|
||
+ if (sersum_accept_connects_ret < 0) {
|
||
+ PRINT_ERROR("server try accept error %d! ", sersum_accept_connects_ret);
|
||
+ return PROGRAM_ABORT;
|
||
+ }
|
||
+ } else if (fd == (server_unit->listener.listen_fd_array[V4_UDP]) ||
|
||
+ fd == (server_unit->listener.listen_fd_array[UDP_MULTICAST])) {
|
||
+ uint32_t pktlen = server_unit->pktlen > UDP_PKTLEN_MAX ? UDP_PKTLEN_MAX : server_unit->pktlen;
|
||
+ int32_t server_ans_ret = server_ans(fd, pktlen, server_unit->api, "udp");
|
||
+ if (server_ans_ret != PROGRAM_OK) {
|
||
+ if (server_handler_close(server_unit->epfd, server_handler) != 0) {
|
||
+ PRINT_ERROR("server_handler_close ret %d! \n", server_ans_ret);
|
||
+ return PROGRAM_ABORT;
|
||
+ }
|
||
+ }
|
||
+ server_unit->recv_bytes += pktlen;
|
||
+ } else {
|
||
+ if (sersum_process_tcp_accept_event(server_unit, curr_epev) != PROGRAM_OK) {
|
||
+ return PROGRAM_ABORT;
|
||
+ }
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
// the single thread, unblock, mutliplexing IO server processes the events
|
||
int32_t sersum_proc_epevs(struct ServerMumUnit *server_unit)
|
||
{
|
||
@@ -482,47 +749,16 @@ int32_t sersum_proc_epevs(struct ServerMumUnit *server_unit)
|
||
for (int32_t i = 0; i < epoll_nfds; ++i) {
|
||
struct epoll_event *curr_epev = server_unit->epevs + i;
|
||
|
||
- if (curr_epev->events == EPOLLERR || curr_epev->events == EPOLLHUP || curr_epev->events == EPOLLRDHUP) {
|
||
- PRINT_ERROR("server epoll wait error %d! ", curr_epev->events);
|
||
- return PROGRAM_FAULT;
|
||
+ if (curr_epev->events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
|
||
+ server_unit->curr_connect--;
|
||
+ if (server_handler_close(server_unit->epfd, (struct ServerHandler *)curr_epev->data.ptr) != 0) {
|
||
+ return PROGRAM_OK;
|
||
+ }
|
||
}
|
||
|
||
if (curr_epev->events == EPOLLIN) {
|
||
- if (curr_epev->data.ptr == (void *)&(server_unit->listener) && strcmp(server_unit->domain, "udp") != 0) {
|
||
- int32_t sersum_accept_connects_ret = sersum_accept_connects(server_unit, &(server_unit->listener));
|
||
- if (sersum_accept_connects_ret < 0) {
|
||
- PRINT_ERROR("server try accept error %d! ", sersum_accept_connects_ret);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- continue;
|
||
- } else {
|
||
- struct ServerHandler *server_handler = (struct ServerHandler *)curr_epev->data.ptr;
|
||
- struct sockaddr_in connect_addr;
|
||
- socklen_t connect_addr_len = sizeof(connect_addr);
|
||
- if (strcmp(server_unit->domain, "udp") != 0 && getpeername(server_handler->fd, (struct sockaddr *)&connect_addr, &connect_addr_len) < 0) {
|
||
- PRINT_ERROR("server can't socket peername %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
-
|
||
- int32_t server_ans_ret = server_ans(server_handler, server_unit->pktlen, server_unit->api, server_unit->domain);
|
||
- if (server_ans_ret == PROGRAM_FAULT) {
|
||
- --server_unit->curr_connect;
|
||
- struct epoll_event ep_ev;
|
||
- if (epoll_ctl(server_unit->epfd, EPOLL_CTL_DEL, server_handler->fd, &ep_ev) < 0) {
|
||
- PRINT_ERROR("server can't delete socket '%d' to control epoll %d! ", server_handler->fd, errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- } else if (server_ans_ret == PROGRAM_ABORT) {
|
||
- --server_unit->curr_connect;
|
||
- if (close(server_handler->fd) < 0) {
|
||
- PRINT_ERROR("server can't close the socket %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
- server_debug_print("server mum unit", "close", connect_addr.sin_addr.s_addr, connect_addr.sin_port, server_unit->debug);
|
||
- } else {
|
||
- server_unit->recv_bytes += server_unit->pktlen;
|
||
- server_debug_print("server mum unit", "receive", connect_addr.sin_addr.s_addr, connect_addr.sin_port, server_unit->debug);
|
||
- }
|
||
+ if (sersum_process_epollin_event(server_unit, curr_epev) != PROGRAM_OK) {
|
||
+ return PROGRAM_ABORT;
|
||
}
|
||
}
|
||
}
|
||
@@ -535,7 +771,9 @@ void *sersum_create_and_run(void *arg)
|
||
{
|
||
struct ServerMumUnit *server_unit = (struct ServerMumUnit *)arg;
|
||
|
||
- if (create_socket_and_listen(&(server_unit->listener.fd), server_unit->ip, server_unit->groupip, server_unit->port, server_unit->domain) < 0) {
|
||
+ if (create_socket_and_listen(server_unit->listener.listen_fd_array, &(server_unit->server_ip_info),
|
||
+ server_unit->port, server_unit->protocol_type_mode) < 0) {
|
||
+ PRINT_ERROR("create_socket_and_listen err! \n");
|
||
exit(PROGRAM_FAULT);
|
||
}
|
||
if (sersum_create_epfd_and_reg(server_unit) < 0) {
|
||
@@ -560,6 +798,7 @@ int32_t sermum_create_and_run(struct ProgramParams *params)
|
||
pthread_t *tids = (pthread_t *)malloc(thread_num * sizeof(pthread_t));
|
||
struct ServerMum *server_mum = (struct ServerMum *)malloc(sizeof(struct ServerMum));
|
||
struct ServerMumUnit *server_unit = (struct ServerMumUnit *)malloc(sizeof(struct ServerMumUnit));
|
||
+ memset_s(server_unit, sizeof(struct ServerMumUnit), 0, sizeof(struct ServerMumUnit));
|
||
|
||
if (pthread_mutex_init(&server_debug_mutex, NULL) < 0) {
|
||
PRINT_ERROR("server can't init posix mutex %d! ", errno);
|
||
@@ -568,22 +807,47 @@ int32_t sermum_create_and_run(struct ProgramParams *params)
|
||
|
||
server_mum->uints = server_unit;
|
||
server_mum->debug = params->debug;
|
||
+ uint32_t port = UNIX_TCP_PORT_MIN;
|
||
|
||
for (uint32_t i = 0; i < thread_num; ++i) {
|
||
server_unit->listener.fd = -1;
|
||
+ for (int32_t i = 0; i < PROTOCOL_MODE_MAX; i++) {
|
||
+ server_unit->listener.listen_fd_array[i] = -1;
|
||
+ }
|
||
server_unit->epfd = -1;
|
||
server_unit->epevs = (struct epoll_event *)malloc(SERVER_EPOLL_SIZE_MAX * sizeof(struct epoll_event));
|
||
server_unit->curr_connect = 0;
|
||
server_unit->recv_bytes = 0;
|
||
- server_unit->ip = inet_addr(params->ip);
|
||
- server_unit->groupip = inet_addr(params->groupip);
|
||
- server_unit->port = htons(params->port);
|
||
+ server_unit->server_ip_info.ip.addr_family = params->addr_family;
|
||
+ inet_pton(AF_INET, params->ip, &server_unit->server_ip_info.ip.u_addr.ip4);
|
||
+ inet_pton(AF_INET6, params->ipv6, &server_unit->server_ip_info.ip.u_addr.ip6);
|
||
+
|
||
+ server_unit->server_ip_info.groupip.addr_family = AF_INET;
|
||
+ inet_pton(AF_INET, params->groupip, &server_unit->server_ip_info.groupip.u_addr);
|
||
+
|
||
+ server_unit->server_ip_info.groupip_interface.addr_family = AF_INET;
|
||
+ inet_pton(AF_INET, params->groupip_interface, &server_unit->server_ip_info.groupip_interface.u_addr);
|
||
+
|
||
+ /* loop to set ports to each server_mums */
|
||
+ while (!((params->port)[port])) {
|
||
+ port = (port + 1) % UNIX_TCP_PORT_MAX;
|
||
+ }
|
||
+ server_unit->port = htons(port++);
|
||
server_unit->pktlen = params->pktlen;
|
||
- server_unit->domain = params->domain;
|
||
+
|
||
+ server_unit->protocol_type_mode = program_get_protocol_mode_by_domain_ip(params->domain, params->ip,
|
||
+ params->ipv6, params->groupip);
|
||
+
|
||
+ // Create multicast sockets only on the first thread
|
||
+ if (i != 0) {
|
||
+ server_unit->protocol_type_mode = setbitnum_off(server_unit->protocol_type_mode, UDP_MULTICAST);
|
||
+ }
|
||
server_unit->api = params->api;
|
||
server_unit->debug = params->debug;
|
||
server_unit->epollcreate = params->epollcreate;
|
||
server_unit->accept = params->accept;
|
||
+ server_unit->tcp_keepalive_idle = params->tcp_keepalive_idle;
|
||
+ server_unit->tcp_keepalive_interval = params->tcp_keepalive_interval;
|
||
server_unit->next = (struct ServerMumUnit *)malloc(sizeof(struct ServerMumUnit));
|
||
if (server_unit->next) {
|
||
memset_s(server_unit->next, sizeof(struct ServerMumUnit), 0, sizeof(struct ServerMumUnit));
|
||
@@ -599,8 +863,14 @@ int32_t sermum_create_and_run(struct ProgramParams *params)
|
||
if (server_mum->debug == false) {
|
||
printf("[program informations]: \n\n");
|
||
}
|
||
- while (true) {
|
||
- sermum_info_print(server_mum);
|
||
+
|
||
+ if (strcmp(params->as, "server") == 0) {
|
||
+ while (true) {
|
||
+ sermum_info_print(server_mum);
|
||
+ }
|
||
+ } else if (strcmp(params->as, "loop") == 0) {
|
||
+ loopmod.model = params->model;
|
||
+ loopmod.server_mum_info = server_mum;
|
||
}
|
||
|
||
pthread_mutex_destroy(&server_debug_mutex);
|
||
diff --git a/examples/src/utilities.c b/examples/src/utilities.c
|
||
index 7247b44..59d8bea 100644
|
||
--- a/examples/src/utilities.c
|
||
+++ b/examples/src/utilities.c
|
||
@@ -11,35 +11,215 @@
|
||
*/
|
||
|
||
|
||
-#include "utilities.h"
|
||
+#include "parameter.h"
|
||
|
||
+int32_t set_tcp_keep_alive_info(int32_t sockfd, int32_t tcp_keepalive_idle, int32_t tcp_keepalive_interval)
|
||
+{
|
||
+ int32_t ret = 0;
|
||
+ int32_t keep_alive = 1;
|
||
+ int32_t keep_idle = 1;
|
||
+ int32_t keep_interval = 1;
|
||
+
|
||
+ if ((tcp_keepalive_idle == PARAM_DEFAULT_KEEPALIVEIDLE) ||
|
||
+ (tcp_keepalive_interval == PARAM_DEFAULT_KEEPALIVEIDLE)) {
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ keep_idle = tcp_keepalive_idle;
|
||
+ ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keep_alive, sizeof(keep_alive));
|
||
+ if (ret != 0) {
|
||
+ PRINT_ERROR("setsockopt keep_alive err ret=%d \n", ret);
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, (void *)&keep_idle, sizeof(keep_idle));
|
||
+ if (ret != 0) {
|
||
+ PRINT_ERROR("setsockopt keep_idle err ret=%d \n", ret);
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ keep_interval = tcp_keepalive_interval;
|
||
+ ret = setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keep_interval, sizeof(keep_interval));
|
||
+ if (ret != 0) {
|
||
+ PRINT_ERROR("setsockopt keep_interval err ret=%d \n", ret);
|
||
+ return ret;
|
||
+ }
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static int32_t process_unix_fd(int32_t *socket_fd, int32_t *listen_fd_array)
|
||
+{
|
||
+ struct sockaddr_un socket_addr;
|
||
+ int32_t fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||
+ if (fd < 0) {
|
||
+ PRINT_ERROR("can't create socket %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ *socket_fd = fd;
|
||
+
|
||
+ unlink(SOCKET_UNIX_DOMAIN_FILE);
|
||
+ socket_addr.sun_family = AF_UNIX;
|
||
+ strcpy_s(socket_addr.sun_path, sizeof(socket_addr.sun_path), SOCKET_UNIX_DOMAIN_FILE);
|
||
+ if (bind(*socket_fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_un)) < 0) {
|
||
+ PRINT_ERROR("can't bind the address to socket %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+
|
||
+ if (listen(*socket_fd, SERVER_SOCKET_LISTEN_BACKLOG) < 0) {
|
||
+ PRINT_ERROR("server socket can't lisiten %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static int32_t process_udp_groupip(int32_t fd, ip_addr_t *ip, ip_addr_t *groupip, sockaddr_t *socker_add_info,
|
||
+ ip_addr_t *groupip_interface)
|
||
+{
|
||
+ struct ip_mreq mreq;
|
||
+ if (groupip->u_addr.ip4.s_addr) {
|
||
+ mreq.imr_multiaddr = groupip->u_addr.ip4;
|
||
+ if (groupip_interface->u_addr.ip4.s_addr) {
|
||
+ mreq.imr_interface = groupip_interface->u_addr.ip4;
|
||
+ } else {
|
||
+ mreq.imr_interface = ip->u_addr.ip4;
|
||
+ }
|
||
+
|
||
+ if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -1) {
|
||
+ PRINT_ERROR("can't set the address to group %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ ((struct sockaddr_in *)socker_add_info)->sin_addr = groupip->u_addr.ip4;
|
||
+ return PROGRAM_OK;
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static int32_t server_create_sock(uint8_t protocol_mode, int32_t* fd_arry)
|
||
+{
|
||
+ bool ret = true;
|
||
+ for (int32_t i = 0; i < PROTOCOL_MODE_MAX; i++) {
|
||
+ if (getbit_num(protocol_mode, i) == 0)
|
||
+ continue;
|
||
+ if (i == V4_TCP) {
|
||
+ fd_arry[i] = socket(AF_INET, SOCK_STREAM, 0);
|
||
+ } else if (i == V6_TCP) {
|
||
+ fd_arry[i] = socket(AF_INET6, SOCK_STREAM, 0);
|
||
+ } else if (i == V4_UDP) {
|
||
+ fd_arry[i] = socket(AF_INET, SOCK_DGRAM, 0);
|
||
+ } else if (i == UDP_MULTICAST) {
|
||
+ fd_arry[i] = socket(AF_INET, SOCK_DGRAM, 0);
|
||
+ } else {
|
||
+ continue;
|
||
+ }
|
||
+ if (fd_arry[i] < 0) {
|
||
+ PRINT_ERROR("can't create socket type=%d errno=%d! ", i, errno);
|
||
+ ret = false;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (ret == false) {
|
||
+ for (int32_t i = 0; i< PROTOCOL_MODE_MAX; i++) {
|
||
+ if (fd_arry[i] > 0) {
|
||
+ close(fd_arry[i]);
|
||
+ }
|
||
+ }
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static int32_t socket_add_info_init(int32_t idx, uint16_t port, struct ServerIpInfo *server_ip_info,
|
||
+ sockaddr_t *socker_add_info, int32_t *listen_fd_array)
|
||
+{
|
||
+ ip_addr_t *ip = &(server_ip_info->ip);
|
||
+ ip_addr_t *groupip = &(server_ip_info->groupip);
|
||
+ ip_addr_t *groupip_interface = &(server_ip_info->groupip_interface);
|
||
+
|
||
+ uint32_t len = ((idx == V4_TCP || idx == V4_UDP || idx == UDP_MULTICAST) ?
|
||
+ sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
|
||
+ memset_s(socker_add_info, len, 0, len);
|
||
+
|
||
+ if (idx == V4_TCP || idx == V4_UDP) {
|
||
+ ((struct sockaddr_in *)socker_add_info)->sin_addr = ip->u_addr.ip4;
|
||
+ } else if (idx == V6_TCP) {
|
||
+ ((struct sockaddr_in6 *)socker_add_info)->sin6_addr = ip->u_addr.ip6;
|
||
+ } else if (idx == UDP_MULTICAST) {
|
||
+ if (process_udp_groupip(listen_fd_array[idx], ip, groupip, socker_add_info, groupip_interface) != PROGRAM_OK) {
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ((struct sockaddr *)socker_add_info)->sa_family = ((idx == V4_TCP || idx == V4_UDP || idx == UDP_MULTICAST) ?
|
||
+ AF_INET : AF_INET6);
|
||
+ ((struct sockaddr_in *)socker_add_info)->sin_port = port;
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
|
||
// create the socket and listen
|
||
-int32_t create_socket_and_listen(int32_t *socket_fd, in_addr_t ip, in_addr_t groupip, uint16_t port, const char *domain)
|
||
+int32_t create_socket_and_listen(int32_t *listen_fd_array, struct ServerIpInfo *server_ip_info,
|
||
+ uint16_t port, uint8_t protocol_mode)
|
||
{
|
||
- if (strcmp(domain, "tcp") == 0) {
|
||
- *socket_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||
- if (*socket_fd < 0) {
|
||
- PRINT_ERROR("can't create socket %d! ", errno);
|
||
+ int32_t port_multi = 1;
|
||
+ uint32_t len = 0;
|
||
+ sockaddr_t socker_add_info;
|
||
+
|
||
+ if (getbit_num(protocol_mode, UNIX) == 1) {
|
||
+ if (process_unix_fd(&listen_fd_array[UNIX], listen_fd_array) != PROGRAM_OK) {
|
||
return PROGRAM_FAULT;
|
||
}
|
||
- } else if (strcmp(domain, "unix") == 0) {
|
||
- *socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||
- if (*socket_fd < 0) {
|
||
- PRINT_ERROR("can't create socket %d! ", errno);
|
||
+ return PROGRAM_OK;
|
||
+ }
|
||
+
|
||
+ if (server_create_sock(protocol_mode, listen_fd_array) != PROGRAM_OK) {
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+
|
||
+ for (int32_t i = 0;i< PROTOCOL_MODE_MAX; i++) {
|
||
+ if (listen_fd_array[i] <= 0)
|
||
+ continue;
|
||
+ if (setsockopt(listen_fd_array[i], SOL_SOCKET, SO_REUSEPORT, (void *)&port_multi, sizeof(int32_t)) < 0) {
|
||
+ PRINT_ERROR("can't set the option of socket %d! ", errno);
|
||
return PROGRAM_FAULT;
|
||
}
|
||
- } else if (strcmp(domain, "udp") == 0) {
|
||
- *socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||
- if (*socket_fd < 0) {
|
||
- PRINT_ERROR("can't create socket %d! ", errno);
|
||
+ if (set_socket_unblock(listen_fd_array[i]) < 0) {
|
||
+ PRINT_ERROR("can't set the socket to unblock! ");
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ if (socket_add_info_init(i, port, server_ip_info, &socker_add_info, listen_fd_array) != PROGRAM_OK) {
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+
|
||
+ len = ((i == V4_TCP || i == V4_UDP || i == UDP_MULTICAST) ?
|
||
+ sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
|
||
+
|
||
+ if (bind(listen_fd_array[i], (struct sockaddr *)&socker_add_info, len) < 0) {
|
||
+ PRINT_ERROR("can't bind the address %d!, i=%d, listen_fd_array[i]=%d ", errno, i, listen_fd_array[i]);
|
||
return PROGRAM_FAULT;
|
||
}
|
||
+
|
||
+ if (i == V4_TCP || i == V6_TCP) {
|
||
+ if (listen(listen_fd_array[i], SERVER_SOCKET_LISTEN_BACKLOG) < 0) {
|
||
+ PRINT_ERROR("server socket can't lisiten %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+ }
|
||
}
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
|
||
- int32_t port_multi = 1;
|
||
- if (setsockopt(*socket_fd, SOL_SOCKET, SO_REUSEPORT, (void *)&port_multi, sizeof(int32_t)) < 0) {
|
||
- PRINT_ERROR("can't set the option of socket %d! ", errno);
|
||
+static int32_t creat_socket_init(int32_t *socket_fd, struct ClientUnit *client_unit, sockaddr_t *server_addr)
|
||
+{
|
||
+ ip_addr_t *ip = &client_unit->ip;
|
||
+ const char *domain = client_unit->domain;
|
||
+
|
||
+ if (strcmp(domain, "tcp") == 0) {
|
||
+ *socket_fd = socket(ip->addr_family, SOCK_STREAM, 0);
|
||
+ } else {
|
||
+ *socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||
+ }
|
||
+ if (*socket_fd < 0) {
|
||
+ PRINT_ERROR("client can't create socket %d! ", errno);
|
||
return PROGRAM_FAULT;
|
||
}
|
||
|
||
@@ -48,106 +228,118 @@ int32_t create_socket_and_listen(int32_t *socket_fd, in_addr_t ip, in_addr_t gro
|
||
return PROGRAM_FAULT;
|
||
}
|
||
|
||
- if (strcmp(domain, "tcp") == 0) {
|
||
- struct sockaddr_in socket_addr;
|
||
- memset_s(&socket_addr, sizeof(socket_addr), 0, sizeof(socket_addr));
|
||
- socket_addr.sin_family = AF_INET;
|
||
- socket_addr.sin_addr.s_addr = ip;
|
||
- socket_addr.sin_port = port;
|
||
- if (bind(*socket_fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) < 0) {
|
||
- PRINT_ERROR("can't bind the address to socket %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
+ ((struct sockaddr *)server_addr)->sa_family = ip->addr_family;
|
||
|
||
- if (listen(*socket_fd, SERVER_SOCKET_LISTEN_BACKLOG) < 0) {
|
||
- PRINT_ERROR("server socket can't lisiten %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static int32_t pocess_connect_sport(int32_t *socket_fd, struct ClientUnit *client_unit, sockaddr_t *server_addr)
|
||
+{
|
||
+ uint16_t sport = client_unit->sport;
|
||
+ ip_addr_t *ip = &client_unit->ip;
|
||
+ uint32_t addr_len = ip->addr_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||
+
|
||
+ if (sport) {
|
||
+ if (ip->addr_family == AF_INET) {
|
||
+ ((struct sockaddr_in *)server_addr)->sin_addr.s_addr = htonl(INADDR_ANY);
|
||
+ } else if (ip->addr_family == AF_INET6) {
|
||
+ ((struct sockaddr_in6 *)server_addr)->sin6_addr = in6addr_any;
|
||
}
|
||
- } else if (strcmp(domain, "unix") == 0) {
|
||
- struct sockaddr_un socket_addr;
|
||
- unlink(SOCKET_UNIX_DOMAIN_FILE);
|
||
- socket_addr.sun_family = AF_UNIX;
|
||
- strcpy_s(socket_addr.sun_path, sizeof(socket_addr.sun_path), SOCKET_UNIX_DOMAIN_FILE);
|
||
- if (bind(*socket_fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_un)) < 0) {
|
||
+ ((struct sockaddr_in *)server_addr)->sin_port = sport;
|
||
+ if (bind(*socket_fd, (struct sockaddr *)server_addr, addr_len) < 0) {
|
||
PRINT_ERROR("can't bind the address to socket %d! ", errno);
|
||
return PROGRAM_FAULT;
|
||
}
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
|
||
- if (listen(*socket_fd, SERVER_SOCKET_LISTEN_BACKLOG) < 0) {
|
||
- PRINT_ERROR("server socket can't lisiten %d! ", errno);
|
||
+static int32_t pocess_unix_create_connect(int32_t *socket_fd)
|
||
+{
|
||
+ *socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||
+ if (*socket_fd < 0) {
|
||
+ PRINT_ERROR("client can't create socket %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
+ }
|
||
+
|
||
+ struct sockaddr_un server_addr;
|
||
+ server_addr.sun_family = AF_UNIX;
|
||
+ strcpy_s(server_addr.sun_path, sizeof(server_addr.sun_path), SOCKET_UNIX_DOMAIN_FILE);
|
||
+ if (connect(*socket_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_un)) < 0) {
|
||
+ if (errno == EINPROGRESS) {
|
||
+ return PROGRAM_INPROGRESS;
|
||
+ } else {
|
||
+ PRINT_ERROR("client can't connect to the server %d! ", errno);
|
||
return PROGRAM_FAULT;
|
||
}
|
||
- } else if (strcmp(domain, "udp") == 0) {
|
||
- struct sockaddr_in socket_addr;
|
||
- memset_s(&socket_addr, sizeof(socket_addr), 0, sizeof(socket_addr));
|
||
- socket_addr.sin_family = AF_INET;
|
||
- socket_addr.sin_port = port;
|
||
-
|
||
- if (groupip) {
|
||
- struct ip_mreq mreq;
|
||
- mreq.imr_multiaddr.s_addr = groupip;
|
||
- mreq.imr_interface.s_addr = ip;
|
||
- if (setsockopt(*socket_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -1) {
|
||
- PRINT_ERROR("can't set the address to group %d! ", errno);
|
||
- return PROGRAM_FAULT;;
|
||
+ }
|
||
+ return PROGRAM_OK;
|
||
+}
|
||
+
|
||
+static int32_t pocess_udp_multicast(int32_t *socket_fd, struct ClientUnit *client_unit, sockaddr_t *server_addr)
|
||
+{
|
||
+ const uint32_t loop = client_unit->loop;
|
||
+ ip_addr_t *groupip = &client_unit->groupip;
|
||
+ if (client_unit->protocol_type_mode == UDP_MULTICAST) {
|
||
+ /* set the local device for a multicast socket */
|
||
+ ((struct sockaddr_in *)server_addr)->sin_addr = groupip->u_addr.ip4;
|
||
+
|
||
+ struct in_addr localInterface;
|
||
+ localInterface.s_addr = client_unit->groupip_interface.u_addr.ip4.s_addr;
|
||
+ if (localInterface.s_addr) {
|
||
+ if (setsockopt(*socket_fd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface,
|
||
+ sizeof(localInterface)) < 0) {
|
||
+ PRINT_ERROR("can't set the multicast interface %d! ", errno);
|
||
+ return PROGRAM_FAULT;
|
||
}
|
||
- socket_addr.sin_addr.s_addr = groupip;
|
||
- } else {
|
||
- socket_addr.sin_addr.s_addr = ip;
|
||
}
|
||
|
||
- if (bind(*socket_fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) < 0) {
|
||
- PRINT_ERROR("can't bind the address to socket %d! ", errno);
|
||
+ /* sent multicast packets should be looped back to the local socket */
|
||
+ if (setsockopt(*socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) == -1) {
|
||
+ PRINT_ERROR("can't set the multicast loop %d! ", errno);
|
||
return PROGRAM_FAULT;
|
||
- }
|
||
+ }
|
||
}
|
||
-
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
// create the socket and connect
|
||
-int32_t create_socket_and_connect(int32_t *socket_fd, in_addr_t ip, in_addr_t groupip, uint16_t port, uint16_t sport, const char *domain, const char *api)
|
||
+int32_t create_socket_and_connect(int32_t *socket_fd, struct ClientUnit *client_unit)
|
||
{
|
||
+ ip_addr_t *ip = &client_unit->ip;
|
||
+ const char *domain = client_unit->domain;
|
||
+ const char *api = client_unit->api;
|
||
+
|
||
+ sockaddr_t server_addr;
|
||
+
|
||
if (strcmp(domain, "tcp") == 0 || strcmp(domain, "udp") == 0) {
|
||
- if (strcmp(domain, "tcp") == 0) {
|
||
- *socket_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||
- } else {
|
||
- *socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||
- }
|
||
- if (*socket_fd < 0) {
|
||
- PRINT_ERROR("client can't create socket %d! ", errno);
|
||
+ uint32_t addr_len = ip->addr_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||
+ memset_s(&server_addr, addr_len, 0, addr_len);
|
||
+
|
||
+ if (creat_socket_init(socket_fd, client_unit, &server_addr) != PROGRAM_OK) {
|
||
return PROGRAM_FAULT;
|
||
}
|
||
|
||
- if (set_socket_unblock(*socket_fd) < 0) {
|
||
- PRINT_ERROR("can't set the socket to unblock! ");
|
||
+ if (pocess_connect_sport(socket_fd, client_unit, &server_addr) < 0) {
|
||
return PROGRAM_FAULT;
|
||
}
|
||
|
||
- struct sockaddr_in server_addr;
|
||
- memset_s(&server_addr, sizeof(server_addr), 0, sizeof(server_addr));
|
||
- server_addr.sin_family = AF_INET;
|
||
- if (sport) {
|
||
- server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||
- server_addr.sin_port = sport;
|
||
- if (bind(*socket_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)) < 0) {
|
||
- PRINT_ERROR("can't bind the address to socket %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
+ if (ip->addr_family == AF_INET) {
|
||
+ ((struct sockaddr_in *)&server_addr)->sin_addr = ip->u_addr.ip4;
|
||
+ } else if (ip->addr_family == AF_INET6) {
|
||
+ ((struct sockaddr_in6 *)&server_addr)->sin6_addr = ip->u_addr.ip6;
|
||
}
|
||
- server_addr.sin_addr.s_addr = ip;
|
||
- server_addr.sin_port = port;
|
||
+ ((struct sockaddr_in *)&server_addr)->sin_port = client_unit->port;
|
||
+
|
||
if (strcmp(domain, "udp") == 0) {
|
||
- if (groupip) {
|
||
- server_addr.sin_addr.s_addr = groupip;
|
||
- if (setsockopt(*socket_fd, IPPROTO_IP, IP_MULTICAST_IF, &ip, sizeof(ip)) != 0) {
|
||
- PRINT_ERROR("can't set the multicast interface %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
+ int32_t ret = pocess_udp_multicast(socket_fd, client_unit, &server_addr);
|
||
+ if (ret != PROGRAM_OK) {
|
||
+ return ret;
|
||
}
|
||
}
|
||
+
|
||
if (strcmp(domain, "udp") != 0 || strcmp(api, "recvfromsendto") != 0) {
|
||
- if (connect(*socket_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)) < 0) {
|
||
+ if (connect(*socket_fd, (struct sockaddr *)&server_addr, addr_len) < 0) {
|
||
if (errno == EINPROGRESS) {
|
||
return PROGRAM_INPROGRESS;
|
||
} else {
|
||
@@ -157,25 +349,11 @@ int32_t create_socket_and_connect(int32_t *socket_fd, in_addr_t ip, in_addr_t gr
|
||
}
|
||
}
|
||
} else if (strcmp(domain, "unix") == 0) {
|
||
- *socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||
- if (*socket_fd < 0) {
|
||
- PRINT_ERROR("client can't create socket %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
-
|
||
- struct sockaddr_un server_addr;
|
||
- server_addr.sun_family = AF_UNIX;
|
||
- strcpy_s(server_addr.sun_path, sizeof(server_addr.sun_path), SOCKET_UNIX_DOMAIN_FILE);
|
||
- if (connect(*socket_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_un)) < 0) {
|
||
- if (errno == EINPROGRESS) {
|
||
- return PROGRAM_INPROGRESS;
|
||
- } else {
|
||
- PRINT_ERROR("client can't connect to the server %d! ", errno);
|
||
- return PROGRAM_FAULT;
|
||
- }
|
||
+ int32_t ret = pocess_unix_create_connect(socket_fd);
|
||
+ if (ret != PROGRAM_OK) {
|
||
+ return ret;
|
||
}
|
||
}
|
||
-
|
||
return PROGRAM_OK;
|
||
}
|
||
|
||
diff --git a/src/lstack/core/lstack_protocol_stack.c b/src/lstack/core/lstack_protocol_stack.c
|
||
index 3e6eeef..e272a04 100644
|
||
--- a/src/lstack/core/lstack_protocol_stack.c
|
||
+++ b/src/lstack/core/lstack_protocol_stack.c
|
||
@@ -655,7 +655,6 @@ int32_t stack_setup_thread(void)
|
||
goto OUT1;
|
||
}
|
||
}
|
||
-
|
||
for (uint32_t i = 0; i < queue_num; i++) {
|
||
if (get_global_cfg_params()->seperate_send_recv) {
|
||
if (i % 2 == 0) {
|
||
@@ -694,6 +693,7 @@ int32_t stack_setup_thread(void)
|
||
g_stack_group.stack_num = queue_num;
|
||
|
||
return 0;
|
||
+
|
||
OUT1:
|
||
for (int32_t i = 0; i < queue_num; ++i) {
|
||
if (t_params[i] != NULL) {
|
||
--
|
||
2.33.0
|
||
|