├── wrapper ├── README.md ├── makefile ├── ut_crc32.h ├── ut_rpc_svr.h ├── ut_rpc.h ├── ut_rpc_clt.h ├── test_rpc_svr.c ├── test_rpc_clt.c ├── ut_rpc.c ├── ut_crc32.c ├── ut_rpc_svr.c └── ut_rpc_clt.c ├── c1000k ├── makefile ├── client.c └── server.c ├── test ├── makefile ├── test_timer.c ├── test_unix_stream_clt.c ├── test_udp_clt.c ├── test_tcp_clt.c ├── test_unix_dgram_clt.c ├── test_unix_seqpacket_clt.c ├── test_unix_fd_clt.c ├── test_state.c ├── test_clt.c ├── echo_server.c └── listener_worker.c ├── .gitignore ├── asnw ├── makefile ├── nw_evt.h ├── nw_timer.h ├── nw_timer.c ├── nw_evt.c ├── nw_state.h ├── nw_job.h ├── nw_ses.h ├── nw_buf.h ├── nw_sock.h ├── nw_clt.h ├── nw_svr.h ├── nw_buf.c ├── nw_job.c ├── nw_state.c ├── nw_sock.c ├── nw_clt.c ├── nw_svr.c └── nw_ses.c ├── LICENSE └── README.md /wrapper/README.md: -------------------------------------------------------------------------------- 1 | ut_rpc is a simple rpc solution, with a common header and heartbeat check. 2 | -------------------------------------------------------------------------------- /c1000k/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc server.c -I ../network/ -L ../network/ -lnetwork -lev -std=gnu99 -Wall -g -o server 3 | gcc client.c -I ../network/ -L ../network/ -lnetwork -lev -std=gnu99 -Wall -g -o client 4 | 5 | clean: 6 | rm server client 7 | -------------------------------------------------------------------------------- /wrapper/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc test_rpc_svr.c ut_rpc_svr.c ut_rpc.c ut_crc32.c -I ../network/ -L ../network/ -lnetwork -lev -g -Wall -std=gnu99 -o test_rpc_svr 3 | gcc test_rpc_clt.c ut_rpc_clt.c ut_rpc.c ut_crc32.c -I ../network/ -L ../network/ -lnetwork -lev -g -Wall -std=gnu99 -o test_rpc_clt 4 | -------------------------------------------------------------------------------- /wrapper/ut_crc32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/29, create 4 | */ 5 | 6 | # ifndef _UT_CRC32_H_ 7 | # define _UT_CRC32_H_ 8 | 9 | # include 10 | # include 11 | 12 | uint32_t generate_crc32c(const char *string, size_t length); 13 | 14 | # endif 15 | -------------------------------------------------------------------------------- /test/makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc echo_server.c -I ../network/ -L ../network/ -lnetwork -lev -std=gnu11 -g -o echo_server 3 | gcc test_clt.c -I ../network/ -L ../network/ -lnetwork -lev -std=gnu11 -g -o test_clt 4 | gcc listener_worker.c -I ../network/ -L ../network/ -lnetwork -lev -std=gnu11 -g -o listener_worker 5 | 6 | clean: 7 | rm -rf echo_server test_clt listener_worker 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | -------------------------------------------------------------------------------- /asnw/makefile: -------------------------------------------------------------------------------- 1 | SOURCE := $(wildcard *.c) 2 | OBJS := $(patsubst %.c, %.o, $(SOURCE)) 3 | CC := gcc 4 | CFLAGS := -Wall -Wno-strict-aliasing -Wno-uninitialized -g -rdynamic -std=gnu11 5 | 6 | .PHONY : all clean install 7 | 8 | TARGET := libasnw.a 9 | 10 | all : $(TARGET) 11 | 12 | clean : 13 | rm -rf *.d *.o $(TARGET) 14 | 15 | $(TARGET) : $(OBJS) 16 | ar -rs $@ $^ 17 | .c.o : 18 | $(CC) $(CFLAGS) -c -o $@ $< $(INCS) 19 | 20 | -------------------------------------------------------------------------------- /asnw/nw_evt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: net workd event, base on libev 3 | * History: yang@haipo.me, 2016/03/19, create 4 | */ 5 | 6 | # ifndef _NW_EVT_H_ 7 | # define _NW_EVT_H_ 8 | 9 | # include "ev.h" 10 | 11 | /* the default global loop instance */ 12 | extern struct ev_loop *nw_default_loop; 13 | 14 | /* initialization the event loop */ 15 | void nw_loop_init(void); 16 | 17 | /* start event loop */ 18 | void nw_loop_run(void); 19 | 20 | /* break event loop */ 21 | void nw_loop_break(void); 22 | 23 | /* break event loop after specail seconds */ 24 | void nw_loop_break_later(double waittime); 25 | 26 | # endif 27 | 28 | -------------------------------------------------------------------------------- /test/test_timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/20, create 4 | */ 5 | 6 | # include 7 | 8 | # include "nw_timer.h" 9 | 10 | void on_timer(nw_timer *timer, void *private) 11 | { 12 | int *count = (int *)private; 13 | *count += 1; 14 | printf("repeat %d\n", *count); 15 | printf("remaining %f\n", nw_timer_remaining(timer)); 16 | if (*count == 10) 17 | { 18 | nw_timer_stop(timer); 19 | } 20 | } 21 | 22 | int main() 23 | { 24 | int count = 0; 25 | nw_timer timer; 26 | nw_timer_set(&timer, 1.0, true, on_timer, &count); 27 | nw_timer_start(&timer); 28 | 29 | nw_loop_run(); 30 | printf("stop!\n"); 31 | 32 | return 0; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /wrapper/ut_rpc_svr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/29, create 4 | */ 5 | 6 | # ifndef _UT_RPC_SVR_H_ 7 | # define _UT_RPC_SVR_H_ 8 | 9 | # include "ut_rpc.h" 10 | # include "nw_svr.h" 11 | # include "nw_timer.h" 12 | # include "nw_buf.h" 13 | 14 | typedef struct rpc_svr_type { 15 | void (*on_recv_pkg)(nw_ses *ses, rpc_pkg *pkg); 16 | void (*on_new_connection)(nw_ses *ses); 17 | void (*on_connection_close)(nw_ses *ses); 18 | } rpc_svr_type; 19 | 20 | typedef struct rpc_svr { 21 | nw_svr *raw_svr; 22 | nw_timer timer; 23 | nw_cache *privdata_cache; 24 | void (*on_recv_pkg)(nw_ses *ses, rpc_pkg *pkg); 25 | void (*on_new_connection)(nw_ses *ses); 26 | } rpc_svr; 27 | 28 | rpc_svr *rpc_svr_create(nw_svr_cfg *cfg, rpc_svr_type *type); 29 | int rpc_svr_start(rpc_svr *svr); 30 | int rpc_svr_stop(rpc_svr *svr); 31 | void rpc_svr_release(rpc_svr *svr); 32 | void rpc_svr_close_clt(rpc_svr *svr, nw_ses *ses); 33 | 34 | # endif 35 | 36 | -------------------------------------------------------------------------------- /asnw/nw_timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/20, create 4 | */ 5 | 6 | # ifndef _NW_TIMER_H_ 7 | # define _NW_TIMER_H_ 8 | 9 | # include 10 | 11 | # include "nw_evt.h" 12 | 13 | struct nw_timer; 14 | typedef void (*nw_timer_callback)(struct nw_timer *timer, void *privdata); 15 | 16 | typedef struct nw_timer { 17 | ev_timer ev; 18 | struct ev_loop *loop; 19 | double interval; 20 | nw_timer_callback callback; 21 | void *privdata; 22 | } nw_timer; 23 | 24 | /* 25 | * set the timer call the callback after interval seconds. 26 | * if repeated is true, callback will be called every interval seconds 27 | * privdata will pass to callback function 28 | */ 29 | void nw_timer_set(nw_timer *timer, double interval, bool repeated, nw_timer_callback callback, void *privdata); 30 | void nw_timer_start(nw_timer *timer); 31 | void nw_timer_stop(nw_timer *timer); 32 | bool nw_timer_active(nw_timer *timer); 33 | double nw_timer_remaining(nw_timer *timer); 34 | 35 | # endif 36 | 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 haipo yang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /wrapper/ut_rpc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/29, create 4 | */ 5 | 6 | # ifndef _UT_RPC_H_ 7 | # define _UT_RPC_H_ 8 | 9 | # include 10 | # include "nw_ses.h" 11 | 12 | # define RPC_MAX_PKG_SIZE (1024*1024) 13 | # define RPC_PKG_MAGIC 0x70656562 14 | 15 | # define RPC_PKG_TYPE_REQUEST 0 16 | # define RPC_PKG_TYPE_REPLY 1 17 | # define RPC_PKG_TYPE_PUSH 2 18 | 19 | # pragma pack(1) 20 | typedef struct rpc_pkg { 21 | uint32_t magic; 22 | uint32_t command; 23 | uint16_t pkg_type; 24 | uint32_t result; 25 | uint32_t crc32; 26 | uint32_t sequence; 27 | uint64_t req_id; 28 | uint32_t body_size; 29 | uint16_t ext_size; 30 | void * ext; 31 | void * body; 32 | } rpc_pkg; 33 | # pragma pack() 34 | 35 | # define RPC_PKG_HEAD_SIZE (sizeof(rpc_pkg) - sizeof(void *) * 2) 36 | 37 | int rpc_decode(nw_ses *ses, void *data, size_t max); 38 | int rpc_send(nw_ses *ses, rpc_pkg *pkg); 39 | 40 | double current_timestamp(void); 41 | 42 | # define RPC_HEARTBEAT_INTERVAL 1.0 43 | # define RPC_HEARTBEAT_TIMEOUT 3.0 44 | 45 | # define RPC_CMD_HEARTBEAT 0 46 | 47 | # endif 48 | 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ASNW: asynchronous network 2 | A high performance asynchronous network programming library based on libev and in C. 3 | 4 | Network including the following modules: 5 | 6 | - `nw_buf` : buf manager 7 | - `nw_evt` : main loop 8 | - `nw_sock` : socket releated 9 | - `nw_ses` : network session manager 10 | - `nw_timer` : timer, call a function after specify time, repeat or not repeat 11 | - `nw_svr` : server implement, one server can bind multi address in different sock type 12 | - `nw_clt` : client implement, auto reconnect 13 | - `nw_state` : state machine with timeout 14 | - `nw_job` : thread pool 15 | 16 | ### example 17 | - `echo_server` : a single process server 18 | 19 | see test/echo_server.c 20 | 21 | ``` 22 | ./echo_server 'tcp@127.0.0.1:1234' 'stream@/tmp/echo_stream.sock' 23 | ``` 24 | 25 | - `listener_worker`: one process listen, multi process process connection 26 | 27 | see test/listener_worker.c 28 | 29 | ``` 30 | ./listener_worker 'tcp@127.0.0.1:1234' 10 31 | ``` 32 | 33 | ### wrapper 34 | Network is a very basic network programming library, but you can wrapper the basic nw_clt 35 | and nw_svr to be more complex. 36 | 37 | wrapper/ut_rpc is a wrapper example. 38 | -------------------------------------------------------------------------------- /wrapper/ut_rpc_clt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/30, create 4 | */ 5 | 6 | # ifndef _UT_RPC_CLT_H_ 7 | # define _UT_RPC_CLT_H_ 8 | 9 | # include "ut_rpc.h" 10 | # include "nw_clt.h" 11 | # include "nw_timer.h" 12 | 13 | typedef struct rpc_clt_cfg { 14 | char *name; 15 | uint32_t addr_count; 16 | nw_addr_t *addr_arr; 17 | int sock_type; 18 | uint32_t read_mem; 19 | uint32_t write_mem; 20 | double reconnect_timeout; 21 | } rpc_clt_cfg; 22 | 23 | typedef struct rpc_clt_type { 24 | void (*on_recv_pkg)(nw_ses *ses, rpc_pkg *pkg); 25 | void (*on_connect)(nw_ses *ses, bool result); 26 | } rpc_clt_type; 27 | 28 | typedef struct rpc_clt { 29 | char *name; 30 | nw_clt *raw_clt; 31 | uint32_t addr_count; 32 | uint32_t curr_index; 33 | nw_addr_t *addr_arr; 34 | nw_timer timer; 35 | double last_heartbeat; 36 | void (*on_recv_pkg)(nw_ses *ses, rpc_pkg *pkg); 37 | void (*on_connect)(nw_ses *ses, bool result); 38 | } rpc_clt; 39 | 40 | rpc_clt *rpc_clt_create(rpc_clt_cfg *cfg, rpc_clt_type *type); 41 | int rpc_clt_start(rpc_clt *clt); 42 | int rpc_clt_close(rpc_clt *clt); 43 | int rpc_clt_send(rpc_clt *clt, rpc_pkg *pkg); 44 | void rpc_clt_release(rpc_clt *clt); 45 | bool rpc_clt_connected(rpc_clt *clt); 46 | 47 | # endif 48 | 49 | -------------------------------------------------------------------------------- /asnw/nw_timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/20, create 4 | */ 5 | 6 | # include "nw_timer.h" 7 | 8 | static void on_timer(struct ev_loop *loop, ev_timer *ev, int events) 9 | { 10 | struct nw_timer *timer = (struct nw_timer *)ev; 11 | timer->callback(timer, timer->privdata); 12 | } 13 | 14 | void nw_timer_set(nw_timer *timer, double interval, bool repeated, nw_timer_callback callback, void *privdata) 15 | { 16 | nw_loop_init(); 17 | if (repeated) { 18 | ev_timer_init(&timer->ev, on_timer, interval, interval); 19 | } else { 20 | ev_timer_init(&timer->ev, on_timer, interval, 0); 21 | } 22 | timer->loop = nw_default_loop; 23 | timer->interval = interval; 24 | timer->callback = callback; 25 | timer->privdata = privdata; 26 | } 27 | 28 | void nw_timer_start(nw_timer *timer) 29 | { 30 | if (!ev_is_active(&timer->ev)) { 31 | ev_timer_start(timer->loop, &timer->ev); 32 | } 33 | } 34 | 35 | void nw_timer_stop(nw_timer *timer) 36 | { 37 | if (ev_is_active(&timer->ev)) { 38 | ev_timer_stop(timer->loop, &timer->ev); 39 | } 40 | } 41 | 42 | bool nw_timer_active(nw_timer *timer) 43 | { 44 | if (ev_is_active(&timer->ev)) { 45 | return true; 46 | } 47 | return false; 48 | } 49 | 50 | double nw_timer_remaining(nw_timer *timer) 51 | { 52 | return ev_timer_remaining(timer->loop, &timer->ev); 53 | } 54 | 55 | -------------------------------------------------------------------------------- /test/test_unix_stream_clt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/21, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | # include 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | if (argc != 2) { 19 | printf("usage: %s path\n", argv[0]); 20 | exit(0); 21 | } 22 | 23 | int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); 24 | if (sockfd < 0) 25 | error(1, errno, "socket fail"); 26 | 27 | struct sockaddr_un un; 28 | memset(&un, 0, sizeof(un)); 29 | un.sun_family = AF_UNIX; 30 | strncpy(un.sun_path, argv[1], sizeof(un.sun_path) - 1); 31 | 32 | if (connect(sockfd, (struct sockaddr *)&un, sizeof(un)) < 0) { 33 | error(1, errno, "conect fail"); 34 | } 35 | 36 | char *line = NULL; 37 | size_t buf_size = 0; 38 | while (getline(&line, &buf_size, stdin) != -1) { 39 | int ret = write(sockfd, line, strlen(line)); 40 | if (ret < 0) { 41 | error(1, errno, "write fail"); 42 | } 43 | char buf[65535]; 44 | ret = read(sockfd, buf, sizeof(buf)); 45 | if (ret < 0) { 46 | error(1, errno, "read fail"); 47 | } 48 | buf[ret] = 0; 49 | printf("%s", buf); 50 | } 51 | 52 | close(sockfd); 53 | 54 | return 0; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /test/test_udp_clt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/21, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | # include 15 | # include 16 | # include 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | if (argc != 3) { 21 | printf("usage: %s ip port\n", argv[0]); 22 | exit(0); 23 | } 24 | 25 | int sockfd = socket(AF_INET, SOCK_DGRAM, 0); 26 | if (sockfd < 0) { 27 | error(1, errno, "create socket fail"); 28 | } 29 | struct sockaddr_in addr; 30 | memset(&addr, 0, sizeof(addr)); 31 | addr.sin_family = AF_INET; 32 | if (inet_aton(argv[1], &addr.sin_addr) == 0) { 33 | error(1, errno, "ip error"); 34 | } 35 | addr.sin_port = htons(atoi(argv[2])); 36 | 37 | char *line = NULL; 38 | size_t buf_size = 0; 39 | while (getline(&line, &buf_size, stdin) != -1) { 40 | int ret = sendto(sockfd, line, strlen(line), 0, (struct sockaddr *)&addr, sizeof(addr)); 41 | if (ret < 0) { 42 | error(1, errno, "sendto fail\n"); 43 | } 44 | 45 | char buf[10240]; 46 | ret = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL); 47 | if (ret < 0) { 48 | error(1, errno, "recvfrom fail\n"); 49 | } 50 | buf[ret] = 0; 51 | printf("%s", buf); 52 | } 53 | 54 | close(sockfd); 55 | 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /test/test_tcp_clt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/21, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | # include 15 | # include 16 | # include 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | if (argc != 3) { 21 | printf("usage: %s ip port\n", argv[0]); 22 | exit(0); 23 | } 24 | 25 | int sockfd = socket(AF_INET, SOCK_STREAM, 0); 26 | if (sockfd < 0) { 27 | error(1, errno, "create socket fail"); 28 | } 29 | struct sockaddr_in addr; 30 | memset(&addr, 0, sizeof(addr)); 31 | addr.sin_family = AF_INET; 32 | if (inet_aton(argv[1], &addr.sin_addr) == 0) { 33 | error(1, errno, "ip error"); 34 | } 35 | addr.sin_port = htons(atoi(argv[2])); 36 | 37 | if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 38 | error(1, errno, "connect fail"); 39 | } 40 | 41 | char *line = NULL; 42 | size_t buf_size = 0; 43 | while (getline(&line, &buf_size, stdin) != -1) { 44 | int ret = write(sockfd, line, strlen(line)); 45 | if (ret < 0) { 46 | error(1, errno, "write fail"); 47 | } 48 | 49 | char buf[10240]; 50 | ret = read(sockfd, buf, sizeof(buf)); 51 | if (ret < 0) { 52 | error(1, errno, "read fail"); 53 | } 54 | buf[ret] = 0; 55 | printf("%s", buf); 56 | } 57 | 58 | close(sockfd); 59 | 60 | return 0; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /test/test_unix_dgram_clt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/21, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | # include 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | if (argc != 2) { 19 | printf("usage: %s path\n", argv[0]); 20 | exit(0); 21 | } 22 | 23 | int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0); 24 | if (sockfd < 0) 25 | error(1, errno, "socket fail"); 26 | 27 | struct sockaddr_un client, server; 28 | memset(&client, 0, sizeof(client)); 29 | client.sun_family = AF_UNIX; 30 | strncpy(client.sun_path, tmpnam(NULL), sizeof(client.sun_path) - 1); 31 | unlink(client.sun_path); 32 | if (bind(sockfd, (struct sockaddr *)&client, sizeof(client)) < 0) { 33 | error(1, errno, "bind fail"); 34 | } 35 | 36 | memset(&server, 0, sizeof(server)); 37 | server.sun_family = AF_UNIX; 38 | strncpy(server.sun_path, argv[1], sizeof(server.sun_path) - 1); 39 | 40 | char *line = NULL; 41 | size_t buf_size = 0; 42 | while (getline(&line, &buf_size, stdin) != -1) { 43 | int ret = sendto(sockfd, line, strlen(line), 0, (struct sockaddr *)&server, sizeof(server)); 44 | if (ret < 0) { 45 | error(1, errno, "sendto fail"); 46 | } 47 | char buf[65535]; 48 | ret = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL); 49 | if (ret < 0) { 50 | error(1, errno, "recvfrom fail"); 51 | } 52 | buf[ret] = 0; 53 | printf("%s", buf); 54 | } 55 | 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /asnw/nw_evt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/19, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | 11 | # include "nw_evt.h" 12 | 13 | struct ev_loop *nw_default_loop; 14 | static int initialized; 15 | static int running; 16 | static ev_timer break_timer; 17 | 18 | static void fatal_error(const char *msg) 19 | { 20 | char exe_path[PATH_MAX]; 21 | ssize_t ret = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); 22 | exe_path[ret] = 0; 23 | 24 | openlog(basename(exe_path), LOG_PERROR | LOG_PID, LOG_DAEMON); 25 | syslog(LOG_ERR, "%s", msg); 26 | closelog(); 27 | } 28 | 29 | void nw_loop_init(void) 30 | { 31 | if (initialized) 32 | return; 33 | 34 | unsigned int flag = 0; 35 | flag |= EVFLAG_AUTO; 36 | flag |= EVFLAG_NOENV; 37 | flag |= EVFLAG_FORKCHECK; 38 | nw_default_loop = ev_loop_new(flag); 39 | ev_set_syserr_cb(fatal_error); 40 | initialized = 1; 41 | } 42 | 43 | void nw_loop_run(void) 44 | { 45 | if (!initialized) 46 | return; 47 | 48 | running = 1; 49 | ev_run(nw_default_loop, 0); 50 | return; 51 | } 52 | 53 | void nw_loop_break(void) 54 | { 55 | if (!initialized) 56 | return; 57 | if (!running) 58 | return; 59 | 60 | ev_break(nw_default_loop, EVBREAK_ALL); 61 | running = 0; 62 | return; 63 | } 64 | 65 | static void on_break_timer(struct ev_loop *loop, ev_timer *ev, int events) 66 | { 67 | nw_loop_break(); 68 | } 69 | 70 | void nw_loop_break_later(double waittime) 71 | { 72 | if (!initialized) 73 | return; 74 | if (!running) 75 | return; 76 | 77 | if (!ev_is_active(&break_timer)) { 78 | ev_timer_init(&break_timer, on_break_timer, waittime, 0); 79 | ev_timer_start(nw_default_loop, &break_timer); 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /wrapper/test_rpc_svr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/30, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | 13 | # include "ut_rpc_svr.h" 14 | 15 | void on_new_connection(nw_ses *ses) 16 | { 17 | printf("new connection from: %s\n", nw_sock_human_addr(&ses->peer_addr)); 18 | } 19 | 20 | void on_connection_close(nw_ses *ses) 21 | { 22 | printf("connection: %s close\n", nw_sock_human_addr(&ses->peer_addr)); 23 | } 24 | 25 | void on_recv_pkg(nw_ses *ses, rpc_pkg *pkg) 26 | { 27 | rpc_send(ses, pkg); 28 | } 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | if (argc < 2) { 33 | printf("usage: %s bind...\n", argv[0]); 34 | exit(0); 35 | } 36 | 37 | int bind_count = argc - 1; 38 | nw_svr_bind *bind_arr = malloc(sizeof(nw_svr_bind) * bind_count); 39 | assert(bind_arr != NULL); 40 | memset(bind_arr, sizeof(nw_svr_bind) * bind_count, 0); 41 | for (int i = 0; i < bind_count; ++i) { 42 | int ret = nw_sock_cfg_parse(argv[i + 1], &bind_arr[i].addr, &bind_arr[i].sock_type); 43 | if (ret < 0) { 44 | printf("parse bind: %s fail: %d\n", argv[1], ret); 45 | exit(0); 46 | } 47 | } 48 | 49 | nw_svr_cfg cfg; 50 | memset(&cfg, 0, sizeof(cfg)); 51 | cfg.bind_count = bind_count; 52 | cfg.bind_arr = bind_arr; 53 | 54 | rpc_svr_type type; 55 | memset(&type, 0, sizeof(type)); 56 | type.on_recv_pkg = on_recv_pkg; 57 | type.on_new_connection = on_new_connection; 58 | type.on_connection_close = on_connection_close; 59 | 60 | rpc_svr *svr = rpc_svr_create(&cfg, &type); 61 | if (svr == NULL) 62 | error(1, errno, "rpc_svr_create fail"); 63 | rpc_svr_start(svr); 64 | 65 | nw_loop_run(); 66 | 67 | return 0; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /wrapper/test_rpc_clt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/30, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | 13 | # include "ut_rpc_clt.h" 14 | # include "nw_timer.h" 15 | 16 | void on_connect(nw_ses *ses, bool result) 17 | { 18 | if (result) { 19 | printf("connect: %s success\n", nw_sock_human_addr(&ses->peer_addr)); 20 | } else { 21 | printf("connect: %s fail\n", nw_sock_human_addr(&ses->peer_addr)); 22 | } 23 | } 24 | 25 | void on_recv_pkg(nw_ses *ses, rpc_pkg *pkg) 26 | { 27 | } 28 | 29 | void on_timer(nw_timer *timer, void *privdata) 30 | { 31 | char *str = "ping"; 32 | rpc_pkg pkg; 33 | memset(&pkg, 0, sizeof(pkg)); 34 | pkg.command = 100; 35 | pkg.body_size = strlen(str); 36 | pkg.body = str; 37 | rpc_clt *clt = privdata; 38 | rpc_clt_send(clt, &pkg); 39 | } 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | if (argc < 3) { 44 | printf("usage: %s name addr...\n", argv[0]); 45 | exit(0); 46 | } 47 | 48 | rpc_clt_cfg cfg; 49 | memset(&cfg, 0, sizeof(cfg)); 50 | cfg.name = strdup(argv[1]); 51 | cfg.addr_count = argc - 2; 52 | cfg.addr_arr = malloc(sizeof(nw_addr_t) * cfg.addr_count); 53 | for (int i = 0; i < cfg.addr_count; ++i) { 54 | if (nw_sock_cfg_parse(argv[i + 2], &cfg.addr_arr[i], &cfg.sock_type) < 0) 55 | error(1, errno, "parse peer addr: %s fail", argv[i + 2]); 56 | } 57 | 58 | rpc_clt_type type; 59 | memset(&type, 0, sizeof(type)); 60 | type.on_connect = on_connect; 61 | type.on_recv_pkg = on_recv_pkg; 62 | 63 | rpc_clt *clt = rpc_clt_create(&cfg, &type); 64 | if (clt == NULL) 65 | error(1, errno, "rpc_clt_create fail"); 66 | rpc_clt_start(clt); 67 | 68 | nw_timer timer; 69 | nw_timer_set(&timer, 1.0, true, on_timer, clt); 70 | nw_timer_start(&timer); 71 | 72 | nw_loop_run(); 73 | 74 | return 0; 75 | } 76 | 77 | -------------------------------------------------------------------------------- /test/test_unix_seqpacket_clt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/21, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | # include 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | if (argc != 2) { 19 | printf("usage: %s path\n", argv[0]); 20 | exit(0); 21 | } 22 | 23 | int sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 24 | if (sockfd < 0) 25 | error(1, errno, "socket fail"); 26 | 27 | struct sockaddr_un un; 28 | memset(&un, 0, sizeof(un)); 29 | un.sun_family = AF_UNIX; 30 | strncpy(un.sun_path, argv[1], sizeof(un.sun_path) - 1); 31 | 32 | if (connect(sockfd, (struct sockaddr *)&un, sizeof(un)) < 0) { 33 | error(1, errno, "conect fail"); 34 | } 35 | 36 | char *line = NULL; 37 | size_t buf_size = 0; 38 | while (getline(&line, &buf_size, stdin) != -1) { 39 | struct msghdr msg; 40 | memset(&msg, 0, sizeof(msg)); 41 | msg.msg_name = (struct sockaddr *)&un; 42 | msg.msg_namelen = sizeof(un); 43 | struct iovec io; 44 | io.iov_base = line; 45 | io.iov_len = strlen(line); 46 | msg.msg_iov = &io; 47 | msg.msg_iovlen = 1; 48 | 49 | int ret = sendmsg(sockfd, &msg, 0); 50 | if (ret < 0) { 51 | error(1, errno, "sendmsg fail"); 52 | } 53 | 54 | char buf[10240]; 55 | struct sockaddr_un peer; 56 | msg.msg_name = (struct sockaddr *)&peer; 57 | msg.msg_namelen = sizeof(peer); 58 | io.iov_base = buf; 59 | io.iov_len = sizeof(buf); 60 | msg.msg_iov = &io; 61 | msg.msg_iovlen = 1; 62 | ret = recvmsg(sockfd, &msg, 0); 63 | if (ret < 0) { 64 | error(1, errno, "recvmsg fail"); 65 | } 66 | buf[ret] = 0; 67 | printf("%s", buf); 68 | } 69 | 70 | close(sockfd); 71 | 72 | return 0; 73 | } 74 | 75 | -------------------------------------------------------------------------------- /c1000k/client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/21, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | # include 15 | # include 16 | # include 17 | # include 18 | # include 19 | 20 | int set_file_limit(size_t limit) 21 | { 22 | struct rlimit rlim; 23 | memset(&rlim, 0, sizeof(rlim)); 24 | if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { 25 | return -1; 26 | } 27 | if (rlim.rlim_cur >= limit) 28 | return 0; 29 | rlim.rlim_cur = limit; 30 | rlim.rlim_max = limit; 31 | if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { 32 | return -1; 33 | } 34 | 35 | return 0; 36 | } 37 | 38 | int main(int argc, char *argv[]) 39 | { 40 | set_file_limit(1000000); 41 | 42 | struct sockaddr_in addr; 43 | memset(&addr, 0, sizeof(addr)); 44 | addr.sin_family = AF_INET; 45 | inet_aton("127.0.0.1", &addr.sin_addr); 46 | 47 | int max = 100; 48 | int *fds = malloc(max * 10000 * sizeof(int)); 49 | int connections = 0; 50 | for (int i = 0; i < max; ++i) { 51 | addr.sin_port = htons(5000 + i); 52 | for (int j = 0; j < 10000; ++j) { 53 | int sockfd = socket(AF_INET, SOCK_STREAM, 0); 54 | if (sockfd < 0) { 55 | goto error; 56 | } 57 | if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 58 | goto error; 59 | } 60 | fds[10000*i+j] = sockfd; 61 | 62 | usleep(100); 63 | connections += 1; 64 | if (connections % 1000 == 0) { 65 | printf("connections: %d\n", connections); 66 | } 67 | } 68 | } 69 | 70 | printf("connections: %d\n", connections); 71 | sleep(10); 72 | 73 | for (int i = 0; i < max * 10000; ++i) 74 | close(fds[i]); 75 | 76 | return 0; 77 | 78 | error: 79 | printf("connections: %d, error: %s\n", connections, strerror(errno)); 80 | return 0; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /test/test_unix_fd_clt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/21, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | # include 15 | # include 16 | # include 17 | # include 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | if (argc != 3) { 22 | printf("usage: %s path file\n", argv[0]); 23 | exit(0); 24 | } 25 | 26 | int sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 27 | if (sockfd < 0) 28 | error(1, errno, "socket fail"); 29 | 30 | struct sockaddr_un un; 31 | memset(&un, 0, sizeof(un)); 32 | un.sun_family = AF_UNIX; 33 | strncpy(un.sun_path, argv[1], sizeof(un.sun_path) - 1); 34 | 35 | if (connect(sockfd, (struct sockaddr *)&un, sizeof(un)) < 0) { 36 | error(1, errno, "conect fail"); 37 | } 38 | 39 | int fd = open(argv[2], 0); 40 | if (fd < 0) { 41 | error(1, errno, "open file fail"); 42 | } 43 | 44 | struct msghdr msg; 45 | struct iovec io; 46 | char control[CMSG_SPACE(sizeof(int))]; 47 | 48 | memset(&msg, 0, sizeof(msg)); 49 | io.iov_base = &fd; 50 | io.iov_len = sizeof(fd); 51 | msg.msg_iov = &io; 52 | msg.msg_iovlen = 1; 53 | msg.msg_control = control; 54 | msg.msg_controllen = sizeof(control); 55 | 56 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 57 | cmsg->cmsg_level = SOL_SOCKET; 58 | cmsg->cmsg_type = SCM_RIGHTS; 59 | cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 60 | *((int *)CMSG_DATA(cmsg)) = fd; 61 | 62 | int ret = sendmsg(sockfd, &msg, 0); 63 | if (ret <= 0) { 64 | error(1, errno, "sendmsg fail"); 65 | } 66 | 67 | char buf[10240]; 68 | memset(&msg, 0, sizeof(msg)); 69 | io.iov_base = buf; 70 | io.iov_len = sizeof(buf); 71 | msg.msg_iov = &io; 72 | msg.msg_iovlen = 1; 73 | ret = recvmsg(sockfd, &msg, 0); 74 | if (ret < 0) { 75 | error(1, errno, "recvmsg fail"); 76 | } 77 | 78 | buf[ret] = 0; 79 | printf("%s", buf); 80 | 81 | close(sockfd); 82 | 83 | return 0; 84 | } 85 | 86 | -------------------------------------------------------------------------------- /asnw/nw_state.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/22, create 4 | */ 5 | 6 | # ifndef _NW_STATE_H_ 7 | # define _NW_STATE_H_ 8 | 9 | # include 10 | # include 11 | 12 | # include "nw_evt.h" 13 | # include "nw_buf.h" 14 | 15 | /* nw_state is a state machine with timeout */ 16 | 17 | typedef struct nw_state_entry { 18 | ev_timer ev; 19 | /* state id */ 20 | uint32_t id; 21 | /* state context, the nw_state instance */ 22 | void *context; 23 | /* state data, user define */ 24 | void *data; 25 | struct nw_state_entry *next; 26 | } nw_state_entry; 27 | 28 | typedef struct nw_state_type { 29 | /* must 30 | * 31 | * called when a state is timeout, after call, the state will be automatic deleted */ 32 | void (*on_timeout)(nw_state_entry *entry); 33 | /* optional 34 | * 35 | * called when a state is deleted */ 36 | void (*on_release)(nw_state_entry *entry); 37 | } nw_state_type; 38 | 39 | typedef struct nw_state { 40 | struct ev_loop *loop; 41 | nw_state_type type; 42 | uint32_t data_size; 43 | nw_cache *cache; 44 | nw_state_entry **table; 45 | uint32_t table_size; 46 | uint32_t table_mask; 47 | uint32_t used; 48 | uint32_t id_start; 49 | } nw_state; 50 | 51 | typedef struct nw_state_iterator { 52 | nw_state *context; 53 | int64_t index; 54 | nw_state_entry *entry; 55 | nw_state_entry *next_entry; 56 | } nw_state_iterator; 57 | 58 | /* create an state machine instance, with the fixed user data size */ 59 | nw_state *nw_state_create(nw_state_type *type, uint32_t data_size); 60 | nw_state_entry *nw_state_add(nw_state *context, double timeout, uint32_t id); 61 | nw_state_entry *nw_state_get(nw_state *context, uint32_t id); 62 | int nw_state_mod(nw_state *context, uint32_t id, double timeout); 63 | int nw_state_del(nw_state *context, uint32_t id); 64 | /* return the total pending state count in a state machine */ 65 | size_t nw_state_count(nw_state *context); 66 | void nw_state_release(nw_state *context); 67 | 68 | /* traverse the state machine */ 69 | nw_state_iterator *nw_state_get_iterator(nw_state *context); 70 | nw_state_entry *nw_state_next(nw_state_iterator *iter); 71 | void nw_state_iterator_release(nw_state_iterator *iter); 72 | 73 | # endif 74 | 75 | -------------------------------------------------------------------------------- /test/test_state.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/23, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | 10 | # include "nw_state.h" 11 | 12 | struct test_data { 13 | char *str; 14 | }; 15 | 16 | void on_timeout(nw_state_entry *entry) 17 | { 18 | struct test_data *data = entry->data; 19 | printf("on_timeout %s\n", data->str); 20 | } 21 | 22 | void on_release(nw_state_entry *entry) 23 | { 24 | struct test_data *data = entry->data; 25 | printf("on_release %s\n", data->str); 26 | free(data->str); 27 | } 28 | 29 | int main(int argc, char *argv[]) 30 | { 31 | struct nw_state_type type; 32 | type.on_timeout = on_timeout; 33 | type.on_release = on_release; 34 | 35 | nw_state *state = nw_state_create(&type, sizeof(struct test_data)); 36 | if (state == NULL) { 37 | error(1, errno, "nw_state_create fail"); 38 | } 39 | 40 | nw_state_entry *entry = nw_state_add(state, 1.0); 41 | if (entry == NULL) { 42 | error(1, errno, "nw_state_add fail"); 43 | } 44 | printf("id: %d\n", entry->id); 45 | 46 | struct test_data *data = entry->data; 47 | data->str = strdup("hello world"); 48 | 49 | entry = nw_state_get(state, entry->id); 50 | if (!entry) { 51 | error(1, errno, "nw_state_get fail"); 52 | } 53 | if (nw_state_mod(state, entry->id, 5.0) < 0) { 54 | error(1, errno, "nw_state_mod fail"); 55 | } 56 | nw_state_del(state, 1); 57 | 58 | for (int i = 0; i < 100; ++i) { 59 | entry = nw_state_add(state, 1.0); 60 | if (entry == NULL) { 61 | error(1, errno, "nw_state_add fail"); 62 | } 63 | 64 | data = entry->data; 65 | data->str = strdup("asdfghjkl"); 66 | } 67 | 68 | printf("state count: %zu\n", nw_state_count(state)); 69 | printf("state table_size: %u\n", state->table_size); 70 | 71 | nw_state_iterator *iter = nw_state_get_iterator(state); 72 | if (iter == NULL) { 73 | error(1, errno, "nw_state_get_iterator fail"); 74 | } 75 | while ((entry = nw_state_next(iter)) != NULL) { 76 | data = entry->data; 77 | printf("%u: %s\n", entry->id, data->str); 78 | } 79 | nw_state_iterator_release(iter); 80 | 81 | nw_loop_run(); 82 | 83 | return 0; 84 | } 85 | 86 | -------------------------------------------------------------------------------- /asnw/nw_job.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/04/17, create 4 | */ 5 | 6 | # ifndef _NW_JOB_H_ 7 | # define _NW_JOB_H_ 8 | 9 | # include 10 | # include 11 | # include 12 | 13 | # include "nw_evt.h" 14 | # include "nw_buf.h" 15 | 16 | /* nw_job is a thread pool object, all threads are workers. 17 | * it include an job queue, you can add job to the queue, 18 | * workers will get job from queue and do the job. */ 19 | 20 | typedef struct nw_job_entry { 21 | uint32_t id; 22 | /* request data */ 23 | void *request; 24 | /* result data */ 25 | void *reply; 26 | struct nw_job_entry *next; 27 | struct nw_job_entry *prev; 28 | } nw_job_entry; 29 | 30 | typedef struct nw_job_type { 31 | /* optional 32 | * 33 | * if set, the return value will be passed to ob_job 34 | * as the privdata, and the on_release also should be 35 | * set, called in main thread */ 36 | void *(*on_init)(void); 37 | /* must 38 | * 39 | * called when get a new job, in worker thread */ 40 | void (*on_job)(nw_job_entry *entry, void *privdata); 41 | /* optional 42 | * 43 | * called when a job is finished, in main thread */ 44 | void (*on_finish)(nw_job_entry *entry); 45 | /* optional 46 | * 47 | * called when after a job is finished, in main thread 48 | * used to free the request and reply data, in main thread */ 49 | void (*on_cleanup)(nw_job_entry *entry); 50 | /* optional 51 | * 52 | * called when the nw_job is released */ 53 | void (*on_release)(void *privdata); 54 | } nw_job_type; 55 | 56 | typedef struct nw_job { 57 | ev_io ev; 58 | nw_job_type type; 59 | struct ev_loop *loop; 60 | int pipefd[2]; 61 | pthread_mutex_t lock; 62 | pthread_cond_t notify; 63 | nw_cache *cache; 64 | int thread_count; 65 | int thread_start; 66 | pthread_t *threads; 67 | bool shutdown; 68 | nw_job_entry *request_head; 69 | nw_job_entry *request_tail; 70 | int request_count; 71 | nw_job_entry *reply_head; 72 | nw_job_entry *reply_tail; 73 | int reply_count; 74 | } nw_job; 75 | 76 | nw_job *nw_job_create(nw_job_type *type, int thread_count); 77 | int nw_job_add(nw_job *job, uint32_t id, void *request); 78 | void nw_job_release(nw_job *job); 79 | 80 | # endif 81 | 82 | -------------------------------------------------------------------------------- /asnw/nw_ses.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: network session 3 | * History: yang@haipo.me, 2016/03/18, create 4 | */ 5 | 6 | # ifndef _NW_SES_H_ 7 | # define _NW_SES_H_ 8 | 9 | # include 10 | 11 | # include "nw_buf.h" 12 | # include "nw_evt.h" 13 | # include "nw_sock.h" 14 | 15 | /* 16 | * nw_ses is low level object for nw_svr and nw_clt, 17 | * represent a sockfd and the related data and operation, 18 | * should not use it directly 19 | */ 20 | 21 | enum { 22 | NW_SES_TYPE_COMMON, /* stream connection */ 23 | NW_SES_TYPE_CLIENT, /* clinet side */ 24 | NW_SES_TYPE_SERVER, /* server side */ 25 | }; 26 | 27 | typedef struct nw_ses { 28 | /* the libev instance */ 29 | ev_io ev; 30 | /* the loop instance, should be nw_default_loop */ 31 | struct ev_loop *loop; 32 | int sockfd; 33 | /* one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET */ 34 | int sock_type; 35 | /* one of NW_SES_TYPE_COMMON, NW_SES_TYPE_CLIENT, NW_SES_TYPE_SERVER */ 36 | int ses_type; 37 | /* peer addr */ 38 | nw_addr_t peer_addr; 39 | /* host addr */ 40 | nw_addr_t *host_addr; 41 | nw_buf *read_buf; 42 | nw_buf_list *write_buf; 43 | nw_buf_pool *pool; 44 | /* nw_svr will assign every connection a uniq id */ 45 | uint64_t id; 46 | void *privdata; 47 | void *svr; 48 | 49 | struct nw_ses *prev; 50 | struct nw_ses *next; 51 | 52 | int (*on_accept)(struct nw_ses *ses, int sockfd, nw_addr_t *peer_addr); 53 | int (*decode_pkg)(struct nw_ses *ses, void *data, size_t max); 54 | void (*on_connect)(struct nw_ses *ses, bool result); 55 | void (*on_recv_pkg)(struct nw_ses *ses, void *data, size_t size); 56 | void (*on_recv_fd)(struct nw_ses *ses, int fd); 57 | void (*on_error)(struct nw_ses *ses, const char *msg); 58 | void (*on_close)(struct nw_ses *ses); 59 | } nw_ses; 60 | 61 | int nw_ses_bind(nw_ses *ses, nw_addr_t *addr); 62 | int nw_ses_listen(nw_ses *ses, int backlog); 63 | int nw_ses_connect(nw_ses *ses, nw_addr_t *addr); 64 | int nw_ses_start(nw_ses *ses); 65 | int nw_ses_stop(nw_ses *ses); 66 | int nw_ses_send(nw_ses *ses, const void *data, size_t size); 67 | /* send a fd, only when the connection is SOCK_SEQPACKET type */ 68 | int nw_ses_send_fd(nw_ses *ses, int fd); 69 | 70 | int nw_ses_init(nw_ses *ses, struct ev_loop *loop, nw_buf_pool *pool, uint32_t buf_limit, int ses_type); 71 | int nw_ses_close(nw_ses *ses); 72 | int nw_ses_release(nw_ses *ses); 73 | 74 | # endif 75 | 76 | -------------------------------------------------------------------------------- /c1000k/server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/30, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | 14 | # include "nw_svr.h" 15 | # include "nw_timer.h" 16 | 17 | int decode_pkg(nw_ses *ses, void *data, size_t max) 18 | { 19 | char *s = data; 20 | for (size_t i = 0; i < max; ++i) { 21 | if (s[i] == '\n') 22 | return i + 1; 23 | } 24 | return 0; 25 | } 26 | 27 | void on_recv_pkg(nw_ses *ses, void *data, size_t size) 28 | { 29 | } 30 | 31 | void on_error_msg(nw_ses *ses, const char *msg) 32 | { 33 | printf("error occur: %s, perr: %s\n", msg, nw_sock_human_addr(&ses->peer_addr)); 34 | } 35 | 36 | void on_timer(nw_timer *timer, void *privdata) 37 | { 38 | nw_svr *svr = (nw_svr *)privdata; 39 | printf("clt count: %u\n", svr->clt_count); 40 | } 41 | 42 | int set_file_limit(size_t limit) 43 | { 44 | struct rlimit rlim; 45 | memset(&rlim, 0, sizeof(rlim)); 46 | if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { 47 | return -1; 48 | } 49 | if (rlim.rlim_cur >= limit) 50 | return 0; 51 | rlim.rlim_cur = limit; 52 | rlim.rlim_max = limit; 53 | if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { 54 | return -1; 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | int main(int argc, char *argv[]) 61 | { 62 | set_file_limit(1001000); 63 | 64 | nw_svr_cfg cfg; 65 | memset(&cfg, 0, sizeof(cfg)); 66 | cfg.bind_count = 100; 67 | cfg.bind_arr = malloc(sizeof(nw_svr_bind) * cfg.bind_count); 68 | cfg.max_pkg_size = 1024; 69 | 70 | for (int i = 0; i < cfg.bind_count; ++i) { 71 | char bind[1024]; 72 | snprintf(bind, sizeof(bind), "tcp@127.0.0.1:%d", 5000 + i); 73 | nw_sock_cfg_parse(bind, &cfg.bind_arr[i].addr, &cfg.bind_arr[i].sock_type); 74 | } 75 | 76 | nw_svr_type type; 77 | memset(&type, 0, sizeof(type)); 78 | type.decode_pkg = decode_pkg; 79 | type.on_recv_pkg = on_recv_pkg; 80 | type.on_error_msg = on_error_msg; 81 | 82 | nw_svr *svr = nw_svr_create(&cfg, &type, NULL); 83 | if (svr == NULL) { 84 | printf("nw_svr_create fail\n"); 85 | exit(0); 86 | } 87 | nw_svr_start(svr); 88 | 89 | nw_timer timer; 90 | nw_timer_set(&timer, 1.0, true, on_timer, svr); 91 | nw_timer_start(&timer); 92 | 93 | printf("server start\n"); 94 | nw_loop_run(); 95 | 96 | return 0; 97 | } 98 | 99 | -------------------------------------------------------------------------------- /asnw/nw_buf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: network buf manager 3 | * History: yang@haipo.me, 2016/03/16, create 4 | */ 5 | 6 | # ifndef _NW_BUF_H_ 7 | # define _NW_BUF_H_ 8 | 9 | # include 10 | # include 11 | 12 | /* buf management */ 13 | 14 | /* nw_buf is the basic instance of buf, with limit size */ 15 | typedef struct nw_buf { 16 | uint32_t size; 17 | uint32_t rpos; 18 | uint32_t wpos; 19 | struct nw_buf *next; 20 | char data[]; 21 | } nw_buf; 22 | 23 | /* nw_buf_pool is a factory of nw_buf */ 24 | typedef struct nw_buf_pool { 25 | uint32_t size; 26 | uint32_t used; 27 | uint32_t free; 28 | uint32_t free_total; 29 | nw_buf **free_arr; 30 | } nw_buf_pool; 31 | 32 | /* nw_buf_list is a list of nw_buf, if limit is not 0, contain at most `limit` buf instance */ 33 | typedef struct nw_buf_list { 34 | nw_buf_pool *pool; 35 | uint32_t count; 36 | uint32_t limit; 37 | nw_buf *head; 38 | nw_buf *tail; 39 | } nw_buf_list; 40 | 41 | /* nw_cache is similar with nw_buf_pool, but a factory for typeless data */ 42 | typedef struct nw_cache { 43 | uint32_t size; 44 | uint32_t used; 45 | uint32_t free; 46 | uint32_t free_total; 47 | void **free_arr; 48 | } nw_cache; 49 | 50 | /* nw_buf operation */ 51 | size_t nw_buf_size(nw_buf *buf); 52 | size_t nw_buf_avail(nw_buf *buf); 53 | size_t nw_buf_write(nw_buf *buf, const void *data, size_t len); 54 | void nw_buf_shift(nw_buf *buf); 55 | 56 | /* nw_buf_pool operation */ 57 | nw_buf_pool *nw_buf_pool_create(uint32_t size); 58 | nw_buf *nw_buf_alloc(nw_buf_pool *pool); 59 | void nw_buf_free(nw_buf_pool *pool, nw_buf *buf); 60 | void nw_buf_pool_release(nw_buf_pool *pool); 61 | 62 | /* nw_buf_list operation */ 63 | nw_buf_list *nw_buf_list_create(nw_buf_pool *pool, uint32_t limit); 64 | /* write data to list, will expand the list if needed, return the size actually write */ 65 | size_t nw_buf_list_write(nw_buf_list *list, const void *data, size_t len); 66 | /* append data to a new buf instance, will expand the list, len shoud not big than buf size 67 | * return the size actually write */ 68 | size_t nw_buf_list_append(nw_buf_list *list, const void *data, size_t len); 69 | /* remove the head buf if exist */ 70 | void nw_buf_list_shift(nw_buf_list *list); 71 | void nw_buf_list_release(nw_buf_list *list); 72 | 73 | /* nw_cache operation */ 74 | nw_cache *nw_cache_create(uint32_t size); 75 | void *nw_cache_alloc(nw_cache *cache); 76 | void nw_cache_free(nw_cache *cache, void *obj); 77 | void nw_cache_release(nw_cache *cache); 78 | 79 | # endif 80 | 81 | -------------------------------------------------------------------------------- /test/test_clt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/22, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | 13 | # include "nw_clt.h" 14 | # include "nw_timer.h" 15 | 16 | int decode_pkg(nw_ses *ses, void *data, size_t max) 17 | { 18 | char *s = data; 19 | for (size_t i = 0; i < max; ++i) { 20 | if (s[i] == '\n') 21 | return i + 1; 22 | } 23 | return 0; 24 | } 25 | 26 | void on_connect(nw_ses *ses, bool result) 27 | { 28 | if (result) { 29 | printf("connect to: %s success\n", nw_sock_human_addr(&ses->peer_addr)); 30 | } else { 31 | printf("connect to: %s fail: %s\n", nw_sock_human_addr(&ses->peer_addr), strerror(errno)); 32 | } 33 | } 34 | 35 | int on_close(nw_ses *ses) 36 | { 37 | printf("connection to: %s close\n", nw_sock_human_addr(&ses->peer_addr)); 38 | } 39 | 40 | void on_recv_pkg(nw_ses *ses, void *data, size_t size) 41 | { 42 | char *str = malloc(size + 1); 43 | memcpy(str, data, size); 44 | str[size] = 0; 45 | printf("from: %s recv: %zu: %s", nw_sock_human_addr(&ses->peer_addr), size, str); 46 | free(str); 47 | } 48 | 49 | void on_error_msg(nw_ses *ses, const char *msg) 50 | { 51 | printf("error occur: %s, perr: %s\n", msg, nw_sock_human_addr(&ses->peer_addr)); 52 | } 53 | 54 | void on_timeout(nw_timer *timer, void *privdata) 55 | { 56 | nw_clt *clt = privdata; 57 | if (nw_clt_connected(clt)) { 58 | char *msg = "ping\n"; 59 | nw_ses_send(&clt->ses, msg, strlen(msg)); 60 | } 61 | } 62 | 63 | int main(int argc, char *argv[]) 64 | { 65 | if (argc != 2) { 66 | printf("usage: %s addr\n", argv[0]); 67 | exit(0); 68 | } 69 | 70 | nw_clt_cfg cfg; 71 | memset(&cfg, 0, sizeof(cfg)); 72 | cfg.max_pkg_size = 10240; 73 | if (nw_sock_cfg_parse(argv[1], &cfg.addr, &cfg.sock_type) < 0) { 74 | error(1, errno, "parse peer addr: %s fail", argv[1]); 75 | } 76 | 77 | nw_clt_type type; 78 | memset(&type, 0, sizeof(type)); 79 | type.decode_pkg = decode_pkg; 80 | type.on_connect = on_connect; 81 | type.on_close = on_close; 82 | type.on_recv_pkg = on_recv_pkg; 83 | type.on_error_msg = on_error_msg; 84 | 85 | nw_clt *clt = nw_clt_create(&cfg, &type, NULL); 86 | if (clt == NULL) { 87 | error(1, errno, "nw_clt_create fail"); 88 | } 89 | nw_clt_start(clt); 90 | 91 | nw_timer timer; 92 | nw_timer_set(&timer, 1.0, true, on_timeout, clt); 93 | nw_timer_start(&timer); 94 | 95 | nw_loop_run(); 96 | 97 | return 0; 98 | } 99 | 100 | -------------------------------------------------------------------------------- /asnw/nw_sock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: socket related 3 | * History: yang@haipo.me, 2016/03/16, create 4 | */ 5 | 6 | # ifndef _NW_SOCK_H_ 7 | # define _NW_SOCK_H_ 8 | 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | # include 15 | # include 16 | # include 17 | 18 | /* nw_addr_t is a abstract addr type, hide the difference between different sock type */ 19 | typedef struct nw_addr_t { 20 | unsigned int family; 21 | unsigned int addrlen; 22 | union { 23 | struct sockaddr_in in; 24 | struct sockaddr_in6 in6; 25 | struct sockaddr_un un; 26 | }; 27 | } nw_addr_t; 28 | 29 | # define NW_SOCKADDR(addr) ((struct sockaddr *)(&(addr)->in)) 30 | # define NW_HUMAN_ADDR_SIZE 128 31 | # define NW_SOCK_IP_SIZE INET6_ADDRSTRLEN 32 | 33 | /* convert nw_addr_t addr to a human readable string */ 34 | char *nw_sock_human_addr(nw_addr_t *addr); 35 | 36 | /* nw_sock_human_addr thead safe version, dest should at least NW_HUMAN_ADDR_SIZE len */ 37 | char *nw_sock_human_addr_s(nw_addr_t *addr, char *dest); 38 | 39 | /* if addr family is AF_INET or AF_INET6, return ip string, else return empty string */ 40 | char *nw_sock_ip(nw_addr_t *addr); 41 | 42 | /* nw_sock_ip thread safe version, ip should at least NW_SOCK_IP_SIZE len */ 43 | char *nw_sock_ip_s(nw_addr_t *addr, char *ip); 44 | 45 | /* set unix socket mode */ 46 | int nw_sock_set_mode(nw_addr_t *addr, mode_t mode); 47 | 48 | /* 49 | * input: cfg, format: protocol@address 50 | * protocol list: TCP, UDP, STREAM, DGRAM, SEQPACKET (case-insensitive) 51 | * addr type: ip:port or unix path. ip can support ipv6 52 | * example: tcp@127.0.0.1:3333 53 | * dgram@/tmp/test.sock 54 | * 55 | * output: addr, sock_type 56 | * sock_type list: SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET 57 | */ 58 | int nw_sock_cfg_parse(const char *cfg, nw_addr_t *addr, int *sock_type); 59 | 60 | /* get sockfd peer addr */ 61 | int nw_sock_peer_addr(int sockfd, nw_addr_t *addr); 62 | 63 | /* get sockfd host addr */ 64 | int nw_sock_host_addr(int sockfd, nw_addr_t *addr); 65 | 66 | /* get sockfd errno to detect error */ 67 | int nw_sock_errno(int sockfd); 68 | 69 | /* get sockfd system send buf size */ 70 | int nw_sock_get_send_buf(int sockfd, int *buf_size); 71 | 72 | /* get sockfd system recv buf size */ 73 | int nw_sock_get_recv_buf(int sockfd, int *buf_size); 74 | 75 | /* set sockfd system send buf size */ 76 | int nw_sock_set_send_buf(int sockfd, int buf_size); 77 | 78 | /* set sockfd system send buf size */ 79 | int nw_sock_set_recv_buf(int sockfd, int buf_size); 80 | 81 | /* set sockfd as nonblock */ 82 | int nw_sock_set_nonblock(int sockfd); 83 | 84 | /* set sockfd no delay */ 85 | int nw_sock_set_no_delay(int sockfd); 86 | 87 | /* set sockfd reuse addr */ 88 | int nw_sock_set_reuse_addr(int sockfd); 89 | 90 | # endif 91 | 92 | -------------------------------------------------------------------------------- /asnw/nw_clt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/21, create 4 | */ 5 | 6 | # ifndef _NW_CLT_H_ 7 | # define _NW_CLT_H_ 8 | 9 | # include 10 | # include 11 | 12 | # include "nw_buf.h" 13 | # include "nw_evt.h" 14 | # include "nw_ses.h" 15 | # include "nw_sock.h" 16 | # include "nw_timer.h" 17 | 18 | /* nw_clt is a client object, will keep connection to the special addr */ 19 | 20 | typedef struct nw_clt_cfg { 21 | /* the target server addr */ 22 | nw_addr_t addr; 23 | /* the target server sock type */ 24 | int sock_type; 25 | /* max full message size */ 26 | uint32_t max_pkg_size; 27 | /* nw_svr will keep a nw_buf_list for every stream connection to save 28 | * the pending send data. the buf_limit is the nw_buf_list limit */ 29 | uint32_t buf_limit; 30 | /* will call nw_sock_set_recv_buf if not 0 */ 31 | uint32_t read_mem; 32 | /* will call nw_sock_set_send_buf if not 0 */ 33 | uint32_t write_mem; 34 | /* interval to reconnect when the stream connection is close */ 35 | double reconnect_timeout; 36 | /* buf factory, if set to NULL, nw_clt will create it */ 37 | nw_buf_pool *buf_pool; 38 | } nw_clt_cfg; 39 | 40 | typedef struct nw_clt_type { 41 | /* must 42 | * 43 | * for dgram and seqpacket connection, every package is consider as a 44 | * full message, but for stream connection, there is no boundary for 45 | * a message, use decode_pkg to determine the full message. 46 | * 47 | * return < 0: broken data, connection will be closed, 48 | * return = 0: don't contain a full message, nothing to do, 49 | * return > 0: return the size of a full message. */ 50 | int (*decode_pkg)(nw_ses *ses, void *data, size_t max); 51 | /* optional 52 | * 53 | * called when the connection is close. if on_close return > 0, 54 | * nw_clt will try reconnect immediately */ 55 | int (*on_close)(nw_ses *ses); 56 | /* optional 57 | * 58 | * called when the connect is success or fail */ 59 | void (*on_connect)(nw_ses *ses, bool result); 60 | /* must 61 | * 62 | * called when a full message is recieved, put your business logic in here */ 63 | void (*on_recv_pkg)(nw_ses *ses, void *data, size_t size); 64 | /* optional 65 | * 66 | * called when a fd is recieved, it not set, default action is close it */ 67 | void (*on_recv_fd)(nw_ses *ses, int fd); 68 | /* optional 69 | * 70 | * called when a error accur, msg is the detail of the error */ 71 | void (*on_error_msg)(nw_ses *ses, const char *msg); 72 | } nw_clt_type; 73 | 74 | typedef struct nw_clt { 75 | nw_ses ses; 76 | nw_clt_type type; 77 | bool custom_buf_pool; 78 | nw_buf_pool *buf_pool; 79 | nw_timer timer; 80 | bool connected; 81 | bool on_connect_called; 82 | double reconnect_timeout; 83 | uint32_t read_mem; 84 | uint32_t write_mem; 85 | } nw_clt; 86 | 87 | /* create a client instance, the privdata will assign to nw_clt privdata */ 88 | nw_clt *nw_clt_create(nw_clt_cfg *cfg, nw_clt_type *type, void *privdata); 89 | int nw_clt_start(nw_clt *clt); 90 | int nw_clt_close(nw_clt *clt); 91 | void nw_clt_release(nw_clt *clt); 92 | bool nw_clt_connected(nw_clt *clt); 93 | 94 | # endif 95 | 96 | -------------------------------------------------------------------------------- /wrapper/ut_rpc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/30, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | 13 | # include "ut_rpc.h" 14 | # include "ut_crc32.h" 15 | 16 | # if __BYTE_ORDER == __LITTLE_ENDIAN 17 | # define htole16(x) (x) 18 | # define htole32(x) (x) 19 | # define htole64(x) (x) 20 | # define le16toh(x) (x) 21 | # define le32toh(x) (x) 22 | # define le64toh(x) (x) 23 | # else 24 | # define htole16(x) bswap_16(x) 25 | # define htole32(x) bswap_32(x) 26 | # define htole64(x) bswap_64(x) 27 | # define le16toh(x) bswap_16(x) 28 | # define le32toh(x) bswap_32(x) 29 | # define le64toh(x) bswap_64(x) 30 | # endif 31 | 32 | int rpc_decode(nw_ses *ses, void *data, size_t max) 33 | { 34 | if (max < RPC_PKG_HEAD_SIZE) 35 | return 0; 36 | 37 | rpc_pkg *pkg = data; 38 | if (le32toh(pkg->magic) != RPC_PKG_MAGIC) 39 | return -1; 40 | uint32_t pkg_size = RPC_PKG_HEAD_SIZE + le16toh(pkg->ext_size) + le32toh(pkg->body_size); 41 | if (pkg_size > RPC_MAX_PKG_SIZE) 42 | return -2; 43 | if (max < pkg_size) 44 | return 0; 45 | 46 | uint32_t crc32 = le32toh(pkg->crc32); 47 | pkg->crc32 = 0; 48 | if (crc32 != generate_crc32c(data, pkg_size)) 49 | return -3; 50 | pkg->crc32 = crc32; 51 | 52 | pkg->magic = le32toh(pkg->magic); 53 | pkg->command = le32toh(pkg->command); 54 | pkg->pkg_type = le16toh(pkg->pkg_type); 55 | pkg->result = le32toh(pkg->result); 56 | pkg->sequence = le32toh(pkg->sequence); 57 | pkg->req_id = le64toh(pkg->req_id); 58 | pkg->body_size = le32toh(pkg->body_size); 59 | pkg->ext_size = le16toh(pkg->ext_size); 60 | 61 | return pkg_size; 62 | } 63 | 64 | int rpc_send(nw_ses *ses, rpc_pkg *pkg) 65 | { 66 | static void *send_buf; 67 | if (send_buf == NULL) { 68 | send_buf = malloc(RPC_MAX_PKG_SIZE); 69 | assert(send_buf != NULL); 70 | } 71 | 72 | uint32_t pkg_size = RPC_PKG_HEAD_SIZE + pkg->ext_size + pkg->body_size; 73 | if (pkg_size > RPC_MAX_PKG_SIZE) 74 | return -1; 75 | 76 | memcpy(send_buf, pkg, RPC_PKG_HEAD_SIZE); 77 | if (pkg->ext_size) 78 | memcpy(send_buf + RPC_PKG_HEAD_SIZE, pkg->ext, pkg->ext_size); 79 | if (pkg->body_size) 80 | memcpy(send_buf + RPC_PKG_HEAD_SIZE + pkg->ext_size, pkg->body, pkg->body_size); 81 | 82 | pkg = send_buf; 83 | pkg->magic = htole32(RPC_PKG_MAGIC); 84 | pkg->command = htole32(pkg->command); 85 | pkg->pkg_type = htole16(pkg->pkg_type); 86 | pkg->result = htole32(pkg->result); 87 | pkg->sequence = htole32(pkg->sequence); 88 | pkg->req_id = htole64(pkg->req_id); 89 | pkg->body_size = htole32(pkg->body_size); 90 | pkg->ext_size = htole16(pkg->ext_size); 91 | 92 | pkg->crc32 = 0; 93 | pkg->crc32 = htole32(generate_crc32c(send_buf, pkg_size)); 94 | 95 | return nw_ses_send(ses, send_buf, pkg_size); 96 | } 97 | 98 | double current_timestamp(void) 99 | { 100 | struct timeval tv; 101 | gettimeofday(&tv, NULL); 102 | return (double)tv.tv_sec + tv.tv_usec / 1000000.0; 103 | } 104 | 105 | -------------------------------------------------------------------------------- /test/echo_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/21, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | 11 | # include "nw_svr.h" 12 | # include "nw_timer.h" 13 | 14 | int decode_pkg(nw_ses *ses, void *data, size_t max) 15 | { 16 | char *s = data; 17 | for (size_t i = 0; i < max; ++i) { 18 | if (s[i] == '\n') 19 | return i + 1; 20 | } 21 | return 0; 22 | } 23 | 24 | void on_new_connection(nw_ses *ses) 25 | { 26 | printf("new connection from: %s\n", nw_sock_human_addr(&ses->peer_addr)); 27 | } 28 | 29 | void on_connection_close(nw_ses *ses) 30 | { 31 | printf("connection: %s close\n", nw_sock_human_addr(&ses->peer_addr)); 32 | } 33 | 34 | void on_recv_pkg(nw_ses *ses, void *data, size_t size) 35 | { 36 | char *str = malloc(size + 1); 37 | memcpy(str, data, size); 38 | str[size] = 0; 39 | printf("from: %s recv: %zu: %s", nw_sock_human_addr(&ses->peer_addr), size, str); 40 | if (nw_ses_send(ses, data, size) < 0) { 41 | printf("nw_ses_send fail\n"); 42 | } 43 | free(str); 44 | } 45 | 46 | void on_recv_fd(nw_ses *ses, int fd) 47 | { 48 | printf("recv fd: %d\n", fd); 49 | char buf[10240]; 50 | int ret = read(fd, buf, sizeof(buf)); 51 | if (ret < 0) { 52 | printf("read error: %s\n", strerror(errno)); 53 | } else if (nw_ses_send(ses, buf, ret) < 0) { 54 | printf("nw_ses_send fail\n"); 55 | } 56 | close(fd); 57 | } 58 | 59 | void on_error_msg(nw_ses *ses, const char *msg) 60 | { 61 | printf("error occur: %s, perr: %s\n", msg, nw_sock_human_addr(&ses->peer_addr)); 62 | } 63 | 64 | void on_timer(nw_timer *timer, void *privdata) 65 | { 66 | nw_svr *svr = (nw_svr *)privdata; 67 | printf("clt count: %u\n", svr->clt_count); 68 | } 69 | 70 | int main(int argc, char *argv[]) 71 | { 72 | if (argc < 2) { 73 | printf("usage: %s bind...\n", argv[0]); 74 | exit(0); 75 | } 76 | 77 | int bind_count = argc - 1; 78 | nw_svr_bind *bind_arr = malloc(sizeof(nw_svr_bind) * bind_count); 79 | if (bind_arr == NULL) { 80 | printf("malloc fail\n"); 81 | exit(0); 82 | } 83 | memset(bind_arr, sizeof(nw_svr_bind) * bind_count, 0); 84 | for (int i = 0; i < bind_count; ++i) { 85 | int ret = nw_sock_cfg_parse(argv[i + 1], &bind_arr[i].addr, &bind_arr[i].sock_type); 86 | if (ret < 0) { 87 | printf("parse bind: %s fail: %d\n", argv[1], ret); 88 | exit(0); 89 | } 90 | } 91 | 92 | nw_svr_cfg cfg; 93 | memset(&cfg, 0, sizeof(cfg)); 94 | cfg.bind_count = bind_count; 95 | cfg.bind_arr = bind_arr; 96 | cfg.max_pkg_size = 10240; 97 | 98 | nw_svr_type type; 99 | memset(&type, 0, sizeof(type)); 100 | type.decode_pkg = decode_pkg; 101 | type.on_new_connection = on_new_connection; 102 | type.on_connection_close = on_connection_close; 103 | type.on_recv_pkg = on_recv_pkg; 104 | type.on_recv_fd = on_recv_fd; 105 | type.on_error_msg = on_error_msg; 106 | 107 | nw_svr *svr = nw_svr_create(&cfg, &type, NULL); 108 | if (svr == NULL) { 109 | printf("nw_svr_create fail\n"); 110 | exit(0); 111 | } 112 | nw_svr_start(svr); 113 | 114 | nw_timer timer; 115 | nw_timer_set(&timer, 5.0, true, on_timer, svr); 116 | nw_timer_start(&timer); 117 | 118 | printf("echo server start\n"); 119 | nw_loop_run(); 120 | printf("echo server stop\n"); 121 | 122 | return 0; 123 | } 124 | 125 | -------------------------------------------------------------------------------- /wrapper/ut_crc32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/29, create 4 | */ 5 | 6 | # include "ut_crc32.h" 7 | 8 | #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) 9 | 10 | static const unsigned int crc_c[256] = { 11 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 12 | 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 13 | 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 14 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 15 | 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 16 | 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 17 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 18 | 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 19 | 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 20 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 21 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 22 | 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 23 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 24 | 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 25 | 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 26 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 27 | 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 28 | 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 29 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 30 | 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 31 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 32 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 33 | 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 34 | 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 35 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 36 | 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 37 | 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 38 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 39 | 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 40 | 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 41 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 42 | 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 43 | 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 44 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 45 | 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 46 | 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 47 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 48 | 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 49 | 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 50 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 51 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 52 | 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 53 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 54 | 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 55 | 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 56 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 57 | 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 58 | 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 59 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 60 | 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 61 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 62 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 63 | 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 64 | 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 65 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 66 | 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 67 | 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 68 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 69 | 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 70 | 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 71 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 72 | 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 73 | 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 74 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 75 | }; 76 | 77 | uint32_t generate_crc32c(const char *buffer, size_t length) { 78 | size_t i; 79 | uint32_t crc32 = ~0L; 80 | 81 | for (i = 0; i < length; i++){ 82 | CRC32C(crc32, (unsigned char)buffer[i]); 83 | } 84 | return ~crc32; 85 | } 86 | 87 | -------------------------------------------------------------------------------- /asnw/nw_svr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/20, create 4 | */ 5 | 6 | # ifndef _NW_SVR_H_ 7 | # define _NW_SVR_H_ 8 | 9 | # include 10 | 11 | # include "nw_buf.h" 12 | # include "nw_evt.h" 13 | # include "nw_ses.h" 14 | # include "nw_sock.h" 15 | 16 | /* nw_svr is a server object bind on multi addrs with same data process method */ 17 | 18 | typedef struct nw_svr_bind { 19 | /* bind addr */ 20 | nw_addr_t addr; 21 | /* bind type, SOCK_STREAM or SOCK_DGRAM or SOCK_SEQPACKET */ 22 | int sock_type; 23 | } nw_svr_bind; 24 | 25 | typedef struct nw_svr_cfg { 26 | /* size of bind_arr */ 27 | uint32_t bind_count; 28 | nw_svr_bind *bind_arr; 29 | /* max full message size */ 30 | uint32_t max_pkg_size; 31 | /* nw_svr will keep a nw_buf_list for every stream connection to save 32 | * the pending send data. the buf_limit is the nw_buf_list limit */ 33 | uint32_t buf_limit; 34 | /* will call nw_sock_set_recv_buf if not 0 */ 35 | uint32_t read_mem; 36 | /* will call nw_sock_set_send_buf if not 0 */ 37 | uint32_t write_mem; 38 | } nw_svr_cfg; 39 | 40 | typedef struct nw_svr_type { 41 | /* must 42 | * 43 | * for dgram and seqpacket connection, every package is consider as a 44 | * full message, but for stream connection, there is no boundary for 45 | * a message, use decode_pkg to determine the full message. 46 | * 47 | * return < 0: broken data, connection will be closed, 48 | * return = 0: don't contain a full message, nothing to do, 49 | * return > 0: return the size of a full message. */ 50 | int (*decode_pkg)(nw_ses *ses, void *data, size_t max); 51 | /* optional 52 | * 53 | * when accept a new connection for non dgram type svr, the default action 54 | * is add the connection to the server, you can overwrite this action by 55 | * set on_accept function. return < 0, sockfd will be close */ 56 | int (*on_accept)(nw_ses *ses, int sockfd, nw_addr_t *peer_addr); 57 | /* optional 58 | * 59 | * called when a new connection is established */ 60 | void (*on_new_connection)(nw_ses *ses); 61 | /* optional 62 | * 63 | * called when a connection is close */ 64 | void (*on_connection_close)(nw_ses *ses); 65 | /* must 66 | * 67 | * called when a full message received, put your business logic here */ 68 | void (*on_recv_pkg)(nw_ses *ses, void *data, size_t size); 69 | /* optional 70 | * 71 | * called when a fd is received, if not set, default action is to close it */ 72 | void (*on_recv_fd)(nw_ses *ses, int fd); 73 | /* optional 74 | * 75 | * called when an error occur, msg is the detail of the error */ 76 | void (*on_error_msg)(nw_ses *ses, const char *msg); 77 | /* optional 78 | * 79 | * if set, the on_privdata_free also should be set. 80 | * the return value will assign to nw_ses privdata 81 | * called when a new connection is established */ 82 | void *(*on_privdata_alloc)(void *svr); 83 | /* optional 84 | * 85 | * called when on_privdata_alloc is set and the connection is closed */ 86 | void (*on_privdata_free)(void *svr, void *privdata); 87 | } nw_svr_type; 88 | 89 | typedef struct nw_svr { 90 | uint32_t svr_count; 91 | nw_ses *svr_list; 92 | nw_svr_type type; 93 | nw_buf_pool *buf_pool; 94 | nw_cache *clt_cache; 95 | nw_ses *clt_list_head; 96 | nw_ses *clt_list_tail; 97 | uint32_t clt_count; 98 | uint32_t buf_limit; 99 | uint32_t read_mem; 100 | uint32_t write_mem; 101 | uint64_t id_start; 102 | void *privdata; 103 | } nw_svr; 104 | 105 | /* create a server instance, the privdata will assign to nw_svr privdata */ 106 | nw_svr *nw_svr_create(nw_svr_cfg *cfg, nw_svr_type *type, void *privdata); 107 | int nw_svr_add_clt_fd(nw_svr *svr, int fd); 108 | int nw_svr_start(nw_svr *svr); 109 | int nw_svr_stop(nw_svr *svr); 110 | void nw_svr_release(nw_svr *svr); 111 | void nw_svr_close_clt(nw_svr *svr, nw_ses *ses); 112 | 113 | # endif 114 | 115 | -------------------------------------------------------------------------------- /wrapper/ut_rpc_svr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/29, create 4 | */ 5 | 6 | # include 7 | 8 | # include "ut_rpc_svr.h" 9 | # include "ut_crc32.h" 10 | # include "nw_sock.h" 11 | 12 | struct clt_info { 13 | double last_heartbeat; 14 | }; 15 | 16 | static void on_recv_pkg(nw_ses *ses, void *data, size_t size) 17 | { 18 | struct rpc_pkg pkg; 19 | memcpy(&pkg, data, RPC_PKG_HEAD_SIZE); 20 | pkg.ext = data + RPC_PKG_HEAD_SIZE; 21 | pkg.body = pkg.ext + pkg.ext_size; 22 | 23 | if (pkg.command == RPC_CMD_HEARTBEAT) { 24 | if (ses->ses_type != NW_SES_TYPE_COMMON) 25 | return; 26 | struct clt_info *info = ses->privdata; 27 | info->last_heartbeat = current_timestamp(); 28 | rpc_send(ses, &pkg); 29 | return; 30 | } 31 | 32 | rpc_svr *svr = ((nw_svr *)ses->svr)->privdata; 33 | svr->on_recv_pkg(ses, &pkg); 34 | } 35 | 36 | static void on_new_connection(nw_ses *ses) 37 | { 38 | struct clt_info *info = ses->privdata; 39 | info->last_heartbeat = current_timestamp(); 40 | rpc_svr *svr = ((nw_svr *)ses->svr)->privdata; 41 | if (svr->on_new_connection) 42 | svr->on_new_connection(ses); 43 | } 44 | 45 | static void on_error_msg(nw_ses *ses, const char *msg) 46 | { 47 | } 48 | 49 | static void *on_privdata_alloc(void *svr) 50 | { 51 | rpc_svr *r_svr = ((nw_svr *)svr)->privdata; 52 | void *privdata = nw_cache_alloc(r_svr->privdata_cache); 53 | assert(privdata != NULL); 54 | return privdata; 55 | } 56 | 57 | static void on_privdata_free(void *svr, void *privdata) 58 | { 59 | rpc_svr *r_svr = ((nw_svr *)svr)->privdata; 60 | return nw_cache_free(r_svr->privdata_cache, privdata); 61 | } 62 | 63 | static void on_timer(nw_timer *timer, void *privdata) 64 | { 65 | rpc_svr *svr = privdata; 66 | double now = current_timestamp(); 67 | 68 | nw_ses *curr = svr->raw_svr->clt_list_head; 69 | nw_ses *next; 70 | while (curr) { 71 | next = curr->next; 72 | struct clt_info *info = curr->privdata; 73 | if (now - info->last_heartbeat > RPC_HEARTBEAT_TIMEOUT) { 74 | nw_svr_close_clt(svr->raw_svr, curr); 75 | } 76 | curr = next; 77 | } 78 | } 79 | 80 | rpc_svr *rpc_svr_create(nw_svr_cfg *cfg, rpc_svr_type *type) 81 | { 82 | if (type->on_recv_pkg == NULL) 83 | return NULL; 84 | 85 | rpc_svr *svr = malloc(sizeof(rpc_svr)); 86 | assert(svr != NULL); 87 | 88 | nw_svr_type raw_type; 89 | memset(&raw_type, 0, sizeof(raw_type)); 90 | raw_type.decode_pkg = rpc_decode; 91 | raw_type.on_connection_close = type->on_connection_close; 92 | raw_type.on_new_connection = on_new_connection; 93 | raw_type.on_error_msg = on_error_msg; 94 | raw_type.on_recv_pkg = on_recv_pkg; 95 | raw_type.on_privdata_alloc = on_privdata_alloc; 96 | raw_type.on_privdata_free = on_privdata_free; 97 | 98 | cfg->max_pkg_size = RPC_MAX_PKG_SIZE; 99 | svr->raw_svr = nw_svr_create(cfg, &raw_type, svr); 100 | if (svr->raw_svr == NULL) { 101 | free(svr); 102 | return NULL; 103 | } 104 | 105 | nw_timer_set(&svr->timer, RPC_HEARTBEAT_INTERVAL, true, on_timer, svr); 106 | svr->privdata_cache = nw_cache_create(sizeof(struct clt_info)); 107 | assert(svr->privdata_cache != NULL); 108 | svr->on_recv_pkg = type->on_recv_pkg; 109 | svr->on_new_connection = type->on_new_connection; 110 | 111 | return svr; 112 | } 113 | 114 | int rpc_svr_start(rpc_svr *svr) 115 | { 116 | int ret = nw_svr_start(svr->raw_svr); 117 | if (ret < 0) 118 | return ret; 119 | nw_timer_start(&svr->timer); 120 | return 0; 121 | } 122 | 123 | int rpc_svr_stop(rpc_svr *svr) 124 | { 125 | int ret = nw_svr_stop(svr->raw_svr); 126 | if (ret < 0) 127 | return ret; 128 | nw_timer_stop(&svr->timer); 129 | return 0; 130 | } 131 | 132 | void rpc_svr_release(rpc_svr *svr) 133 | { 134 | nw_svr_release(svr->raw_svr); 135 | nw_timer_stop(&svr->timer); 136 | nw_cache_release(svr->privdata_cache); 137 | free(svr); 138 | } 139 | 140 | void rpc_svr_close_clt(rpc_svr *svr, nw_ses *ses) 141 | { 142 | nw_svr_close_clt(svr->raw_svr, ses); 143 | } 144 | 145 | -------------------------------------------------------------------------------- /wrapper/ut_rpc_clt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/30, create 4 | */ 5 | 6 | # include 7 | 8 | # include "ut_rpc_clt.h" 9 | # include "ut_crc32.h" 10 | # include "nw_sock.h" 11 | 12 | static void on_recv_pkg(nw_ses *ses, void *data, size_t size) 13 | { 14 | struct rpc_pkg pkg; 15 | memcpy(&pkg, data, RPC_PKG_HEAD_SIZE); 16 | pkg.ext = data + RPC_PKG_HEAD_SIZE; 17 | pkg.body = pkg.ext + pkg.ext_size; 18 | 19 | rpc_clt *clt= ses->privdata; 20 | if (pkg.command == RPC_CMD_HEARTBEAT) { 21 | clt->last_heartbeat = current_timestamp(); 22 | return; 23 | } 24 | clt->on_recv_pkg(ses, &pkg); 25 | } 26 | 27 | static void on_error_msg(nw_ses *ses, const char *msg) 28 | { 29 | } 30 | 31 | static void on_connect(nw_ses *ses, bool result) 32 | { 33 | rpc_clt *clt= ses->privdata; 34 | if (result) { 35 | clt->curr_index = 0; 36 | clt->last_heartbeat = current_timestamp(); 37 | } 38 | if (clt->on_connect) { 39 | clt->on_connect(ses, result); 40 | } 41 | } 42 | 43 | static int on_close(nw_ses *ses) 44 | { 45 | rpc_clt *clt= ses->privdata; 46 | 47 | if (clt->curr_index == clt->addr_count) { 48 | clt->curr_index = 0; 49 | return 0; 50 | } 51 | memcpy(&ses->peer_addr, &clt->addr_arr[clt->curr_index], sizeof(nw_addr_t)); 52 | clt->curr_index += 1; 53 | return 1; 54 | } 55 | 56 | static void on_timer(nw_timer *timer, void *privdata) 57 | { 58 | rpc_clt *clt = privdata; 59 | if (!nw_clt_connected(clt->raw_clt)) 60 | return; 61 | if (clt->raw_clt->ses.sock_type == SOCK_DGRAM) 62 | return; 63 | 64 | double now = current_timestamp(); 65 | if (now - clt->last_heartbeat > RPC_HEARTBEAT_TIMEOUT) { 66 | nw_clt_close(clt->raw_clt); 67 | nw_clt_start(clt->raw_clt); 68 | } else { 69 | rpc_pkg pkg; 70 | memset(&pkg, 0, sizeof(pkg)); 71 | pkg.pkg_type = RPC_PKG_TYPE_REQUEST; 72 | pkg.command = RPC_CMD_HEARTBEAT; 73 | rpc_send(&clt->raw_clt->ses, &pkg); 74 | } 75 | } 76 | 77 | rpc_clt *rpc_clt_create(rpc_clt_cfg *cfg, rpc_clt_type *type) 78 | { 79 | if (cfg->name == NULL) 80 | return NULL; 81 | if (cfg->addr_count == 0) 82 | return NULL; 83 | if (type->on_recv_pkg == NULL) 84 | return NULL; 85 | 86 | nw_clt_cfg raw_cfg; 87 | memset(&raw_cfg, 0, sizeof(raw_cfg)); 88 | memcpy(&raw_cfg.addr, &cfg->addr_arr[0], sizeof(nw_addr_t)); 89 | raw_cfg.sock_type = cfg->sock_type; 90 | raw_cfg.read_mem = cfg->read_mem; 91 | raw_cfg.write_mem = cfg->write_mem; 92 | raw_cfg.reconnect_timeout = cfg->reconnect_timeout; 93 | raw_cfg.max_pkg_size = RPC_MAX_PKG_SIZE; 94 | 95 | nw_clt_type raw_type; 96 | memset(&raw_type, 0, sizeof(raw_type)); 97 | raw_type.decode_pkg = rpc_decode; 98 | raw_type.on_connect = on_connect; 99 | raw_type.on_close = on_close; 100 | raw_type.on_recv_pkg = on_recv_pkg; 101 | raw_type.on_error_msg = on_error_msg; 102 | 103 | rpc_clt *clt = malloc(sizeof(rpc_clt)); 104 | assert(clt != NULL); 105 | 106 | clt->raw_clt = nw_clt_create(&raw_cfg, &raw_type, clt); 107 | if (clt->raw_clt == NULL) { 108 | free(clt); 109 | return NULL; 110 | } 111 | 112 | clt->name = strdup(cfg->name); 113 | assert(clt->name != NULL); 114 | clt->addr_count = cfg->addr_count; 115 | clt->addr_arr = malloc(sizeof(nw_addr_t) * clt->addr_count); 116 | assert(clt->addr_arr != NULL); 117 | memcpy(clt->addr_arr, cfg->addr_arr, sizeof(nw_addr_t) * clt->addr_count); 118 | 119 | nw_timer_set(&clt->timer, RPC_HEARTBEAT_INTERVAL, true, on_timer, clt); 120 | clt->on_recv_pkg = type->on_recv_pkg; 121 | clt->on_connect = type->on_connect; 122 | 123 | return clt; 124 | } 125 | 126 | int rpc_clt_start(rpc_clt *clt) 127 | { 128 | int ret = nw_clt_start(clt->raw_clt); 129 | if (ret < 0) { 130 | return ret; 131 | } 132 | nw_timer_start(&clt->timer); 133 | return 0; 134 | } 135 | 136 | int rpc_clt_close(rpc_clt *clt) 137 | { 138 | int ret = nw_clt_close(clt->raw_clt); 139 | if (ret < 0) { 140 | return ret; 141 | } 142 | nw_timer_stop(&clt->timer); 143 | return 0; 144 | } 145 | 146 | int rpc_clt_send(rpc_clt *clt, rpc_pkg *pkg) 147 | { 148 | return rpc_send(&clt->raw_clt->ses, pkg); 149 | } 150 | 151 | void rpc_clt_release(rpc_clt *clt) 152 | { 153 | nw_clt_release(clt->raw_clt); 154 | nw_timer_stop(&clt->timer); 155 | free(clt); 156 | } 157 | 158 | bool rpc_clt_connected(rpc_clt *clt) 159 | { 160 | return nw_clt_connected(clt->raw_clt); 161 | } 162 | 163 | -------------------------------------------------------------------------------- /asnw/nw_buf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: network buf manager 3 | * History: yang@haipo.me, 2016/03/16, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include "nw_buf.h" 9 | 10 | # define NW_BUF_POOL_INIT_SIZE 64 11 | # define NW_CACHE_INIT_SIZE 64 12 | 13 | size_t nw_buf_size(nw_buf *buf) 14 | { 15 | return buf->wpos - buf->rpos; 16 | } 17 | 18 | size_t nw_buf_avail(nw_buf *buf) 19 | { 20 | return buf->size - buf->wpos; 21 | } 22 | 23 | size_t nw_buf_write(nw_buf *buf, const void *data, size_t len) 24 | { 25 | size_t available = buf->size - buf->wpos; 26 | size_t wlen = len > available ? available : len; 27 | memcpy(buf->data + buf->wpos, data, wlen); 28 | buf->wpos += wlen; 29 | return wlen; 30 | } 31 | 32 | void nw_buf_shift(nw_buf *buf) 33 | { 34 | if (buf->rpos == buf->wpos) { 35 | buf->rpos = buf->wpos = 0; 36 | } else if (buf->rpos != 0) { 37 | memmove(buf->data, buf->data + buf->rpos, buf->wpos - buf->rpos); 38 | buf->wpos -= buf->rpos; 39 | buf->rpos = 0; 40 | } 41 | } 42 | 43 | nw_buf_pool *nw_buf_pool_create(uint32_t size) 44 | { 45 | nw_buf_pool *pool = malloc(sizeof(nw_buf_pool)); 46 | if (pool == NULL) 47 | return NULL; 48 | 49 | pool->size = size; 50 | pool->used = 0; 51 | pool->free = 0; 52 | pool->free_total = NW_BUF_POOL_INIT_SIZE; 53 | pool->free_arr = malloc(pool->free_total * sizeof(nw_buf *)); 54 | if (pool->free_arr == NULL) { 55 | free(pool); 56 | return NULL; 57 | } 58 | 59 | return pool; 60 | } 61 | 62 | nw_buf *nw_buf_alloc(nw_buf_pool *pool) 63 | { 64 | if (pool->free) { 65 | nw_buf *buf = pool->free_arr[--pool->free]; 66 | buf->size = pool->size; 67 | buf->rpos = 0; 68 | buf->wpos = 0; 69 | buf->next = NULL; 70 | return buf; 71 | } 72 | 73 | nw_buf *buf = malloc(sizeof(nw_buf) + pool->size); 74 | if (buf == NULL) 75 | return NULL; 76 | buf->size = pool->size; 77 | buf->rpos = 0; 78 | buf->wpos = 0; 79 | buf->next = NULL; 80 | 81 | return buf; 82 | } 83 | 84 | void nw_buf_free(nw_buf_pool *pool, nw_buf *buf) 85 | { 86 | if (pool->free < pool->free_total) { 87 | pool->free_arr[pool->free++] = buf; 88 | } else { 89 | uint32_t new_free_total = pool->free_total * 2; 90 | void *new_arr = realloc(pool->free_arr, new_free_total * sizeof(nw_buf *)); 91 | if (new_arr) { 92 | pool->free_total = new_free_total; 93 | pool->free_arr = new_arr; 94 | pool->free_arr[pool->free++] = buf; 95 | } else { 96 | free(buf); 97 | } 98 | } 99 | } 100 | 101 | void nw_buf_pool_release(nw_buf_pool *pool) 102 | { 103 | for (uint32_t i = 0; i < pool->free; ++i) { 104 | free(pool->free_arr[i]); 105 | } 106 | free(pool->free_arr); 107 | free(pool); 108 | } 109 | 110 | nw_buf_list *nw_buf_list_create(nw_buf_pool *pool, uint32_t limit) 111 | { 112 | nw_buf_list *list = malloc(sizeof(nw_buf_list)); 113 | if (list == NULL) 114 | return NULL; 115 | list->pool = pool; 116 | list->count = 0; 117 | list->limit = limit; 118 | list->head = NULL; 119 | list->tail = NULL; 120 | 121 | return list; 122 | } 123 | 124 | size_t nw_buf_list_write(nw_buf_list *list, const void *data, size_t len) 125 | { 126 | const void *pos = data; 127 | size_t left = len; 128 | 129 | if (list->tail && nw_buf_avail(list->tail)) { 130 | size_t ret = nw_buf_write(list->tail, pos, left); 131 | left -= ret; 132 | pos += ret; 133 | } 134 | 135 | while (left) { 136 | if (list->limit && list->count >= list->limit) 137 | return len - left; 138 | nw_buf *buf = nw_buf_alloc(list->pool); 139 | if (buf == NULL) 140 | return len - left; 141 | if (list->head == NULL) 142 | list->head = buf; 143 | if (list->tail != NULL) 144 | list->tail->next = buf; 145 | list->tail = buf; 146 | list->count++; 147 | size_t ret = nw_buf_write(list->tail, pos, left); 148 | left -= ret; 149 | pos += ret; 150 | } 151 | 152 | return len; 153 | } 154 | 155 | size_t nw_buf_list_append(nw_buf_list *list, const void *data, size_t len) 156 | { 157 | if (list->limit && list->count >= list->limit) 158 | return 0; 159 | nw_buf *buf = nw_buf_alloc(list->pool); 160 | if (buf == NULL) 161 | return 0; 162 | if (len > buf->size) { 163 | nw_buf_free(list->pool, buf); 164 | return 0; 165 | } 166 | nw_buf_write(buf, data, len); 167 | if (list->head == NULL) 168 | list->head = buf; 169 | if (list->tail != NULL) 170 | list->tail->next = buf; 171 | list->tail = buf; 172 | list->count++; 173 | 174 | return len; 175 | } 176 | 177 | void nw_buf_list_shift(nw_buf_list *list) 178 | { 179 | if (list->head) { 180 | nw_buf *tmp = list->head; 181 | list->head = tmp->next; 182 | if (list->head == NULL) { 183 | list->tail = NULL; 184 | } 185 | list->count--; 186 | nw_buf_free(list->pool, tmp); 187 | } 188 | } 189 | 190 | void nw_buf_list_release(nw_buf_list *list) 191 | { 192 | nw_buf *curr = list->head; 193 | nw_buf *next = NULL; 194 | while (curr) { 195 | next = curr->next; 196 | nw_buf_free(list->pool, curr); 197 | curr = next; 198 | } 199 | free(list); 200 | } 201 | 202 | 203 | nw_cache *nw_cache_create(uint32_t size) 204 | { 205 | nw_cache *cache = malloc(sizeof(nw_cache)); 206 | if (cache == NULL) 207 | return NULL; 208 | 209 | cache->size = size; 210 | cache->used = 0; 211 | cache->free = 0; 212 | cache->free_total = NW_CACHE_INIT_SIZE; 213 | cache->free_arr = malloc(cache->free_total * sizeof(void *)); 214 | if (cache->free_arr == NULL) { 215 | free(cache); 216 | return NULL; 217 | } 218 | 219 | return cache; 220 | } 221 | 222 | void *nw_cache_alloc(nw_cache *cache) 223 | { 224 | if (cache->free) 225 | return cache->free_arr[--cache->free]; 226 | return malloc(cache->size); 227 | } 228 | 229 | void nw_cache_free(nw_cache *cache, void *obj) 230 | { 231 | if (cache->free < cache->free_total) { 232 | cache->free_arr[cache->free++] = obj; 233 | } else { 234 | uint32_t new_free_total = cache->free_total * 2; 235 | void *new_arr = realloc(cache->free_arr, new_free_total * sizeof(void *)); 236 | if (new_arr) { 237 | cache->free_total = new_free_total; 238 | cache->free_arr = new_arr; 239 | cache->free_arr[cache->free++] = obj; 240 | } else { 241 | free(obj); 242 | } 243 | } 244 | } 245 | 246 | void nw_cache_release(nw_cache *cache) 247 | { 248 | for (uint32_t i = 0; i < cache->free; ++i) { 249 | free(cache->free_arr[i]); 250 | } 251 | free(cache->free_arr); 252 | free(cache); 253 | } 254 | 255 | -------------------------------------------------------------------------------- /asnw/nw_job.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/04/17, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | 10 | # include "nw_job.h" 11 | # include "nw_sock.h" 12 | 13 | struct thread_arg { 14 | nw_job *job; 15 | void *privdata; 16 | }; 17 | 18 | static void *thread_routine(void *data) 19 | { 20 | struct thread_arg *arg = data; 21 | nw_job *job = arg->job; 22 | void *privdata = arg->privdata; 23 | free(data); 24 | 25 | for (;;) { 26 | pthread_mutex_lock(&job->lock); 27 | while ((job->request_count == 0) && (!job->shutdown)) { 28 | pthread_cond_wait(&job->notify, &job->lock); 29 | } 30 | if (job->shutdown) { 31 | break; 32 | } 33 | assert(job->request_head != NULL); 34 | nw_job_entry *entry = job->request_head; 35 | job->request_head = entry->next; 36 | if (job->request_head) { 37 | job->request_head->prev = NULL; 38 | } else { 39 | job->request_tail = NULL; 40 | } 41 | job->request_count -= 1; 42 | pthread_mutex_unlock(&job->lock); 43 | 44 | job->type.on_job(entry, privdata); 45 | 46 | pthread_mutex_lock(&job->lock); 47 | if (job->reply_tail) { 48 | entry->prev = job->reply_tail; 49 | entry->next = NULL; 50 | job->reply_tail->next = entry; 51 | job->reply_tail = entry; 52 | } else { 53 | entry->prev = NULL; 54 | entry->next = NULL; 55 | job->reply_head = entry; 56 | job->reply_tail = entry; 57 | } 58 | job->reply_count += 1; 59 | write(job->pipefd[1], " ", 1); 60 | pthread_mutex_unlock(&job->lock); 61 | } 62 | 63 | pthread_mutex_unlock(&job->lock); 64 | return privdata; 65 | } 66 | 67 | static void on_can_read(struct ev_loop *loop, ev_io *watcher, int events) 68 | { 69 | nw_job *job = (nw_job *)watcher; 70 | for (;;) { 71 | char c; 72 | int ret = read(job->pipefd[0], &c, 1); 73 | if (ret < 0) 74 | break; 75 | } 76 | 77 | for (;;) { 78 | pthread_mutex_lock(&job->lock); 79 | if (job->reply_count == 0) { 80 | pthread_mutex_unlock(&job->lock); 81 | break; 82 | } 83 | nw_job_entry *entry = job->reply_head; 84 | job->reply_head = entry->next; 85 | if (job->reply_head) { 86 | job->reply_head->prev = NULL; 87 | } else { 88 | job->reply_tail = NULL; 89 | } 90 | job->reply_count -= 1; 91 | pthread_mutex_unlock(&job->lock); 92 | 93 | if (job->type.on_finish) 94 | job->type.on_finish(entry); 95 | if (job->type.on_cleanup) 96 | job->type.on_cleanup(entry); 97 | nw_cache_free(job->cache, entry); 98 | } 99 | } 100 | 101 | static void nw_job_free(nw_job *job) 102 | { 103 | pthread_mutex_destroy(&job->lock); 104 | pthread_cond_destroy(&job->notify); 105 | if (job->threads) 106 | free(job->threads); 107 | free(job); 108 | } 109 | 110 | nw_job *nw_job_create(nw_job_type *type, int thread_count) 111 | { 112 | if (!type->on_job) 113 | return NULL; 114 | if (type->on_init && !type->on_release) 115 | return NULL; 116 | 117 | nw_job *job = malloc(sizeof(nw_job)); 118 | if (job == NULL) 119 | return NULL; 120 | memset(job, 0, sizeof(nw_job)); 121 | nw_loop_init(); 122 | job->type = *type; 123 | job->loop = nw_default_loop; 124 | if (pthread_mutex_init(&job->lock, NULL) != 0) { 125 | free(job); 126 | return NULL; 127 | } 128 | if (pthread_cond_init(&job->notify, NULL) != 0) { 129 | pthread_mutex_destroy(&job->lock); 130 | free(job); 131 | return NULL; 132 | } 133 | job->thread_count = thread_count; 134 | job->threads = calloc(job->thread_count, sizeof(pthread_t)); 135 | if (job->threads == NULL) { 136 | nw_job_free(job); 137 | return NULL; 138 | } 139 | job->cache = nw_cache_create(sizeof(nw_job_entry)); 140 | if (job->cache == NULL) { 141 | nw_job_free(job); 142 | return NULL; 143 | } 144 | if (pipe(job->pipefd) != 0) { 145 | nw_job_free(job); 146 | return NULL; 147 | } 148 | nw_sock_set_nonblock(job->pipefd[0]); 149 | nw_sock_set_nonblock(job->pipefd[1]); 150 | ev_io_init(&job->ev, on_can_read, job->pipefd[0], EV_READ); 151 | ev_io_start(job->loop, &job->ev); 152 | 153 | for (int i = 0; i < job->thread_count; ++i) { 154 | struct thread_arg *arg = malloc(sizeof(struct thread_arg)); 155 | if (arg == NULL) { 156 | nw_job_release(job); 157 | return NULL; 158 | } 159 | memset(arg, 0, sizeof(struct thread_arg)); 160 | arg->job = job; 161 | if (job->type.on_init) { 162 | arg->privdata = job->type.on_init(); 163 | if (arg->privdata == NULL) { 164 | nw_job_release(job); 165 | return NULL; 166 | } 167 | } 168 | if (pthread_create(&job->threads[i], NULL, thread_routine, arg) != 0) { 169 | nw_job_release(job); 170 | return NULL; 171 | } 172 | job->thread_start++; 173 | } 174 | 175 | return job; 176 | } 177 | 178 | int nw_job_add(nw_job *job, uint32_t id, void *request) 179 | { 180 | nw_job_entry *entry = nw_cache_alloc(job->cache); 181 | if (entry == NULL) 182 | return -1; 183 | memset(entry, 0, sizeof(nw_job_entry)); 184 | entry->id = id; 185 | entry->request = request; 186 | 187 | pthread_mutex_lock(&job->lock); 188 | if (job->request_tail) { 189 | entry->prev = job->request_tail; 190 | entry->next = NULL; 191 | job->request_tail->next = entry; 192 | job->request_tail = entry; 193 | } else { 194 | entry->prev = NULL; 195 | entry->next = NULL; 196 | job->request_head = entry; 197 | job->request_tail = entry; 198 | } 199 | job->request_count += 1; 200 | pthread_cond_signal(&job->notify); 201 | pthread_mutex_unlock(&job->lock); 202 | 203 | return 0; 204 | } 205 | 206 | void nw_job_release(nw_job *job) 207 | { 208 | pthread_mutex_lock(&job->lock); 209 | if (job->shutdown) { 210 | pthread_mutex_unlock(&job->lock); 211 | return; 212 | } 213 | job->shutdown = true; 214 | pthread_cond_broadcast(&job->notify); 215 | pthread_mutex_unlock(&job->lock); 216 | for (int i = 0; i < job->thread_start; ++i) { 217 | void *privdata = NULL; 218 | if (pthread_join(job->threads[i], &privdata) != 0) { 219 | continue; 220 | } 221 | if (privdata != NULL && privdata != PTHREAD_CANCELED) { 222 | job->type.on_release(privdata); 223 | } 224 | } 225 | ev_io_stop(job->loop, &job->ev); 226 | close(job->pipefd[0]); 227 | close(job->pipefd[1]); 228 | nw_job_free(job); 229 | } 230 | 231 | -------------------------------------------------------------------------------- /asnw/nw_state.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/22, create 4 | */ 5 | 6 | # include 7 | # include 8 | 9 | # include "nw_state.h" 10 | 11 | # define NW_STATE_HASH_TABLE_INIT_SIZE 64 12 | 13 | nw_state *nw_state_create(nw_state_type *type, uint32_t data_size) 14 | { 15 | if (type->on_timeout == NULL) 16 | return NULL; 17 | 18 | nw_loop_init(); 19 | nw_state *context = malloc(sizeof(nw_state)); 20 | if (context == NULL) { 21 | return NULL; 22 | } 23 | memset(context, 0, sizeof(nw_state)); 24 | context->loop = nw_default_loop; 25 | context->type = *type; 26 | context->data_size = data_size; 27 | context->cache = nw_cache_create(sizeof(nw_state_entry) + data_size); 28 | if (context->cache == NULL) { 29 | free(context); 30 | return NULL; 31 | } 32 | context->table_size = NW_STATE_HASH_TABLE_INIT_SIZE; 33 | context->table_mask = context->table_size - 1; 34 | context->table = calloc(context->table_size, sizeof(nw_state_entry *)); 35 | if (context->table == NULL) { 36 | nw_cache_release(context->cache); 37 | free(context); 38 | return NULL; 39 | } 40 | 41 | return context; 42 | } 43 | 44 | static int expand_if_needed(nw_state *context) 45 | { 46 | if (context->used < context->table_size * 4) 47 | return 0; 48 | 49 | uint32_t new_table_size = context->table_size * 4; 50 | uint32_t new_table_mask = new_table_size - 1; 51 | nw_state_entry **new_table = calloc(new_table_size, sizeof(nw_state_entry *)); 52 | if (new_table == NULL) { 53 | return -1; 54 | } 55 | 56 | for (uint32_t i = 0; i < context->table_size; ++i) { 57 | nw_state_entry *entry = context->table[i]; 58 | nw_state_entry *next = NULL; 59 | while (entry) { 60 | next = entry->next; 61 | uint32_t index = entry->id & new_table_mask; 62 | entry->next = new_table[index]; 63 | new_table[index] = entry; 64 | entry = next; 65 | } 66 | } 67 | 68 | free(context->table); 69 | context->table = new_table; 70 | context->table_size = new_table_size; 71 | context->table_mask = new_table_mask; 72 | 73 | return 0; 74 | } 75 | 76 | static void state_release(nw_state *context, nw_state_entry *entry) 77 | { 78 | if (context->type.on_release) 79 | context->type.on_release(entry); 80 | nw_cache_free(context->cache, entry); 81 | } 82 | 83 | static void state_remove(nw_state *context, nw_state_entry *entry) 84 | { 85 | uint32_t index = entry->id & context->table_mask; 86 | nw_state_entry *curr = context->table[index]; 87 | nw_state_entry *prev = NULL; 88 | while (curr) { 89 | if (curr->id == entry->id) { 90 | if (prev) { 91 | prev->next = entry->next; 92 | } else { 93 | context->table[index] = entry->next; 94 | } 95 | state_release(context, entry); 96 | context->used--; 97 | return; 98 | } 99 | prev = curr; 100 | curr = curr->next; 101 | } 102 | } 103 | 104 | static void on_timeout(struct ev_loop *loop, ev_timer *ev, int events) 105 | { 106 | nw_state_entry *entry = (nw_state_entry *)ev; 107 | nw_state *context = entry->context; 108 | context->type.on_timeout(entry); 109 | state_remove(context, entry); 110 | } 111 | 112 | static uint32_t get_available_id(nw_state *context) 113 | { 114 | while (true) { 115 | context->id_start++; 116 | if (context->id_start == 0) 117 | context->id_start++; 118 | if (nw_state_get(context, context->id_start) == NULL) 119 | break; 120 | } 121 | return context->id_start; 122 | } 123 | 124 | nw_state_entry *nw_state_add(nw_state *context, double timeout, uint32_t id) 125 | { 126 | if (id != 0 && nw_state_get(context, id) != NULL) 127 | return NULL; 128 | if (context->used == UINT32_MAX) 129 | return NULL; 130 | nw_state_entry *entry = nw_cache_alloc(context->cache); 131 | if (entry == NULL) { 132 | return NULL; 133 | } 134 | 135 | if (id != 0) { 136 | entry->id = id; 137 | } else { 138 | entry->id = get_available_id(context); 139 | } 140 | ev_timer_init(&entry->ev, on_timeout, timeout, 0); 141 | ev_timer_start(context->loop, &entry->ev); 142 | entry->context = context; 143 | entry->data = ((void *)entry + sizeof(nw_state_entry)); 144 | memset(entry->data, 0, context->data_size); 145 | 146 | expand_if_needed(context); 147 | uint32_t index = entry->id & context->table_mask; 148 | entry->next = context->table[index]; 149 | context->table[index] = entry; 150 | context->used++; 151 | 152 | return entry; 153 | } 154 | 155 | nw_state_entry *nw_state_get(nw_state *context, uint32_t id) 156 | { 157 | uint32_t index = id & context->table_mask; 158 | nw_state_entry *entry = context->table[index]; 159 | while (entry) { 160 | if (entry->id == id) 161 | return entry; 162 | entry = entry->next; 163 | } 164 | 165 | return NULL; 166 | } 167 | 168 | int nw_state_mod(nw_state *context, uint32_t id, double timeout) 169 | { 170 | nw_state_entry *entry = nw_state_get(context, id); 171 | if (entry == NULL) 172 | return -1; 173 | ev_timer_stop(context->loop, &entry->ev); 174 | ev_timer_set(&entry->ev, timeout, 0); 175 | ev_timer_start(context->loop, &entry->ev); 176 | 177 | return 0; 178 | } 179 | 180 | int nw_state_del(nw_state *context, uint32_t id) 181 | { 182 | nw_state_entry *entry = nw_state_get(context, id); 183 | if (entry == NULL) 184 | return -1; 185 | ev_timer_stop(context->loop, &entry->ev); 186 | state_remove(context, entry); 187 | 188 | return 0; 189 | } 190 | 191 | size_t nw_state_count(nw_state *context) 192 | { 193 | return context->used; 194 | } 195 | 196 | void nw_state_release(nw_state *context) 197 | { 198 | for (uint32_t i = 0; i < context->table_size; ++i) { 199 | nw_state_entry *entry = context->table[i]; 200 | nw_state_entry *next = NULL; 201 | while (entry) { 202 | next = entry->next; 203 | ev_timer_stop(context->loop, &entry->ev); 204 | state_release(context, entry); 205 | entry = next; 206 | } 207 | } 208 | nw_cache_release(context->cache); 209 | free(context->table); 210 | free(context); 211 | } 212 | 213 | nw_state_iterator *nw_state_get_iterator(nw_state *context) 214 | { 215 | nw_state_iterator *iter = malloc(sizeof(nw_state_iterator)); 216 | if (iter == NULL) 217 | return NULL; 218 | memset(iter, 0, sizeof(nw_state_iterator)); 219 | iter->context = context; 220 | iter->index = -1; 221 | iter->entry = NULL; 222 | iter->next_entry = NULL; 223 | 224 | return iter; 225 | } 226 | 227 | nw_state_entry *nw_state_next(nw_state_iterator *iter) 228 | { 229 | while (true) { 230 | if (iter->entry == NULL) { 231 | iter->index++; 232 | if (iter->index >= iter->context->table_size) 233 | break; 234 | iter->entry = iter->context->table[iter->index]; 235 | } else { 236 | iter->entry = iter->next_entry; 237 | } 238 | if (iter->entry) { 239 | iter->next_entry = iter->entry->next; 240 | return iter->entry; 241 | } 242 | } 243 | 244 | return NULL; 245 | } 246 | 247 | void nw_state_iterator_release(nw_state_iterator *iter) 248 | { 249 | free(iter); 250 | } 251 | 252 | -------------------------------------------------------------------------------- /asnw/nw_sock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/16, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | 14 | # include "nw_sock.h" 15 | 16 | char *nw_sock_human_addr(nw_addr_t *addr) 17 | { 18 | static char str[128]; 19 | char ip[INET6_ADDRSTRLEN]; 20 | 21 | switch (addr->family) { 22 | case AF_INET: 23 | inet_ntop(addr->family, &addr->in.sin_addr, ip, sizeof(ip)); 24 | snprintf(str, sizeof(str), "%s:%u", ip, ntohs(addr->in.sin_port)); 25 | break; 26 | case AF_INET6: 27 | inet_ntop(addr->family, &addr->in6.sin6_addr, ip, sizeof(ip)); 28 | snprintf(str, sizeof(str), "%s:%u", ip, ntohs(addr->in6.sin6_port)); 29 | break; 30 | case AF_UNIX: 31 | snprintf(str, sizeof(str), "%s:%s", "unix", (addr->un.sun_path)); 32 | break; 33 | default: 34 | str[0] = 0; 35 | break; 36 | } 37 | 38 | return str; 39 | } 40 | 41 | char *nw_sock_human_addr_s(nw_addr_t *addr, char *dest) 42 | { 43 | char ip[INET6_ADDRSTRLEN]; 44 | 45 | switch (addr->family) { 46 | case AF_INET: 47 | inet_ntop(addr->family, &addr->in.sin_addr, ip, sizeof(ip)); 48 | snprintf(dest, NW_HUMAN_ADDR_SIZE, "%s:%u", ip, ntohs(addr->in.sin_port)); 49 | break; 50 | case AF_INET6: 51 | inet_ntop(addr->family, &addr->in6.sin6_addr, ip, sizeof(ip)); 52 | snprintf(dest, NW_HUMAN_ADDR_SIZE, "%s:%u", ip, ntohs(addr->in6.sin6_port)); 53 | break; 54 | case AF_UNIX: 55 | snprintf(dest, NW_HUMAN_ADDR_SIZE, "%s:%s", "unix", (addr->un.sun_path)); 56 | break; 57 | default: 58 | dest[0] = 0; 59 | break; 60 | } 61 | 62 | return dest; 63 | } 64 | 65 | char *nw_sock_ip(nw_addr_t *addr) 66 | { 67 | static char ip[INET6_ADDRSTRLEN]; 68 | switch (addr->family) { 69 | case AF_INET: 70 | inet_ntop(addr->family, &addr->in.sin_addr, ip, sizeof(ip)); 71 | break; 72 | case AF_INET6: 73 | inet_ntop(addr->family, &addr->in6.sin6_addr, ip, sizeof(ip)); 74 | break; 75 | default: 76 | ip[0] = 0; 77 | break; 78 | } 79 | return ip; 80 | } 81 | 82 | char *nw_sock_ip_s(nw_addr_t *addr, char *ip) 83 | { 84 | switch (addr->family) { 85 | case AF_INET: 86 | inet_ntop(addr->family, &addr->in.sin_addr, ip, NW_SOCK_IP_SIZE); 87 | break; 88 | case AF_INET6: 89 | inet_ntop(addr->family, &addr->in6.sin6_addr, ip, NW_SOCK_IP_SIZE); 90 | break; 91 | default: 92 | ip[0] = 0; 93 | break; 94 | } 95 | return ip; 96 | } 97 | 98 | int nw_sock_set_mode(nw_addr_t *addr, mode_t mode) 99 | { 100 | if (addr->family != AF_UNIX) 101 | return 0; 102 | return chmod(addr->un.sun_path, mode); 103 | } 104 | 105 | int nw_sock_peer_addr(int sockfd, nw_addr_t *addr) 106 | { 107 | addr->addrlen = sizeof(addr->un); 108 | if (getpeername(sockfd, NW_SOCKADDR(addr), &addr->addrlen) == 0) 109 | { 110 | addr->family = NW_SOCKADDR(addr)->sa_family; 111 | return 0; 112 | } 113 | return -1; 114 | } 115 | 116 | int nw_sock_host_addr(int sockfd, nw_addr_t *addr) 117 | { 118 | addr->addrlen = sizeof(addr->un); 119 | if (getsockname(sockfd, NW_SOCKADDR(addr), &addr->addrlen) == 0) 120 | { 121 | addr->family = NW_SOCKADDR(addr)->sa_family; 122 | return 0; 123 | } 124 | return -1; 125 | } 126 | 127 | static int nw_sock_addr_fill_inet(nw_addr_t *addr, const char *host, const char *port) 128 | { 129 | memset(addr, 0, sizeof(nw_addr_t)); 130 | if (strchr(host, '.') != NULL) { 131 | addr->in.sin_family = AF_INET; 132 | if (inet_pton(addr->in.sin_family, host, &addr->in.sin_addr) <= 0) { 133 | return -1; 134 | } 135 | addr->in.sin_port = htons(strtoul(port, NULL, 0)); 136 | addr->family = addr->in.sin_family; 137 | addr->addrlen = sizeof(addr->in); 138 | } else { 139 | addr->in6.sin6_family = AF_INET6; 140 | if (inet_pton(addr->in6.sin6_family, host, &addr->in6.sin6_addr) <= 0) { 141 | return -1; 142 | } 143 | addr->in6.sin6_port = htons(strtoul(port, NULL, 0)); 144 | addr->family = addr->in6.sin6_family; 145 | addr->addrlen = sizeof(addr->in6); 146 | } 147 | 148 | return 0; 149 | } 150 | 151 | int nw_sock_addr_fill_unix(nw_addr_t *addr, const char* unix_path) 152 | { 153 | size_t pathlen = strlen(unix_path); 154 | if (pathlen >= sizeof(addr->un.sun_path)) { 155 | return -1; 156 | } 157 | addr->un.sun_family = AF_UNIX; 158 | strcpy(addr->un.sun_path, unix_path); 159 | addr->family = addr->un.sun_family; 160 | addr->addrlen = sizeof(addr->un); 161 | 162 | return 0; 163 | } 164 | 165 | int nw_sock_cfg_parse(const char *cfg, nw_addr_t *addr, int *sock_type) 166 | { 167 | char *s = strdup(cfg); 168 | char *sep = strchr(s, '@'); 169 | if (sep == NULL) { 170 | free(s); 171 | return -1; 172 | } 173 | *sep = '\0'; 174 | char *type = s; 175 | char *name = sep + 1; 176 | int is_inet = 0; 177 | 178 | if (strcasecmp(type, "tcp") == 0) { 179 | *sock_type = SOCK_STREAM; 180 | is_inet = 1; 181 | } else if (strcasecmp(type, "udp") == 0) { 182 | *sock_type = SOCK_DGRAM; 183 | is_inet = 1; 184 | } else if (strcasecmp(type, "stream") == 0) { 185 | *sock_type = SOCK_STREAM; 186 | } else if (strcasecmp(type, "dgram") == 0) { 187 | *sock_type = SOCK_DGRAM; 188 | } else if (strcasecmp(type, "seqpacket") == 0) { 189 | *sock_type = SOCK_SEQPACKET; 190 | } else { 191 | free(s); 192 | return -2; 193 | } 194 | 195 | if (is_inet) { 196 | sep = strchr(name, ':'); 197 | if (sep == NULL) { 198 | free(s); 199 | return -3; 200 | } 201 | *sep = '\0'; 202 | char *host = name; 203 | char *port = sep + 1; 204 | if (nw_sock_addr_fill_inet(addr, host, port) < 0) { 205 | free(s); 206 | return -4; 207 | } 208 | } else { 209 | if (nw_sock_addr_fill_unix(addr, name) < 0) { 210 | free(s); 211 | return -5; 212 | } 213 | } 214 | 215 | free(s); 216 | return 0; 217 | } 218 | 219 | int nw_sock_errno(int sockfd) 220 | { 221 | int _errno = 0; 222 | socklen_t len = sizeof(int); 223 | if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &_errno, &len) == 0) 224 | return _errno; 225 | if (errno != 0) 226 | return errno; 227 | return EBADFD; 228 | } 229 | 230 | int nw_sock_get_send_buf(int sockfd, int *buf_size) 231 | { 232 | socklen_t len = sizeof(*buf_size); 233 | if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, buf_size, &len) != 0) 234 | return -1; 235 | return 0; 236 | } 237 | 238 | int nw_sock_get_recv_buf(int sockfd, int *buf_size) 239 | { 240 | socklen_t len = sizeof(*buf_size); 241 | if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, buf_size, &len) != 0) 242 | return -1; 243 | return 0; 244 | } 245 | 246 | int nw_sock_set_send_buf(int sockfd, int buf_size) 247 | { 248 | if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)) != 0) 249 | return -1; 250 | return 0; 251 | } 252 | 253 | int nw_sock_set_recv_buf(int sockfd, int buf_size) 254 | { 255 | if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size)) != 0) 256 | return -1; 257 | return 0; 258 | } 259 | 260 | int nw_sock_set_nonblock(int sockfd) 261 | { 262 | int flags = fcntl(sockfd, F_GETFL, 0); 263 | if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) != 0) 264 | return -1; 265 | return 0; 266 | } 267 | 268 | int nw_sock_set_no_delay(int sockfd) 269 | { 270 | int val = 1; 271 | if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) != 0) 272 | return -1; 273 | return 0; 274 | } 275 | 276 | int nw_sock_set_reuse_addr(int sockfd) 277 | { 278 | int val = 1; 279 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != 0) 280 | return -1; 281 | return 0; 282 | } 283 | 284 | -------------------------------------------------------------------------------- /test/listener_worker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/23, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | # include 11 | # include 12 | # include 13 | 14 | # include "nw_svr.h" 15 | # include "nw_clt.h" 16 | 17 | int worker_id; 18 | uint32_t max_pkg_size = 10240; 19 | nw_svr *outer_svr; 20 | nw_svr *inner_svr; 21 | nw_clt *inner_clt; 22 | const char *inner_sock_cfg = "seqpacket@/tmp/test_worker.sock"; 23 | 24 | int outer_decode_pkg(nw_ses *ses, void *data, size_t max) 25 | { 26 | char *s = data; 27 | for (size_t i = 0; i < max; ++i) { 28 | if (s[i] == '\n') 29 | return i + 1; 30 | } 31 | return 0; 32 | } 33 | 34 | int outer_on_accept(nw_ses *ses, int sockfd, nw_addr_t *peer_addr) 35 | { 36 | if (inner_svr->clt_count == 0) { 37 | printf("worker: %d, no available worker\n", worker_id); 38 | return -1; 39 | } 40 | int worker = rand() % inner_svr->clt_count; 41 | nw_ses *curr = inner_svr->clt_list_head; 42 | for (int i = 0; i < worker && curr != NULL; ++i) { 43 | curr = curr->next; 44 | } 45 | if (!curr) { 46 | return -1; 47 | } 48 | if (nw_ses_send_fd(curr, sockfd) < 0) { 49 | return -1; 50 | } 51 | 52 | // close it after success send 53 | close(sockfd); 54 | 55 | return 0; 56 | } 57 | 58 | void outer_on_new_connection(nw_ses *ses) 59 | { 60 | printf("worker: %d: new connection from: %s\n", worker_id, nw_sock_human_addr(&ses->peer_addr)); 61 | } 62 | 63 | void outer_on_connection_close(nw_ses *ses) 64 | { 65 | printf("worker: %d: connection: %s close\n", worker_id, nw_sock_human_addr(&ses->peer_addr)); 66 | } 67 | 68 | void outer_on_recv_pkg(nw_ses *ses, void *data, size_t size) 69 | { 70 | char *str = malloc(size + 1); 71 | memcpy(str, data, size); 72 | str[size] = 0; 73 | printf("worker: %d, from: %s recv: %zu: %s", worker_id, nw_sock_human_addr(&ses->peer_addr), size, str); 74 | if (nw_ses_send(ses, data, size) < 0) { 75 | printf("nw_ses_send fail\n"); 76 | } 77 | free(str); 78 | } 79 | 80 | void outer_on_error_msg(nw_ses *ses, const char *msg) 81 | { 82 | printf("worker: %d, outer error: %s\n", worker_id, msg); 83 | } 84 | 85 | void inner_svr_on_new_connection(nw_ses *ses) 86 | { 87 | printf("new worker connection\n"); 88 | } 89 | 90 | void inner_svr_on_connection_close(nw_ses *ses) 91 | { 92 | printf("worker connection close\n"); 93 | } 94 | 95 | void inner_svr_on_recv_pkg(nw_ses *ses, void *data, size_t size) 96 | { 97 | return; 98 | } 99 | 100 | void inner_svr_on_error_msg(nw_ses *ses, const char *msg) 101 | { 102 | printf("listener error: %s\n", msg); 103 | } 104 | 105 | void inner_clt_on_connect(nw_ses *ses, bool result) 106 | { 107 | if (result) { 108 | printf("worker: %d connect listener success\n", worker_id); 109 | } else { 110 | printf("worker: %d connect listener fail\n", worker_id); 111 | } 112 | } 113 | 114 | int inner_clt_on_close(nw_ses *ses) 115 | { 116 | printf("worker: %d connection with listener close\n", worker_id); 117 | } 118 | 119 | void inner_clt_on_recv_pkg(nw_ses *ses, void *data, size_t size) 120 | { 121 | return; 122 | } 123 | 124 | void inner_clt_on_recv_fd(nw_ses *ses, int fd) 125 | { 126 | if (nw_svr_add_clt_fd(outer_svr, fd) < 0) { 127 | printf("worker: %d: nw_svr_add_clt_fd fail\n", worker_id); 128 | } else { 129 | printf("worker: %d recv fd success\n", worker_id); 130 | } 131 | } 132 | 133 | void inner_clt_on_error_msg(nw_ses *ses, const char *msg) 134 | { 135 | printf("worker: %d: clt error msg: %s\n", worker_id, msg); 136 | } 137 | 138 | int init_outer_svr(nw_svr_bind *bind) 139 | { 140 | nw_svr_cfg cfg; 141 | memset(&cfg, 0, sizeof(cfg)); 142 | cfg.bind_arr = bind; 143 | cfg.bind_count = 1; 144 | cfg.max_pkg_size = max_pkg_size; 145 | 146 | nw_svr_type type; 147 | memset(&type, 0, sizeof(type)); 148 | type.decode_pkg = outer_decode_pkg; 149 | type.on_accept = outer_on_accept; 150 | type.on_new_connection = outer_on_new_connection; 151 | type.on_connection_close = outer_on_connection_close; 152 | type.on_recv_pkg = outer_on_recv_pkg; 153 | type.on_error_msg = outer_on_error_msg; 154 | 155 | outer_svr = nw_svr_create(&cfg, &type, NULL); 156 | if (outer_svr == NULL) { 157 | return -1; 158 | } 159 | 160 | return 0; 161 | } 162 | 163 | int init_inner_svr(void) 164 | { 165 | nw_svr_bind bind; 166 | if (nw_sock_cfg_parse(inner_sock_cfg, &bind.addr, &bind.sock_type) < 0) { 167 | return -1; 168 | } 169 | 170 | nw_svr_cfg cfg; 171 | memset(&cfg, 0, sizeof(cfg)); 172 | cfg.bind_arr = &bind; 173 | cfg.bind_count = 1; 174 | cfg.max_pkg_size = max_pkg_size; 175 | 176 | nw_svr_type type; 177 | memset(&type, 0, sizeof(type)); 178 | type.on_new_connection = inner_svr_on_new_connection; 179 | type.on_connection_close = inner_svr_on_connection_close; 180 | type.on_recv_pkg = inner_svr_on_recv_pkg; 181 | type.on_error_msg = inner_svr_on_error_msg; 182 | 183 | inner_svr = nw_svr_create(&cfg, &type, NULL); 184 | if (inner_svr == NULL) { 185 | return -1; 186 | } 187 | 188 | return 0; 189 | } 190 | 191 | int init_inner_clt(void) 192 | { 193 | nw_clt_cfg cfg; 194 | memset(&cfg, 0, sizeof(cfg)); 195 | if (nw_sock_cfg_parse(inner_sock_cfg, &cfg.addr, &cfg.sock_type) < 0) { 196 | return -1; 197 | } 198 | cfg.max_pkg_size = max_pkg_size; 199 | 200 | nw_clt_type type; 201 | memset(&type, 0, sizeof(type)); 202 | type.on_connect = inner_clt_on_connect; 203 | type.on_close = inner_clt_on_close; 204 | type.on_recv_pkg = inner_clt_on_recv_pkg; 205 | type.on_recv_fd = inner_clt_on_recv_fd; 206 | type.on_error_msg = inner_clt_on_error_msg; 207 | 208 | inner_clt = nw_clt_create(&cfg, &type, NULL); 209 | if (inner_clt == NULL) { 210 | return -1; 211 | } 212 | 213 | return 0; 214 | } 215 | 216 | int init_as_listener(nw_svr_bind *bind) 217 | { 218 | if (init_outer_svr(bind) < 0) { 219 | printf("init_outer_svr fail\n"); 220 | return -1; 221 | } 222 | if (nw_svr_start(outer_svr) < 0) { 223 | printf("nw_svr_start fail\n"); 224 | return -1; 225 | } 226 | if (init_inner_svr() < 0) { 227 | printf("init_inner_svr fail\n"); 228 | return -1; 229 | } 230 | if (nw_svr_start(inner_svr) < 0) { 231 | printf("nw_svr_start fail\n"); 232 | return -1; 233 | } 234 | 235 | printf("listener start\n"); 236 | 237 | return 0; 238 | } 239 | 240 | int init_as_worker(nw_svr_bind *bind) 241 | { 242 | if (init_outer_svr(bind) < 0) { 243 | printf("init_outer_svr fail\n"); 244 | return -1; 245 | } 246 | if (init_inner_clt() < 0) { 247 | printf("init_inner_clt fail\n"); 248 | return -1; 249 | } 250 | 251 | printf("worker: %d start\n", worker_id); 252 | 253 | return 0; 254 | } 255 | 256 | int main(int argc, char *argv[]) 257 | { 258 | if (argc != 3) { 259 | printf("usage: %s bind worker-num\n", argv[0]); 260 | return 0; 261 | } 262 | 263 | nw_svr_bind bind; 264 | if (nw_sock_cfg_parse(argv[1], &bind.addr, &bind.sock_type) < 0) { 265 | printf("parse bind: %s fail\n", argv[1]); 266 | return 0; 267 | } 268 | if (bind.sock_type != SOCK_STREAM) { 269 | printf("not stream: %s\n", argv[1]); 270 | return 0; 271 | } 272 | size_t worker_num = atoi(argv[2]); 273 | if (worker_num == 0) { 274 | printf("invalid num: %s\n", argv[2]); 275 | } 276 | 277 | for (size_t i = 0; i < worker_num; ++i) { 278 | int pid = fork(); 279 | if (pid < 0) { 280 | error(1, errno, "fork error"); 281 | } else if (pid == 0) { 282 | worker_id = i + 1; 283 | if (init_as_worker(&bind) < 0) { 284 | error(1, errno, "init worker: %d fail", worker_id); 285 | } 286 | break; 287 | } 288 | } 289 | 290 | if (worker_id == 0) { 291 | if (init_as_listener(&bind) < 0) { 292 | error(1, errno, "init listener fail"); 293 | } 294 | } else { 295 | if (nw_clt_start(inner_clt) < 0) { 296 | error(1, errno, "nw_clt_start fail"); 297 | } 298 | } 299 | 300 | daemon(true, true); 301 | nw_loop_run(); 302 | 303 | return 0; 304 | } 305 | 306 | -------------------------------------------------------------------------------- /asnw/nw_clt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/22, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | # include 10 | 11 | # include "nw_clt.h" 12 | 13 | static int create_socket(int family, int sock_type) 14 | { 15 | int sockfd = socket(family, sock_type, 0); 16 | if (sockfd < 0) { 17 | return -1; 18 | } 19 | if (nw_sock_set_nonblock(sockfd) < 0) { 20 | close(sockfd); 21 | return -1; 22 | } 23 | if (sock_type == SOCK_STREAM && (family == AF_INET || family == AF_INET6)) { 24 | if (nw_sock_set_no_delay(sockfd) < 0) { 25 | close(sockfd); 26 | return -1; 27 | } 28 | } 29 | 30 | return sockfd; 31 | } 32 | 33 | static int set_socket_option(nw_clt *clt, int sockfd) 34 | { 35 | if (clt->read_mem > 0) { 36 | if (nw_sock_set_recv_buf(sockfd, clt->read_mem) < 0) { 37 | close(sockfd); 38 | return -1; 39 | } 40 | } 41 | if (clt->write_mem > 0) { 42 | if (nw_sock_set_send_buf(sockfd, clt->write_mem) < 0) { 43 | close(sockfd); 44 | return -1; 45 | } 46 | } 47 | 48 | return 0; 49 | } 50 | 51 | static void generate_random_path(char *path, size_t size, char *prefix, char *suffix) 52 | { 53 | struct timeval tv; 54 | gettimeofday(&tv, NULL); 55 | srand(tv.tv_sec * tv.tv_usec); 56 | char randname[11]; 57 | for (int i = 0; i < 10; ++i) { 58 | randname[i] = 'a' + rand() % 26; 59 | } 60 | randname[10] = '\0'; 61 | snprintf(path, size, "%s/%s%s%s", P_tmpdir, prefix, randname, suffix); 62 | } 63 | 64 | static void on_reconnect_timeout(nw_timer *timer, void *privdata) 65 | { 66 | nw_clt *clt = (nw_clt *)privdata; 67 | nw_clt_start(clt); 68 | } 69 | 70 | static void reconnect_later(nw_clt *clt) 71 | { 72 | nw_timer_set(&clt->timer, clt->reconnect_timeout, false, on_reconnect_timeout, clt); 73 | nw_timer_start(&clt->timer); 74 | } 75 | 76 | static void on_connect_timeout(nw_timer *timer, void *privdata) 77 | { 78 | nw_clt *clt = (nw_clt *)privdata; 79 | if (!clt->on_connect_called) { 80 | nw_clt_close(clt); 81 | nw_clt_start(clt); 82 | } 83 | } 84 | 85 | static void watch_connect(nw_clt *clt) 86 | { 87 | nw_timer_set(&clt->timer, clt->reconnect_timeout, false, on_connect_timeout, clt); 88 | nw_timer_start(&clt->timer); 89 | } 90 | 91 | static void on_recv_fd(nw_ses *ses, int fd) 92 | { 93 | close(fd); 94 | } 95 | 96 | static int clt_close(nw_clt *clt) 97 | { 98 | if (nw_timer_active(&clt->timer)) { 99 | nw_timer_stop(&clt->timer); 100 | } 101 | clt->connected = false; 102 | return nw_ses_close(&clt->ses); 103 | } 104 | 105 | static void on_connect(nw_ses *ses, bool result) 106 | { 107 | nw_clt *clt = (nw_clt *)ses; 108 | clt->on_connect_called = true; 109 | if (result) { 110 | clt->connected = true; 111 | set_socket_option(clt, clt->ses.sockfd); 112 | nw_sock_host_addr(ses->sockfd, ses->host_addr); 113 | if (clt->type.on_connect) { 114 | clt->type.on_connect(ses, result); 115 | } 116 | } else { 117 | if (clt->type.on_connect) { 118 | clt->type.on_connect(ses, result); 119 | } 120 | int ret = 0; 121 | if (clt->type.on_close) { 122 | ret = clt->type.on_close(&clt->ses); 123 | } 124 | clt_close(clt); 125 | if (ret > 0) { 126 | nw_clt_start(clt); 127 | } else { 128 | reconnect_later(clt); 129 | } 130 | } 131 | } 132 | 133 | static void on_error(nw_ses *ses, const char *msg) 134 | { 135 | nw_clt *clt = (nw_clt *)ses; 136 | if (clt->type.on_error_msg) { 137 | clt->type.on_error_msg(ses, msg); 138 | } 139 | if (ses->sock_type == SOCK_DGRAM) 140 | return; 141 | int ret = 0; 142 | if (clt->type.on_close) { 143 | ret = clt->type.on_close(&clt->ses); 144 | } 145 | clt_close(clt); 146 | if (ret > 0) { 147 | nw_clt_start(clt); 148 | } else { 149 | reconnect_later(clt); 150 | } 151 | } 152 | 153 | static void on_close(nw_ses *ses) 154 | { 155 | nw_clt *clt = (nw_clt *)ses; 156 | int ret = 0; 157 | if (clt->type.on_close) { 158 | ret = clt->type.on_close(&clt->ses); 159 | } 160 | clt_close(clt); 161 | if (ret > 0) { 162 | nw_clt_start(clt); 163 | } else { 164 | reconnect_later(clt); 165 | } 166 | } 167 | 168 | nw_clt *nw_clt_create(nw_clt_cfg *cfg, nw_clt_type *type, void *privdata) 169 | { 170 | nw_loop_init(); 171 | 172 | if (cfg->max_pkg_size == 0) 173 | return NULL; 174 | if (type->decode_pkg == NULL) 175 | return NULL; 176 | if (type->on_recv_pkg == NULL) 177 | return NULL; 178 | 179 | nw_clt *clt = malloc(sizeof(nw_clt)); 180 | memset(clt, 0, sizeof(nw_clt)); 181 | clt->type = *type; 182 | clt->reconnect_timeout = cfg->reconnect_timeout == 0 ? 1.0 : cfg->reconnect_timeout; 183 | if (cfg->buf_pool) { 184 | clt->custom_buf_pool = true; 185 | clt->buf_pool = cfg->buf_pool; 186 | } else { 187 | clt->custom_buf_pool = false; 188 | clt->buf_pool = nw_buf_pool_create(cfg->max_pkg_size); 189 | if (clt->buf_pool == NULL) { 190 | nw_clt_release(clt); 191 | return NULL; 192 | } 193 | } 194 | clt->read_mem = cfg->read_mem; 195 | clt->write_mem = cfg->write_mem; 196 | 197 | nw_addr_t *host_addr = malloc(sizeof(nw_addr_t)); 198 | if (host_addr == NULL) { 199 | nw_clt_release(clt); 200 | return NULL; 201 | } 202 | memset(host_addr, 0, sizeof(nw_addr_t)); 203 | host_addr->family = cfg->addr.family; 204 | host_addr->addrlen = cfg->addr.addrlen; 205 | 206 | if (nw_ses_init(&clt->ses, nw_default_loop, clt->buf_pool, cfg->buf_limit, NW_SES_TYPE_CLIENT) < 0) { 207 | nw_clt_release(clt); 208 | return NULL; 209 | } 210 | memcpy(&clt->ses.peer_addr, &cfg->addr, sizeof(nw_addr_t)); 211 | clt->ses.host_addr = host_addr; 212 | clt->ses.sockfd = -1; 213 | clt->ses.sock_type = cfg->sock_type; 214 | clt->ses.privdata = privdata; 215 | 216 | clt->ses.decode_pkg = type->decode_pkg; 217 | clt->ses.on_recv_pkg = type->on_recv_pkg; 218 | clt->ses.on_recv_fd = type->on_recv_fd == NULL ? on_recv_fd : type->on_recv_fd; 219 | clt->ses.on_connect = on_connect; 220 | clt->ses.on_error = on_error; 221 | clt->ses.on_close = on_close; 222 | 223 | return clt; 224 | } 225 | 226 | int nw_clt_start(nw_clt *clt) 227 | { 228 | int sockfd = create_socket(clt->ses.peer_addr.family, clt->ses.sock_type); 229 | if (sockfd < 0) { 230 | return -1; 231 | } 232 | clt->ses.sockfd = sockfd; 233 | if (clt->ses.peer_addr.family == AF_UNIX && clt->ses.sock_type == SOCK_DGRAM) { 234 | clt->ses.host_addr->un.sun_family = AF_UNIX; 235 | generate_random_path(clt->ses.host_addr->un.sun_path, sizeof(clt->ses.host_addr->un.sun_path), "dgram", ".sock"); 236 | if (nw_ses_bind(&clt->ses, clt->ses.host_addr) < 0) { 237 | return -1; 238 | } 239 | } 240 | 241 | if (clt->ses.sock_type == SOCK_STREAM || clt->ses.sock_type == SOCK_SEQPACKET) { 242 | clt->connected = false; 243 | clt->on_connect_called = false; 244 | int ret = nw_ses_connect(&clt->ses, &clt->ses.peer_addr); 245 | if (ret < 0) { 246 | if (clt->type.on_close) { 247 | ret = clt->type.on_close(&clt->ses); 248 | } 249 | clt_close(clt); 250 | if (ret > 0) { 251 | nw_clt_start(clt); 252 | } else { 253 | reconnect_later(clt); 254 | } 255 | } 256 | if (!clt->on_connect_called) { 257 | watch_connect(clt); 258 | } 259 | return 0; 260 | } else { 261 | clt->connected = true; 262 | set_socket_option(clt, clt->ses.sockfd); 263 | nw_sock_host_addr(clt->ses.sockfd, clt->ses.host_addr); 264 | return nw_ses_start(&clt->ses); 265 | } 266 | } 267 | 268 | int nw_clt_close(nw_clt *clt) 269 | { 270 | if (clt->type.on_close) { 271 | clt->type.on_close(&clt->ses); 272 | } 273 | return clt_close(clt); 274 | } 275 | 276 | void nw_clt_release(nw_clt *clt) 277 | { 278 | nw_ses_release(&clt->ses); 279 | if (!clt->custom_buf_pool && clt->buf_pool) { 280 | nw_buf_pool_release(clt->buf_pool); 281 | } 282 | free(clt->ses.host_addr); 283 | free(clt); 284 | } 285 | 286 | bool nw_clt_connected(nw_clt *clt) 287 | { 288 | return clt->connected; 289 | } 290 | 291 | -------------------------------------------------------------------------------- /asnw/nw_svr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/20, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | 10 | # include "nw_svr.h" 11 | 12 | static int create_socket(int family, int sock_type) 13 | { 14 | int sockfd = socket(family, sock_type, 0); 15 | if (sockfd < 0) 16 | return -1; 17 | if (nw_sock_set_nonblock(sockfd) < 0) { 18 | close(sockfd); 19 | return -1; 20 | } 21 | if (nw_sock_set_reuse_addr(sockfd) < 0) { 22 | close(sockfd); 23 | return -1; 24 | } 25 | if (sock_type == SOCK_STREAM && (family == AF_INET || family == AF_INET6)) { 26 | if (nw_sock_set_no_delay(sockfd) < 0) { 27 | close(sockfd); 28 | return -1; 29 | } 30 | } 31 | 32 | return sockfd; 33 | } 34 | 35 | static int set_socket_option(nw_svr *svr, int sockfd) 36 | { 37 | if (svr->read_mem > 0) { 38 | if (nw_sock_set_recv_buf(sockfd, svr->read_mem) < 0) { 39 | close(sockfd); 40 | return -1; 41 | } 42 | } 43 | if (svr->write_mem > 0) { 44 | if (nw_sock_set_send_buf(sockfd, svr->write_mem) < 0) { 45 | close(sockfd); 46 | return -1; 47 | } 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | static void on_error(nw_ses *ses, const char *msg) 54 | { 55 | nw_svr *svr = (nw_svr *)ses->svr; 56 | if (svr->type.on_error_msg) { 57 | svr->type.on_error_msg(ses, msg); 58 | } 59 | if (ses->ses_type == NW_SES_TYPE_COMMON) { 60 | nw_svr_close_clt(svr, ses); 61 | } 62 | } 63 | 64 | static void on_close(nw_ses *ses) 65 | { 66 | nw_svr *svr = (nw_svr *)ses->svr; 67 | if (ses->ses_type == NW_SES_TYPE_COMMON) { 68 | nw_svr_close_clt(svr, ses); 69 | } 70 | } 71 | 72 | static void on_recv_fd(nw_ses *ses, int fd) 73 | { 74 | close(fd); 75 | } 76 | 77 | static void nw_svr_free(nw_svr *svr) 78 | { 79 | if (svr->buf_pool) 80 | nw_buf_pool_release(svr->buf_pool); 81 | if (svr->clt_cache) 82 | nw_cache_release(svr->clt_cache); 83 | if (svr->svr_list) { 84 | for (uint32_t i = 0; i < svr->svr_count; ++i) { 85 | if (svr->svr_list[i].write_buf != NULL) { 86 | nw_ses_release(&svr->svr_list[i]); 87 | free(svr->svr_list[i].host_addr); 88 | } 89 | } 90 | free(svr->svr_list); 91 | } 92 | free(svr); 93 | } 94 | 95 | static int nw_svr_add_clt(nw_ses *ses, int sockfd, nw_addr_t *peer_addr) 96 | { 97 | nw_svr *svr = (nw_svr *)ses->svr; 98 | set_socket_option(svr, sockfd); 99 | if (nw_sock_set_nonblock(sockfd) < 0) { 100 | return -1; 101 | } 102 | 103 | void *privdata = NULL; 104 | if (svr->type.on_privdata_alloc) { 105 | privdata = svr->type.on_privdata_alloc(svr); 106 | if (privdata == NULL) { 107 | return -1; 108 | } 109 | } 110 | 111 | nw_ses *clt = nw_cache_alloc(svr->clt_cache); 112 | if (clt == NULL) { 113 | return -1; 114 | } 115 | memset(clt, 0, sizeof(nw_ses)); 116 | if (nw_ses_init(clt, nw_default_loop, svr->buf_pool, svr->buf_limit, NW_SES_TYPE_COMMON) < 0) { 117 | nw_cache_free(svr->clt_cache, clt); 118 | if (privdata) { 119 | svr->type.on_privdata_free(svr, privdata); 120 | } 121 | return -1; 122 | } 123 | memcpy(&clt->peer_addr, peer_addr, sizeof(nw_addr_t)); 124 | clt->host_addr = ses->host_addr; 125 | clt->sockfd = sockfd; 126 | clt->sock_type = ses->sock_type; 127 | clt->privdata = privdata; 128 | clt->svr = svr; 129 | 130 | clt->id = svr->id_start++; 131 | if (clt->id == 0) 132 | clt->id = svr->id_start++; 133 | 134 | clt->decode_pkg = svr->type.decode_pkg; 135 | clt->on_recv_pkg = svr->type.on_recv_pkg; 136 | clt->on_recv_fd = svr->type.on_recv_fd == NULL ? on_recv_fd : svr->type.on_recv_fd; 137 | clt->on_error = on_error; 138 | clt->on_close = on_close; 139 | 140 | if (svr->clt_list_tail) { 141 | clt->prev = svr->clt_list_tail; 142 | svr->clt_list_tail->next = clt; 143 | svr->clt_list_tail = clt; 144 | clt->next = NULL; 145 | } else { 146 | svr->clt_list_head = clt; 147 | svr->clt_list_tail = clt; 148 | clt->prev = NULL; 149 | clt->next = NULL; 150 | } 151 | svr->clt_count++; 152 | nw_ses_start(clt); 153 | 154 | if (svr->type.on_new_connection) { 155 | svr->type.on_new_connection(clt); 156 | } 157 | 158 | return 0; 159 | } 160 | 161 | static int on_accept(nw_ses *ses, int sockfd, nw_addr_t *peer_addr) 162 | { 163 | nw_svr *svr = (nw_svr *)ses->svr; 164 | if (svr->type.on_accept) { 165 | return svr->type.on_accept(ses, sockfd, peer_addr); 166 | } 167 | return nw_svr_add_clt(ses, sockfd, peer_addr); 168 | } 169 | 170 | int nw_svr_add_clt_fd(nw_svr *svr, int fd) 171 | { 172 | nw_addr_t peer_addr; 173 | if (nw_sock_peer_addr(fd, &peer_addr) < 0) { 174 | return -1; 175 | } 176 | nw_ses *ses = NULL; 177 | for (uint32_t i = 0; i < svr->svr_count; ++i) { 178 | if (peer_addr.family == svr->svr_list[i].host_addr->family) { 179 | ses = &svr->svr_list[i]; 180 | break; 181 | } 182 | } 183 | if (ses == NULL) 184 | return -1; 185 | return nw_svr_add_clt(ses, fd, &peer_addr); 186 | } 187 | 188 | nw_svr *nw_svr_create(nw_svr_cfg *cfg, nw_svr_type *type, void *privdata) 189 | { 190 | nw_loop_init(); 191 | 192 | if (cfg->bind_count == 0) 193 | return NULL; 194 | if (cfg->max_pkg_size == 0) 195 | return NULL; 196 | if (type->decode_pkg == NULL) 197 | return NULL; 198 | if (type->on_recv_pkg == NULL) 199 | return NULL; 200 | if (type->on_privdata_alloc && !type->on_privdata_free) 201 | return NULL; 202 | 203 | nw_svr *svr = malloc(sizeof(nw_svr)); 204 | if (svr == NULL) 205 | return NULL; 206 | memset(svr, 0, sizeof(nw_svr)); 207 | svr->type = *type; 208 | svr->svr_count = cfg->bind_count; 209 | svr->svr_list = malloc(sizeof(nw_ses) * svr->svr_count); 210 | if (svr->svr_list == NULL) { 211 | nw_svr_free(svr); 212 | return NULL; 213 | } 214 | svr->buf_pool = nw_buf_pool_create(cfg->max_pkg_size); 215 | if (svr->buf_pool == NULL) { 216 | nw_svr_free(svr); 217 | return NULL; 218 | } 219 | svr->clt_cache = nw_cache_create(sizeof(nw_ses)); 220 | if (svr->clt_cache == NULL) { 221 | nw_svr_free(svr); 222 | return NULL; 223 | } 224 | svr->buf_limit = cfg->buf_limit; 225 | svr->read_mem = cfg->read_mem; 226 | svr->write_mem = cfg->write_mem; 227 | svr->privdata = privdata; 228 | memset(svr->svr_list, 0, sizeof(nw_ses) * svr->svr_count); 229 | for (uint32_t i = 0; i < svr->svr_count; ++i) { 230 | nw_ses *ses = &svr->svr_list[i]; 231 | int sockfd = create_socket(cfg->bind_arr[i].addr.family, cfg->bind_arr[i].sock_type); 232 | if (sockfd < 0) { 233 | nw_svr_free(svr); 234 | return NULL; 235 | } 236 | nw_addr_t *host_addr = malloc(sizeof(nw_addr_t)); 237 | if (host_addr == NULL) { 238 | nw_svr_free(svr); 239 | return NULL; 240 | } 241 | memcpy(host_addr, &cfg->bind_arr[i].addr, sizeof(nw_addr_t)); 242 | if (nw_ses_init(ses, nw_default_loop, svr->buf_pool, svr->buf_limit, NW_SES_TYPE_SERVER) < 0) { 243 | free(host_addr); 244 | nw_svr_free(svr); 245 | return NULL; 246 | } 247 | ses->sockfd = sockfd; 248 | ses->sock_type = cfg->bind_arr[i].sock_type; 249 | ses->host_addr = host_addr; 250 | ses->svr = svr; 251 | 252 | ses->on_accept = on_accept; 253 | ses->decode_pkg = type->decode_pkg; 254 | ses->on_recv_pkg = type->on_recv_pkg; 255 | ses->on_recv_fd = type->on_recv_fd == NULL ? on_recv_fd : type->on_recv_fd; 256 | ses->on_error = on_error; 257 | ses->on_close = on_close; 258 | 259 | if (cfg->bind_arr[i].sock_type == SOCK_DGRAM) { 260 | ses->peer_addr.family = host_addr->family; 261 | ses->peer_addr.addrlen = host_addr->addrlen; 262 | set_socket_option(svr, sockfd); 263 | } 264 | } 265 | 266 | return svr; 267 | } 268 | 269 | int nw_svr_start(nw_svr *svr) 270 | { 271 | for (uint32_t i = 0; i < svr->svr_count; ++i) { 272 | nw_ses *ses = &svr->svr_list[i]; 273 | if (nw_ses_bind(ses, ses->host_addr) < 0) { 274 | return -1; 275 | } 276 | if (nw_ses_start(ses) < 0) { 277 | return -1; 278 | } 279 | } 280 | 281 | return 0; 282 | } 283 | 284 | int nw_svr_stop(nw_svr *svr) 285 | { 286 | for (uint32_t i = 0; i < svr->svr_count; ++i) { 287 | if (nw_ses_stop(&svr->svr_list[i]) < 0) { 288 | return -1; 289 | } 290 | } 291 | return 0; 292 | } 293 | 294 | void nw_svr_release(nw_svr *svr) 295 | { 296 | nw_svr_stop(svr); 297 | nw_ses *curr = svr->clt_list_head; 298 | while (curr) { 299 | nw_ses *next = curr->next; 300 | if (svr->type.on_connection_close) { 301 | svr->type.on_connection_close(curr); 302 | } 303 | if (curr->privdata) { 304 | svr->type.on_privdata_free(svr, curr->privdata); 305 | } 306 | nw_ses_release(curr); 307 | nw_cache_free(svr->clt_cache, curr); 308 | curr = next; 309 | } 310 | for (uint32_t i = 0; i < svr->svr_count; ++i) { 311 | nw_ses_release(&svr->svr_list[i]); 312 | } 313 | nw_cache_release(svr->clt_cache); 314 | nw_svr_free(svr); 315 | } 316 | 317 | void nw_svr_close_clt(nw_svr *svr, nw_ses *ses) 318 | { 319 | if (ses->id == 0) 320 | return; 321 | if (ses->ses_type != NW_SES_TYPE_COMMON) 322 | return; 323 | 324 | if (svr->type.on_connection_close) { 325 | svr->type.on_connection_close(ses); 326 | } 327 | if (ses->prev) { 328 | ses->prev->next = ses->next; 329 | } else { 330 | svr->clt_list_head = ses->next; 331 | } 332 | if (ses->next) { 333 | ses->next->prev = ses->prev; 334 | } else { 335 | svr->clt_list_tail = ses->prev; 336 | } 337 | if (ses->privdata) { 338 | svr->type.on_privdata_free(svr, ses->privdata); 339 | } 340 | nw_ses_release(ses); 341 | nw_cache_free(svr->clt_cache, ses); 342 | svr->clt_count--; 343 | } 344 | 345 | -------------------------------------------------------------------------------- /asnw/nw_ses.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: 3 | * History: yang@haipo.me, 2016/03/19, create 4 | */ 5 | 6 | # include 7 | # include 8 | # include 9 | 10 | # include "nw_ses.h" 11 | 12 | static void libev_on_read_write_evt(struct ev_loop *loop, ev_io *watcher, int events); 13 | static void libev_on_accept_evt(struct ev_loop *loop, ev_io *watcher, int events); 14 | static void libev_on_connect_evt(struct ev_loop *loop, ev_io *watcher, int events); 15 | 16 | static void watch_stop(nw_ses *ses) 17 | { 18 | if (ev_is_active(&ses->ev)) { 19 | ev_io_stop(ses->loop, &ses->ev); 20 | } 21 | } 22 | 23 | static void watch_read(nw_ses *ses) 24 | { 25 | if (ev_is_active(&ses->ev)) { 26 | ev_io_stop(ses->loop, &ses->ev); 27 | } 28 | ev_io_init(&ses->ev, libev_on_read_write_evt, ses->sockfd, EV_READ); 29 | ev_io_start(ses->loop, &ses->ev); 30 | } 31 | 32 | static void watch_read_write(nw_ses *ses) 33 | { 34 | if (ev_is_active(&ses->ev)) { 35 | ev_io_stop(ses->loop, &ses->ev); 36 | } 37 | ev_io_init(&ses->ev, libev_on_read_write_evt, ses->sockfd, EV_READ | EV_WRITE); 38 | ev_io_start(ses->loop, &ses->ev); 39 | } 40 | 41 | static void watch_accept(nw_ses *ses) 42 | { 43 | ev_io_init(&ses->ev, libev_on_accept_evt, ses->sockfd, EV_READ); 44 | ev_io_start(ses->loop, &ses->ev); 45 | } 46 | 47 | static void watch_connect(nw_ses *ses) 48 | { 49 | ev_io_init(&ses->ev, libev_on_connect_evt, ses->sockfd, EV_WRITE); 50 | ev_io_start(ses->loop, &ses->ev); 51 | } 52 | 53 | static int nw_write_stream(nw_ses *ses, const void *data, size_t size) 54 | { 55 | size_t spos = 0; 56 | while (spos < size) { 57 | int ret = write(ses->sockfd, data + spos, size - spos); 58 | if (ret > 0) { 59 | spos += ret; 60 | } else if (ret < 0) { 61 | if (errno == EINTR) { 62 | continue; 63 | } 64 | break; 65 | } else { 66 | break; 67 | } 68 | } 69 | 70 | return spos; 71 | } 72 | 73 | static int nw_write_packet(nw_ses *ses, const void *data, size_t size) 74 | { 75 | while (true) { 76 | struct msghdr msg; 77 | struct iovec io; 78 | 79 | memset(&msg, 0, sizeof(msg)); 80 | io.iov_base = (void *)data; 81 | io.iov_len = size; 82 | msg.msg_iov = &io; 83 | msg.msg_iovlen = 1; 84 | 85 | int ret = sendmsg(ses->sockfd, &msg, MSG_EOR); 86 | if (ret < 0 && errno == EINTR) { 87 | continue; 88 | } else { 89 | return ret; 90 | } 91 | } 92 | } 93 | 94 | static void on_can_read(nw_ses *ses) 95 | { 96 | if (ses->sockfd < 0) 97 | return; 98 | if (ses->read_buf == NULL) { 99 | ses->read_buf = nw_buf_alloc(ses->pool); 100 | if (ses->read_buf == NULL) { 101 | ses->on_error(ses, "no recv buf"); 102 | return; 103 | } 104 | } 105 | 106 | switch (ses->sock_type) { 107 | case SOCK_STREAM: 108 | { 109 | while (true) { 110 | int ret = read(ses->sockfd, ses->read_buf->data + ses->read_buf->wpos, nw_buf_avail(ses->read_buf)); 111 | if (ret < 0) { 112 | if (errno == EINTR) { 113 | continue; 114 | } else if (errno == EAGAIN || errno == EWOULDBLOCK) { 115 | break; 116 | } else { 117 | char errmsg[100]; 118 | snprintf(errmsg, sizeof(errmsg), "read error: %s", strerror(errno)); 119 | ses->on_error(ses, errmsg); 120 | return; 121 | } 122 | } else if (ret == 0) { 123 | ses->on_close(ses); 124 | return; 125 | } else { 126 | ses->read_buf->wpos += ret; 127 | } 128 | 129 | size_t size = 0; 130 | while ((size = nw_buf_size(ses->read_buf)) > 0) { 131 | ret = ses->decode_pkg(ses, ses->read_buf->data + ses->read_buf->rpos, size); 132 | if (ret < 0) { 133 | char errmsg[100]; 134 | snprintf(errmsg, sizeof(errmsg), "decode msg error: %d", ret); 135 | ses->on_error(ses, errmsg); 136 | return; 137 | } else if (ret > 0) { 138 | ses->on_recv_pkg(ses, ses->read_buf->data + ses->read_buf->rpos, ret); 139 | if (!ses->read_buf) 140 | return; 141 | ses->read_buf->rpos += ret; 142 | } else { 143 | nw_buf_shift(ses->read_buf); 144 | if (ses->read_buf->wpos == ses->read_buf->size) { 145 | ses->on_error(ses, "decode msg error"); 146 | return; 147 | } 148 | break; 149 | } 150 | } 151 | 152 | nw_buf_shift(ses->read_buf); 153 | } 154 | if (nw_buf_size(ses->read_buf) == 0) { 155 | nw_buf_free(ses->pool, ses->read_buf); 156 | ses->read_buf = NULL; 157 | } 158 | } 159 | break; 160 | case SOCK_DGRAM: 161 | { 162 | while (true) { 163 | int ret = recvfrom(ses->sockfd, ses->read_buf->data, ses->read_buf->size, 0, \ 164 | NW_SOCKADDR(&ses->peer_addr), &ses->peer_addr.addrlen); 165 | if (ret < 0) { 166 | if (errno == EINTR) { 167 | continue; 168 | } else if (errno == EAGAIN || errno == EWOULDBLOCK) { 169 | break; 170 | } else { 171 | char errmsg[100]; 172 | snprintf(errmsg, sizeof(errmsg), "recvfrom error: %s", strerror(errno)); 173 | ses->on_error(ses, errmsg); 174 | return; 175 | } 176 | } 177 | int pkg_size = ret; 178 | ret = ses->decode_pkg(ses, ses->read_buf->data, pkg_size); 179 | if (ret < 0) { 180 | char errmsg[100]; 181 | snprintf(errmsg, sizeof(errmsg), "decode msg error: %d", ret); 182 | ses->on_error(ses, errmsg); 183 | return; 184 | } 185 | ses->on_recv_pkg(ses, ses->read_buf->data, ret); 186 | if (!ses->read_buf) 187 | return; 188 | } 189 | nw_buf_free(ses->pool, ses->read_buf); 190 | ses->read_buf = NULL; 191 | } 192 | break; 193 | case SOCK_SEQPACKET: 194 | { 195 | while (true) { 196 | struct msghdr msg; 197 | struct iovec io; 198 | char control[CMSG_SPACE(sizeof(int))]; 199 | 200 | memset(&msg, 0, sizeof(msg)); 201 | io.iov_base = ses->read_buf->data; 202 | io.iov_len = ses->read_buf->size; 203 | msg.msg_iov = &io; 204 | msg.msg_iovlen = 1; 205 | msg.msg_control = control; 206 | msg.msg_controllen = sizeof(control); 207 | 208 | int ret = recvmsg(ses->sockfd, &msg, 0); 209 | if (ret < 0) { 210 | if (errno == EINTR) { 211 | continue; 212 | } else if (errno == EAGAIN || errno == EWOULDBLOCK) { 213 | break; 214 | } else { 215 | char errmsg[100]; 216 | snprintf(errmsg, sizeof(errmsg), "recvmsg error: %s", strerror(errno)); 217 | ses->on_error(ses, errmsg); 218 | return; 219 | } 220 | } else if (ret == 0) { 221 | ses->on_close(ses); 222 | return; 223 | } 224 | 225 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 226 | if (cmsg != NULL) { 227 | if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type==SCM_RIGHTS) { 228 | int fd = *(int *)CMSG_DATA(cmsg); 229 | ses->on_recv_fd(ses, fd); 230 | } 231 | } else { 232 | int pkg_size = ret; 233 | ret = ses->decode_pkg(ses, ses->read_buf->data, pkg_size); 234 | if (ret < 0) { 235 | char errmsg[100]; 236 | snprintf(errmsg, sizeof(errmsg), "decode msg error: %d", ret); 237 | ses->on_error(ses, errmsg); 238 | return; 239 | } 240 | ses->on_recv_pkg(ses, ses->read_buf->data, ret); 241 | if (!ses->read_buf) 242 | return; 243 | } 244 | } 245 | nw_buf_free(ses->pool, ses->read_buf); 246 | ses->read_buf = NULL; 247 | } 248 | break; 249 | } 250 | } 251 | 252 | static void on_can_write(nw_ses *ses) 253 | { 254 | if (ses->sockfd < 0) 255 | return; 256 | 257 | while (ses->write_buf->count > 0) { 258 | nw_buf *buf = ses->write_buf->head; 259 | size_t size = nw_buf_size(buf); 260 | int nwrite = 0; 261 | if (ses->sock_type == SOCK_STREAM) { 262 | nwrite = nw_write_stream(ses, buf->data + buf->rpos, size); 263 | } else { 264 | nwrite = nw_write_packet(ses, buf->data + buf->rpos, size); 265 | } 266 | if (nwrite < size) { 267 | if (errno == EAGAIN || errno == EWOULDBLOCK) { 268 | if (ses->sock_type == SOCK_STREAM) { 269 | buf->rpos += nwrite; 270 | break; 271 | } else { 272 | break; 273 | } 274 | } else { 275 | char errmsg[100]; 276 | snprintf(errmsg, sizeof(errmsg), "write error: %s", strerror(errno)); 277 | ses->on_error(ses, errmsg); 278 | return; 279 | } 280 | } else { 281 | nw_buf_list_shift(ses->write_buf); 282 | } 283 | } 284 | 285 | if (ses->write_buf->count == 0) { 286 | watch_read(ses); 287 | } 288 | } 289 | 290 | static void on_can_accept(nw_ses *ses) 291 | { 292 | if (ses->sockfd < 0) 293 | return; 294 | 295 | while (true) { 296 | nw_addr_t peer_addr; 297 | memset(&peer_addr, 0, sizeof(peer_addr)); 298 | peer_addr.family = ses->host_addr->family; 299 | peer_addr.addrlen = ses->host_addr->addrlen; 300 | int sockfd = accept(ses->sockfd, NW_SOCKADDR(&peer_addr), &peer_addr.addrlen); 301 | if (sockfd < 0) { 302 | if (errno == EINTR) { 303 | continue; 304 | } else if (errno == EAGAIN || errno == EWOULDBLOCK) { 305 | break; 306 | } else { 307 | char errmsg[100]; 308 | snprintf(errmsg, sizeof(errmsg), "accept error: %s", strerror(errno)); 309 | ses->on_error(ses, errmsg); 310 | return; 311 | } 312 | } else { 313 | int ret = ses->on_accept(ses, sockfd, &peer_addr); 314 | if (ret < 0) { 315 | close(sockfd); 316 | } 317 | } 318 | } 319 | } 320 | 321 | static void on_can_connect(nw_ses *ses) 322 | { 323 | if (ses->sockfd < 0) 324 | return; 325 | errno = nw_sock_errno(ses->sockfd); 326 | if (errno != 0) { 327 | ses->on_connect(ses, false); 328 | return; 329 | } 330 | watch_read(ses); 331 | ses->on_connect(ses, true); 332 | } 333 | 334 | static void libev_on_read_write_evt(struct ev_loop *loop, ev_io *watcher, int events) 335 | { 336 | nw_ses *ses = (nw_ses *)watcher; 337 | if (events & EV_READ) 338 | on_can_read(ses); 339 | if (events & EV_WRITE) 340 | on_can_write(ses); 341 | } 342 | 343 | static void libev_on_accept_evt(struct ev_loop *loop, ev_io *watcher, int events) 344 | { 345 | nw_ses *ses = (nw_ses *)watcher; 346 | if (events & EV_READ) 347 | on_can_accept(ses); 348 | } 349 | 350 | static void libev_on_connect_evt(struct ev_loop *loop, ev_io *watcher, int events) 351 | { 352 | nw_ses *ses = (nw_ses *)watcher; 353 | watch_stop(ses); 354 | if (events & EV_WRITE) 355 | on_can_connect(ses); 356 | } 357 | 358 | int nw_ses_bind(nw_ses *ses, nw_addr_t *addr) 359 | { 360 | if (addr->family == AF_UNIX) { 361 | unlink(addr->un.sun_path); 362 | } 363 | int ret = bind(ses->sockfd, NW_SOCKADDR(addr), addr->addrlen); 364 | if (ret < 0) 365 | return ret; 366 | if (addr->family == AF_UNIX) { 367 | return nw_sock_set_mode(addr, 0777); 368 | } 369 | return 0; 370 | } 371 | 372 | int nw_ses_listen(nw_ses *ses, int backlog) 373 | { 374 | int ret = listen(ses->sockfd, backlog); 375 | if (ret < 0) 376 | return -1; 377 | watch_accept(ses); 378 | return 0; 379 | } 380 | 381 | int nw_ses_connect(nw_ses *ses, nw_addr_t *addr) 382 | { 383 | int ret = connect(ses->sockfd, NW_SOCKADDR(addr), addr->addrlen); 384 | if (ret == 0) { 385 | watch_read(ses); 386 | ses->on_connect(ses, true); 387 | return 0; 388 | } 389 | if (errno == EINPROGRESS) { 390 | watch_connect(ses); 391 | } else { 392 | ses->on_connect(ses, false); 393 | return -1; 394 | } 395 | return 0; 396 | } 397 | 398 | int nw_ses_start(nw_ses *ses) 399 | { 400 | if (ses->ses_type == NW_SES_TYPE_SERVER && (ses->sock_type == SOCK_STREAM || ses->sock_type == SOCK_SEQPACKET)) { 401 | return nw_ses_listen(ses, SOMAXCONN); 402 | } else { 403 | watch_read(ses); 404 | } 405 | return 0; 406 | } 407 | 408 | int nw_ses_stop(nw_ses *ses) 409 | { 410 | watch_stop(ses); 411 | return 0; 412 | } 413 | 414 | int nw_ses_send(nw_ses *ses, const void *data, size_t size) 415 | { 416 | if (ses->sockfd < 0) { 417 | return -1; 418 | } 419 | 420 | if (ses->write_buf->count > 0) { 421 | size_t nwrite; 422 | if (ses->sock_type == SOCK_STREAM) { 423 | nwrite = nw_buf_list_write(ses->write_buf, data, size); 424 | } else { 425 | nwrite = nw_buf_list_append(ses->write_buf, data, size); 426 | } 427 | if (nwrite != size) { 428 | ses->on_error(ses, "no send buf"); 429 | return -1; 430 | } 431 | } else { 432 | switch (ses->sock_type) { 433 | case SOCK_STREAM: 434 | { 435 | int nwrite = nw_write_stream(ses, data, size); 436 | if (nwrite < size) { 437 | if (errno == EAGAIN || errno == EWOULDBLOCK) { 438 | if (nw_buf_list_write(ses->write_buf, data + nwrite, size - nwrite) != (size - nwrite)) { 439 | ses->on_error(ses, "no send buf"); 440 | return -1; 441 | } 442 | watch_read_write(ses); 443 | } else { 444 | char errmsg[100]; 445 | snprintf(errmsg, sizeof(errmsg), "write error: %s", strerror(errno)); 446 | ses->on_error(ses, errmsg); 447 | return -1; 448 | } 449 | } 450 | } 451 | break; 452 | case SOCK_DGRAM: 453 | { 454 | int ret = sendto(ses->sockfd, data, size, 0, NW_SOCKADDR(&ses->peer_addr), ses->peer_addr.addrlen); 455 | if (ret < 0) { 456 | char errmsg[100]; 457 | snprintf(errmsg, sizeof(errmsg), "sendto error: %s", strerror(errno)); 458 | ses->on_error(ses, errmsg); 459 | return -1; 460 | } 461 | } 462 | break; 463 | case SOCK_SEQPACKET: 464 | { 465 | int ret = nw_write_packet(ses, data, size); 466 | if (ret < 0) { 467 | if (errno == EAGAIN || errno == EWOULDBLOCK) { 468 | if (nw_buf_list_append(ses->write_buf, data, size) != size) { 469 | ses->on_error(ses, "on send buf"); 470 | return -1; 471 | } 472 | watch_read_write(ses); 473 | } else { 474 | char errmsg[100]; 475 | snprintf(errmsg, sizeof(errmsg), "sendmsg error: %s", strerror(errno)); 476 | ses->on_error(ses, errmsg); 477 | return -1; 478 | } 479 | } 480 | } 481 | break; 482 | default: 483 | break; 484 | } 485 | } 486 | 487 | return 0; 488 | } 489 | 490 | int nw_ses_send_fd(nw_ses *ses, int fd) 491 | { 492 | if (ses->sockfd < 0 || ses->sock_type != SOCK_SEQPACKET) { 493 | return -1; 494 | } 495 | 496 | struct msghdr msg; 497 | struct iovec io; 498 | char control[CMSG_SPACE(sizeof(int))]; 499 | 500 | memset(&msg, 0, sizeof(msg)); 501 | io.iov_base = &fd; 502 | io.iov_len = sizeof(fd); 503 | msg.msg_iov = &io; 504 | msg.msg_iovlen = 1; 505 | msg.msg_control = control; 506 | msg.msg_controllen = sizeof(control); 507 | 508 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 509 | cmsg->cmsg_level = SOL_SOCKET; 510 | cmsg->cmsg_type = SCM_RIGHTS; 511 | cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 512 | *((int *)CMSG_DATA(cmsg)) = fd; 513 | 514 | return sendmsg(ses->sockfd, &msg, MSG_EOR); 515 | } 516 | 517 | int nw_ses_init(nw_ses *ses, struct ev_loop *loop, nw_buf_pool *pool, uint32_t buf_limit, int ses_type) 518 | { 519 | memset(ses, 0, sizeof(nw_ses)); 520 | ses->loop = loop; 521 | ses->ses_type = ses_type; 522 | ses->pool = pool; 523 | ses->write_buf = nw_buf_list_create(pool, buf_limit); 524 | if (ses->write_buf == NULL) { 525 | return -1; 526 | } 527 | 528 | return 0; 529 | } 530 | 531 | int nw_ses_close(nw_ses *ses) 532 | { 533 | watch_stop(ses); 534 | ses->id = 0; 535 | if (ses->sockfd >= 0) { 536 | close(ses->sockfd); 537 | ses->sockfd = -1; 538 | } 539 | if (ses->read_buf) { 540 | nw_buf_free(ses->pool, ses->read_buf); 541 | ses->read_buf = NULL; 542 | } 543 | if (ses->write_buf) { 544 | while (ses->write_buf->count) { 545 | nw_buf_list_shift(ses->write_buf); 546 | } 547 | } 548 | 549 | return 0; 550 | } 551 | 552 | int nw_ses_release(nw_ses *ses) 553 | { 554 | nw_ses_close(ses); 555 | if (ses->write_buf) { 556 | nw_buf_list_release(ses->write_buf); 557 | ses->write_buf = NULL; 558 | } 559 | 560 | return 0; 561 | } 562 | 563 | --------------------------------------------------------------------------------