From b73d188e309844410fbe0f077f5ae82a0304f5f4 Mon Sep 17 00:00:00 2001 From: zhengshuxin Date: Fri, 7 Apr 2017 20:13:08 +0800 Subject: [PATCH] support IPV6. --- lib_acl/changes.txt | 8 + lib_acl/include/net/acl_connect.h | 27 +- lib_acl/include/net/acl_sane_inet.h | 2 + lib_acl/include/stdlib/acl_define_unix.h | 1 + lib_acl/include/stdlib/acl_define_win32.h | 2 + lib_acl/include/stdlib/acl_mbox.h | 38 ++ lib_acl/include/stdlib/acl_mystring.h | 24 +- lib_acl/include/stdlib/acl_sys_patch.h | 19 + lib_acl/include/thread/acl_pthread.h | 23 +- lib_acl/samples/connect/main.cpp | 31 +- lib_acl/samples/server/main.c | 15 +- lib_acl/src/event/events_define.h | 2 +- lib_acl/src/net/acl_host_port.c | 22 +- lib_acl/src/net/acl_sane_inet.c | 77 ++- lib_acl/src/net/acl_valid_hostname.c | 57 +- lib_acl/src/net/connect/acl_inet_connect.c | 249 +++---- lib_acl/src/net/connect/acl_sane_connect.c | 10 +- lib_acl/src/net/connect/acl_timed_connect.c | 14 +- lib_acl/src/net/ipv6_patch.h | 24 + lib_acl/src/net/listen/acl_inet_listen.c | 151 +++-- lib_acl/src/stdlib/acl_atomic.c | 2 +- lib_acl/src/stdlib/acl_mbox.c | 13 +- lib_acl/src/stdlib/common/acl_yqueue.c | 1 + lib_acl/src/stdlib/iostuff/acl_write_wait.c | 3 + lib_acl/src/stdlib/sys/acl_sys_socket.c | 5 + lib_acl/src/thread/acl_pthread_cond.c | 21 +- lib_acl/src/thread/acl_pthread_mutex.c | 14 +- lib_acl_cpp/acl_cpp.xcodeproj/project.pbxproj | 6 + lib_acl_cpp/changes.txt | 2 + lib_acl_cpp/include/acl_cpp/lib_acl.hpp | 1 + lib_acl_cpp/include/acl_cpp/stdlib/mbox.hpp | 56 ++ .../include/acl_cpp/stream/socket_stream.hpp | 18 + lib_acl_cpp/lib_acl_cpp_vc2003.vcproj | 6 + lib_acl_cpp/lib_acl_cpp_vc2008.vcproj | 8 + lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj | 2 + .../lib_acl_cpp_vc2010.vcxproj.filters | 6 + lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj | 2 + .../lib_acl_cpp_vc2012.vcxproj.filters | 8 +- lib_acl_cpp/lib_acl_cpp_vc2015.vcxproj | 2 + .../lib_acl_cpp_vc2015.vcxproj.filters | 6 + lib_acl_cpp/samples/json/json1/json.cpp | 2 +- lib_acl_cpp/src/serialize/gsoner.cpp | 14 +- lib_acl_cpp/src/stdlib/mbox.cpp | 51 ++ lib_acl_cpp/src/stream/socket_stream.cpp | 30 + lib_fiber/c/src/fiber.c.star | 636 ++++++++++++++++++ lib_fiber/samples/mbox/Makefile | 2 + lib_fiber/samples/mbox/main.cpp | 148 ++++ lib_fiber/samples/mbox/stdafx.cpp | 1 + lib_fiber/samples/mbox/stdafx.h | 20 + lib_fiber/samples/mbox/valgrind.sh | 4 + 50 files changed, 1547 insertions(+), 339 deletions(-) create mode 100644 lib_acl/src/net/ipv6_patch.h create mode 100644 lib_acl_cpp/include/acl_cpp/stdlib/mbox.hpp create mode 100644 lib_acl_cpp/src/stdlib/mbox.cpp create mode 100644 lib_fiber/c/src/fiber.c.star create mode 100644 lib_fiber/samples/mbox/Makefile create mode 100644 lib_fiber/samples/mbox/main.cpp create mode 100644 lib_fiber/samples/mbox/stdafx.cpp create mode 100644 lib_fiber/samples/mbox/stdafx.h create mode 100644 lib_fiber/samples/mbox/valgrind.sh diff --git a/lib_acl/changes.txt b/lib_acl/changes.txt index fdfb1e47a..acc3a1810 100644 --- a/lib_acl/changes.txt +++ b/lib_acl/changes.txt @@ -1,5 +1,13 @@ 修改历史列表: +------------------------------------------------------------------------ + +579) 2017.4.7 +579.1) feature: 网络监听及网络连接模块支持 IPV6 + +578) 2017.4.5 +578.1) bugfix: acl_atomic.c/acl_mbox.c/acl_pthread_mutext.c 存在内存泄露问题 + 577) 2017.3.30 577.1) feature: json 类对象在创建 json 字符串时默认不自动添加空格,但允许调用者 设置参数以便于自动添加空格从而使 json 字符串更可读 diff --git a/lib_acl/include/net/acl_connect.h b/lib_acl/include/net/acl_connect.h index 067d7de67..a52ca89fe 100644 --- a/lib_acl/include/net/acl_connect.h +++ b/lib_acl/include/net/acl_connect.h @@ -41,25 +41,26 @@ ACL_API int acl_timed_connect(ACL_SOCKET fd, const struct sockaddr * sa, /** * 远程连接网络服务器地址 - * @param addr {const char*} 远程服务器的监听地址,如:192.168.0.1:80, 如果需要绑定本地 - * 的地址,则格式为: {local_ip}@{remote_addr}, 如: 60.28.250.199@www.sina.com:80 - * @param block_mode {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING - * @param timeout {int} 连接超时时间,如果 block_mode 为 ACL_NON_BLOCKING 则该值将被忽略 + * @param addr {const char*} 远程服务器的监听地址,如:192.168.0.1:80, 如果需 + * 要绑定本地的地址,则格式为: {local_ip}@{remote_addr}, + * 如: 60.28.250.199@www.sina.com:80 + * @param blocking {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING + * @param timeout {int} 连接超时时间,如果 blocking 为 ACL_NON_BLOCKING 则该值将被忽略 * @return {ACL_SOCKET} 如果返回 ACL_SOCKET_INVALID 表示连接失败 */ -ACL_API ACL_SOCKET acl_inet_connect(const char *addr, int block_mode, int timeout); +ACL_API ACL_SOCKET acl_inet_connect(const char *addr, int blocking, int timeout); /** * 远程连接网络服务器地址 * @param addr {const char*} 远程服务器的监听地址,如:192.168.0.1:80, * 当本机有多个网卡地址且想通过某个指定网卡连接服务器时的地址格式: - local_ip@remote_ip:remote_port,如:192.168.1.1@211.150.111.12:80 - * @param block_mode {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING - * @param timeout {int} 连接超时时间,如果 block_mode 为 ACL_NON_BLOCKING 则该值将被忽略 + * local_ip@remote_ip:remote_port,如:192.168.1.1@211.150.111.12:80 + * @param blocking {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING + * @param timeout {int} 连接超时时间,如果 blocking 为 ACL_NON_BLOCKING 则该值将被忽略 * @param h_error {int*} 当连接失败时存储失败原因错误号 * @return {ACL_SOCKET} 如果返回 ACL_SOCKET_INVALID 表示连接失败 */ -ACL_API ACL_SOCKET acl_inet_connect_ex(const char *addr, int block_mode, +ACL_API ACL_SOCKET acl_inet_connect_ex(const char *addr, int blocking, int timeout, int *h_error); #ifdef ACL_UNIX @@ -69,15 +70,15 @@ ACL_API ACL_SOCKET acl_inet_connect_ex(const char *addr, int block_mode, /** * 连接监听域套接字服务器 * @param addr {const char*} 服务器监听的域套接字全路径, 如: /tmp/test.sock - * @param block_mode {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING - * @param timeout {int} 连接超时时间,如果 block_mode 为 ACL_NON_BLOCKING 则该值将被忽略 + * @param blocking {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING + * @param timeout {int} 连接超时时间,如果 blocking 为 ACL_NON_BLOCKING 则该值将被忽略 * @return {ACL_SOCKET} 如果返回 ACL_SOCKET_INVALID 表示连接失败 */ -ACL_API ACL_SOCKET acl_unix_connect(const char *addr, int block_mode, int timeout); +ACL_API ACL_SOCKET acl_unix_connect(const char *addr, int blocking, int timeout); /* in acl_stream_connect.c */ #ifdef SUNOS5 -ACL_API int acl_stream_connect(const char *path, int block_mode, int unused_timeout); +ACL_API int acl_stream_connect(const char *path, int blocking, int timeout); #endif #endif diff --git a/lib_acl/include/net/acl_sane_inet.h b/lib_acl/include/net/acl_sane_inet.h index 12cf4d487..c543e541a 100644 --- a/lib_acl/include/net/acl_sane_inet.h +++ b/lib_acl/include/net/acl_sane_inet.h @@ -34,6 +34,8 @@ ACL_API const char *acl_inet_ntoa(struct in_addr in, char *dst, size_t size); * @return {int} 0: 是; -1: 否 */ ACL_API int acl_is_ip(const char *ip); +ACL_API int acl_is_ipv4(const char *ip); +ACL_API int acl_is_ipv6(const char *ip); /** * 判断所给的 ip 地址是否符合 xxx.xxx.xxx.xxx 格式 diff --git a/lib_acl/include/stdlib/acl_define_unix.h b/lib_acl/include/stdlib/acl_define_unix.h index 43823c161..6d2c29d08 100644 --- a/lib_acl/include/stdlib/acl_define_unix.h +++ b/lib_acl/include/stdlib/acl_define_unix.h @@ -40,6 +40,7 @@ # include # include +# include # ifndef acl_assert # define acl_assert assert diff --git a/lib_acl/include/stdlib/acl_define_win32.h b/lib_acl/include/stdlib/acl_define_win32.h index 81e1b88e3..9cf86a5b0 100644 --- a/lib_acl/include/stdlib/acl_define_win32.h +++ b/lib_acl/include/stdlib/acl_define_win32.h @@ -92,6 +92,8 @@ # include # endif +# include /* for getaddrinfo */ + # ifdef ACL_BCB_COMPILER # pragma hdrstop # endif diff --git a/lib_acl/include/stdlib/acl_mbox.h b/lib_acl/include/stdlib/acl_mbox.h index 3453fd603..7e764945d 100644 --- a/lib_acl/include/stdlib/acl_mbox.h +++ b/lib_acl/include/stdlib/acl_mbox.h @@ -9,11 +9,49 @@ extern "C" { typedef struct ACL_MBOX ACL_MBOX; +/** + * 创建无锁消息队列对象 + * @return {ACL_MBOX} + */ ACL_API ACL_MBOX *acl_mbox_create(void); + +/** + * 释放无锁消息队列对象 + * @param mbox {ACL_MBOX*} 消息队列对象 + * @param free_fn {void (*)(void*)} 非空时用来释放当前存在于消息队列中的对象 + */ ACL_API void acl_mbox_free(ACL_MBOX *mbox, void (*free_fn)(void*)); + +/** + * 向消息队列中添加动态消息对象 + * @param mbox {ACL_MBOX*} 消息队列对象 + * @param msg {void*} + * @return {int} 发送成功返回 0,否则返回 -1 + */ ACL_API int acl_mbox_send(ACL_MBOX *mbox, void *msg); + +/** + * 从消息队列中读取消息 + * @param mbox {ACL_MBOX*} 消息队列对象 + * @param timeout {int} 等待超时时间(秒) + * @param success {int*} 存储操作是否成功的结果, 0 表示出错,非 0 表示成功 + * @return {void*} 返回读到的消息对象,如果返回 NULL 时还需判断 success 的值,以此来 + * 判断读操作是否成功,如果返回非 NULL 表示成功读到一条消息 + */ ACL_API void *acl_mbox_read(ACL_MBOX *mbox, int timeout, int *success); + +/** + * 获得当前消息队列已经成功发送的消息数 + * @param mbox {ACL_MBOX*} 消息队列对象 + * @return {size_t} + */ ACL_API size_t acl_mbox_nsend(ACL_MBOX *mbox); + +/** + * 获得当前消息队列已经成功接收到的消息数 + * @param mbox {ACL_MBOX*} 消息队列对象 + * @return {size_t} + */ ACL_API size_t acl_mbox_nread(ACL_MBOX *mbox); #ifdef __cplusplus diff --git a/lib_acl/include/stdlib/acl_mystring.h b/lib_acl/include/stdlib/acl_mystring.h index db79d82c2..9969d1fd2 100644 --- a/lib_acl/include/stdlib/acl_mystring.h +++ b/lib_acl/include/stdlib/acl_mystring.h @@ -16,25 +16,15 @@ extern "C" { * @param _size {int} 目的内存区的空间大小 */ #ifndef ACL_SAFE_STRNCPY -#if defined(_WIN32) || defined(_WIN64) -#define ACL_SAFE_STRNCPY(_obj, _src, _size) do { \ - size_t _n = strlen(_src); \ - _n = _n > (size_t ) _size - 1? (size_t) _size - 1 : _n; \ - memcpy(_obj, _src, _n); \ - _obj[_n] = 0; \ -} while (0) -#else -#define ACL_SAFE_STRNCPY(_obj, _src, _size) do { \ - if (_size > 0) { \ - strncpy(_obj, _src, _size); \ - if ((int)_size > 0) \ - _obj[_size - 1] = 0; \ - else \ - _obj[_size] = 0; \ - } \ +#define ACL_SAFE_STRNCPY(_obj, _src, _size) do { \ + if (_size > 0) { \ + size_t _n = strlen(_src); \ + _n = _n > (size_t ) _size - 1? (size_t) _size - 1 : _n; \ + memcpy(_obj, _src, _n); \ + _obj[_n] = 0; \ + } \ } while (0) #endif -#endif /** * 将字符串转换为小写,直接在原内存空间进行操作 diff --git a/lib_acl/include/stdlib/acl_sys_patch.h b/lib_acl/include/stdlib/acl_sys_patch.h index eae255024..dc83a7cbe 100644 --- a/lib_acl/include/stdlib/acl_sys_patch.h +++ b/lib_acl/include/stdlib/acl_sys_patch.h @@ -64,6 +64,25 @@ ACL_API int acl_socket_end(void); */ ACL_API int acl_socket_close(ACL_SOCKET fd); +/** + * 禁止套接口的发送与接收 + * @param fd {ACL_SOCKET} 套接字 + * @param how {int} + * @return {int} 返回 0 表示操作成功,否则表示出错 + */ +#if defined(_WIN32) || defined(_WIN64) +# ifndef SHUT_RD +# define SHUT_RD SD_RECEIVE +# endif +# ifndef SHUT_WR +# define SHUT_WR SD_SEND +# endif +# ifndef SHUT_RDWR +# define SHUT_RDWR SD_BOTH +# endif +#endif +ACL_API int acl_socket_shutdown(ACL_SOCKET fd, int how); + /** * 从套接字读数据 * @param fd {ACL_SOCKET} 网络套接字 diff --git a/lib_acl/include/thread/acl_pthread.h b/lib_acl/include/thread/acl_pthread.h index 18fac1044..904aaed2d 100644 --- a/lib_acl/include/thread/acl_pthread.h +++ b/lib_acl/include/thread/acl_pthread.h @@ -1,5 +1,5 @@ -#ifndef ACL_PTHREAD_WIN32_INCLUDE_H -#define ACL_PTHREAD_WIN32_INCLUDE_H +#ifndef __ACL_PTHREAD_INCLUDE_H__ +#define __ACL_PTHREAD_INCLUDE_H__ #ifdef __cplusplus extern "C" { @@ -35,13 +35,11 @@ typedef pthread_once_t acl_pthread_once_t; #define acl_pthread_detach pthread_detach #define acl_pthread_once pthread_once #define acl_pthread_join pthread_join -#define acl_pthread_mutex_destroy pthread_mutex_destroy #define acl_pthread_mutex_init pthread_mutex_init #define acl_pthread_mutex_lock pthread_mutex_lock #define acl_pthread_mutex_unlock pthread_mutex_unlock #define acl_pthread_mutex_trylock pthread_mutex_trylock #define acl_pthread_cond_init pthread_cond_init -/* #define acl_pthread_cond_create pthread_cond_create */ #define acl_pthread_cond_destroy pthread_cond_destroy #define acl_pthread_cond_signal pthread_cond_signal #define acl_pthread_cond_broadcast pthread_cond_broadcast @@ -147,7 +145,6 @@ ACL_API int acl_pthread_detach(acl_pthread_t thread); ACL_API int acl_pthread_join(acl_pthread_t thread, void **thread_return); /* in acl_pthread_mutex.c */ -ACL_API int acl_pthread_mutex_destroy(acl_pthread_mutex_t *mutex); ACL_API int acl_pthread_mutex_init(acl_pthread_mutex_t *mutex, const acl_pthread_mutexattr_t *mattr); ACL_API int acl_pthread_mutex_lock(acl_pthread_mutex_t *mutex); @@ -158,7 +155,11 @@ ACL_API int acl_pthread_mutex_unlock(acl_pthread_mutex_t *mutex); /* in acl_pthread_cond.c */ ACL_API int acl_pthread_cond_init(acl_pthread_cond_t *cond, acl_pthread_condattr_t *cond_attr); -ACL_API acl_pthread_cond_t * acl_pthread_cond_create(void); +ACL_API acl_pthread_cond_t *acl_thread_cond_create(void); +#ifndef acl_pthread_cond_create +#define acl_pthread_cond_create acl_thread_cond_create +#endif + ACL_API int acl_pthread_cond_destroy(acl_pthread_cond_t *cond); ACL_API int acl_pthread_cond_signal(acl_pthread_cond_t *cond); ACL_API int acl_pthread_cond_broadcast(acl_pthread_cond_t *cond); @@ -177,7 +178,12 @@ ACL_API int acl_thread_mutex_unlock(acl_pthread_mutex_t *mutex); ACL_API int acl_thread_mutex_nested(acl_pthread_mutex_t *mutex); /* in acl_pthread_mutex.c */ -ACL_API acl_pthread_mutex_t *acl_pthread_mutex_create(void); +ACL_API acl_pthread_mutex_t *acl_thread_mutex_create(void); +#ifndef acl_pthread_mutex_create +#define acl_pthread_mutex_create acl_thread_mutex_create +#endif + +ACL_API int acl_pthread_mutex_destroy(acl_pthread_mutex_t *mutex); /* in acl_pthread.c */ ACL_API int acl_pthread_atexit_add(void *arg, void (*free_callback)(void*)); @@ -194,9 +200,6 @@ ACL_API void acl_pthread_tls_once_set(acl_pthread_once_t control_once); ACL_API acl_pthread_key_t acl_pthread_tls_key_get(void); ACL_API void acl_pthread_tls_key_set(acl_pthread_key_t key); -/* in acl_pthread_cond.c */ -ACL_API acl_pthread_cond_t * acl_pthread_cond_create(void); - #ifdef __cplusplus } #endif diff --git a/lib_acl/samples/connect/main.cpp b/lib_acl/samples/connect/main.cpp index 825272d1a..61c0b0963 100644 --- a/lib_acl/samples/connect/main.cpp +++ b/lib_acl/samples/connect/main.cpp @@ -1,11 +1,12 @@ #include "lib_acl.h" +#include #include static void test(const char* addr) { std::list conns; - for (int i = 0; i < 10000; i++) + for (int i = 0; i < 1; i++) { ACL_VSTREAM* client = acl_vstream_connect(addr, ACL_BLOCKING, 10, 10, 4096); if (client == NULL) @@ -26,9 +27,35 @@ static void test(const char* addr) printf("Exit now ok\r\n"); } +static void get_name(void) +{ + const char *name = "localhost"; + struct addrinfo hints, *res, *res0; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ALL; + + int error = getaddrinfo(name, "8089", &hints, &res0); + if (error) { + printf("getaddrinfo error %s\r\n", acl_last_serror()); + return; + } + + for (res = res0; res; res = res->ai_next) { + printf("ai_family: %d, len: %d\r\n", + res->ai_family, (int) res->ai_addrlen); + } + + freeaddrinfo(res0); +} + int main(int argc, char *argv[]) { - test(argv[1]); + acl_msg_stdout_enable(1); + get_name(); + test(argc >= 2 ? argv[1] : "localhost:8809"); return 0; ACL_VSTREAM *client; diff --git a/lib_acl/samples/server/main.c b/lib_acl/samples/server/main.c index 8fd1bea36..7883a6b57 100644 --- a/lib_acl/samples/server/main.c +++ b/lib_acl/samples/server/main.c @@ -5,6 +5,7 @@ static void init(void) { acl_lib_init(); + acl_msg_stdout_enable(1); } static void end(void) @@ -26,13 +27,12 @@ static void thread_run(void *arg) } buf[ret] = 0; - printf("(%s)\n", buf); + (void) acl_vstream_write(client, buf, ret); acl_vstream_close(client); } -static void run(void) +static void run(const char *addr) { - const char *addr = "0.0.0.0:8089"; ACL_VSTREAM *sstream = acl_vstream_listen(addr, 128); acl_pthread_pool_t *pool; @@ -49,16 +49,21 @@ static void run(void) acl_msg_error("accept error(%s)", acl_last_serror()); break; } + printf("accept one client\r\n"); acl_pthread_pool_add(pool, thread_run, client); } acl_vstream_close(sstream); } -int main(int argc acl_unused, char *argv[] acl_unused) +int main(int argc, char *argv[]) { + const char *addr = "0:8809"; + + if (argc >= 2) + addr = argv[1]; init(); - run(); + run(addr); end(); return (0); } diff --git a/lib_acl/src/event/events_define.h b/lib_acl/src/event/events_define.h index e4945723b..8f46f2354 100644 --- a/lib_acl/src/event/events_define.h +++ b/lib_acl/src/event/events_define.h @@ -29,7 +29,7 @@ extern "C" { #elif defined(SUNOS5) # define ACL_EVENTS_KERNEL_STYLE ACL_EVENTS_STYLE_DEVPOLL # define USE_FDMAP -#elif defined(FREEBSD) || defined(MACOSX) +#elif defined(ACL_FREEBSD) || defined(ACL_MACOSX) # define ACL_EVENTS_KERNEL_STYLE ACL_EVENTS_STYLE_KQUEUE #else # undef ACL_EVENTS_KERNEL_STYLE diff --git a/lib_acl/src/net/acl_host_port.c b/lib_acl/src/net/acl_host_port.c index c7eb37f14..9e8cbdedc 100644 --- a/lib_acl/src/net/acl_host_port.c +++ b/lib_acl/src/net/acl_host_port.c @@ -32,7 +32,7 @@ const char *acl_host_port(char *buf, char **host, char *def_host, char **port, char *def_service) { - char *cp = buf; + char *cp = buf; /* * [host]:port, [host]:, [host]. @@ -49,17 +49,17 @@ const char *acl_host_port(char *buf, char **host, char *def_host, /* * host:port, host:, host, :port, port. */ - else { - if ((cp = acl_split_at_right(buf, ':')) != 0) { - *host = *buf ? buf : def_host; - *port = *cp ? cp : def_service; - } else { - *host = def_host ? def_host : (*buf ? buf : 0); - *port = def_service ? def_service : (*buf ? buf : 0); - } + else if ((cp = acl_split_at_right(buf, ':')) != 0) { + *host = *buf ? buf : def_host; + *port = *cp ? cp : def_service; + } else { + *host = def_host ? def_host : (*buf ? buf : 0); + *port = def_service ? def_service : (*buf ? buf : 0); } + if (*host == 0) return "missing host information"; + if (*port == 0) return "missing service information"; @@ -70,8 +70,12 @@ const char *acl_host_port(char *buf, char **host, char *def_host, if (*host != def_host && !acl_valid_hostname(*host, ACL_DONT_GRIPE) && !acl_valid_hostaddr(*host, ACL_DONT_GRIPE)) + { return "valid hostname or network address required"; + } + if (*port != def_service && ACL_ISDIGIT(**port) && !acl_alldig(*port)) return "garbage after numerical service"; + return NULL; } diff --git a/lib_acl/src/net/acl_sane_inet.c b/lib_acl/src/net/acl_sane_inet.c index 9d588b50c..2af5254ab 100644 --- a/lib_acl/src/net/acl_sane_inet.c +++ b/lib_acl/src/net/acl_sane_inet.c @@ -62,44 +62,53 @@ const char *acl_inet_ntoa(struct in_addr in, char *dst, size_t size) return (acl_inet_ntop4(src, dst, size)); } -int acl_is_ip(const char *pstrip) +int acl_is_ipv4(const char *ip) { const char *ptr; int count = 0, n = 0; char ch; - if (pstrip == NULL || *pstrip == 0) - return(-1); + if (ip == NULL || *ip == 0) + return 0; + + ptr = ip; + if(*ptr == '.') /* the first char should not be '.' */ + return 0; - ptr = pstrip; - if(*ptr == '.') { /* the first char should not be '.' */ - return(-1); - } while(*ptr) { if (*ptr == '.') { ch = *(ptr + 1); - if (ch < '0' || ch > '9') { - return(-1); - } + if (ch < '0' || ch > '9') + return 0; count++; } else { ch = *ptr; - if (ch < '0' || ch > '9') { - return(-1); - } + if (ch < '0' || ch > '9') + return 0; } ptr++; n++; if (n > 16) - return (-1); - } - if(*(ptr - 1) == '.') { /* the last char should not be '.' */ - return(-1); - } - if(count != 3) { /* 192.168.0.1 has the number '.' is 4 */ - return(-1); + return 0; } - return(0); + + if (*(ptr - 1) == '.') /* the last char should not be '.' */ + return 0; + if (count != 3) /* 192.168.0.1 has the number '.' is 4 */ + return 0; + + return 1; +} + +int acl_is_ipv6(const char *ip) +{ + /* xxx: ? */ + return !acl_is_ipv4(ip); +} + +int acl_is_ip(const char *ip) +{ + return (acl_is_ipv4(ip) || acl_is_ipv6(ip)) ? 0 : -1; } int acl_ipv4_valid(const char *addr) @@ -108,60 +117,60 @@ int acl_ipv4_valid(const char *addr) int n, k; if (addr == NULL || *addr == 0) - return (0); + return 0; k = 3; while (*ptr && *ptr != '.') { n = *ptr; if (n < '0' || n > '9') - return (0); + return 0; ptr++; k--; if (k < 0) - return (0); + return 0; } if (*ptr == 0) - return (0); + return 0; k = 3; ptr++; while (*ptr && *ptr != '.') { n = *ptr; if (n < '0' || n > '9') - return (0); + return 0; ptr++; k--; if (k < 0) - return (0); + return 0; } if (*ptr == 0) - return (0); + return 0; k = 3; ptr++; while (*ptr && *ptr != '.') { n = *ptr; if (n < '0' || n > '9') - return (0); + return 0; ptr++; k--; if (k < 0) - return (0); + return 0; } if (*ptr == 0) - return (0); + return 0; k = 3; ptr++; while (*ptr) { n = *ptr; if (n < '0' || n > '9') - return (0); + return 0; ptr++; k--; if (k < 0) - return (0); + return 0; } - return (1); + return 1; } int acl_ipv4_addr_valid(const char *addr) diff --git a/lib_acl/src/net/acl_valid_hostname.c b/lib_acl/src/net/acl_valid_hostname.c index 7eaf72389..fe79072cf 100644 --- a/lib_acl/src/net/acl_valid_hostname.c +++ b/lib_acl/src/net/acl_valid_hostname.c @@ -34,7 +34,7 @@ int acl_valid_hostname(const char *name, int gripe) if (*name == 0) { if (gripe) acl_msg_warn("%s: empty hostname", myname); - return (0); + return 0; } /* @@ -50,7 +50,7 @@ int acl_valid_hostname(const char *name, int gripe) acl_msg_warn("%s: hostname label" " too long: %.100s", myname, name); - return (0); + return 0; } if (!ACL_ISDIGIT(ch)) non_numeric = 1; @@ -59,7 +59,7 @@ int acl_valid_hostname(const char *name, int gripe) if (gripe) acl_msg_warn("%s: misplaced delimiter:" " %.100s", myname, name); - return (0); + return 0; } label_length = 0; } else if (ch == '-') { @@ -68,7 +68,7 @@ int acl_valid_hostname(const char *name, int gripe) if (gripe) acl_msg_warn("%s: misplaced hyphen:" " %.100s", myname, name); - return (0); + return 0; } } #ifdef SLOPPY_VALID_HOSTNAME @@ -81,7 +81,7 @@ int acl_valid_hostname(const char *name, int gripe) if (gripe) acl_msg_warn("%s: invalid character %d(decimal): %.100s", myname, ch, name); - return (0); + return 0; } } @@ -89,16 +89,16 @@ int acl_valid_hostname(const char *name, int gripe) if (gripe) acl_msg_warn("%s: numeric hostname: %.100s", myname, name); #ifndef SLOPPY_VALID_HOSTNAME - return (0); + return 0; #endif } if (cp - name > ACL_VALID_HOSTNAME_LEN) { if (gripe) acl_msg_warn("%s: bad length %d for %.100s...", myname, (int) (cp - name), name); - return (0); + return 0; } - return (1); + return 1; } /* acl_valid_hostaddr - verify numerical address syntax */ @@ -113,16 +113,16 @@ int acl_valid_hostaddr(const char *addr, int gripe) if (*addr == 0) { if (gripe) acl_msg_warn("%s: empty address", myname); - return (0); + return 0; } /* * Protocol-dependent processing next. */ if (strchr(addr, ':') != 0) - return (acl_valid_ipv6_hostaddr(addr, gripe)); + return acl_valid_ipv6_hostaddr(addr, gripe); else - return (acl_valid_ipv4_hostaddr(addr, gripe)); + return acl_valid_ipv4_hostaddr(addr, gripe); } /* acl_valid_ipv4_hostaddr - test dotted quad string for correctness */ @@ -157,14 +157,14 @@ int acl_valid_ipv4_hostaddr(const char *addr, int gripe) if (gripe) acl_msg_warn("%s: invalid octet value:" " %.100s", myname, addr); - return (0); + return 0; } } else if (ch == '.') { if (in_byte == 0 || cp[1] == 0) { if (gripe) acl_msg_warn("%s: misplaced dot:" " %.100s", myname, addr); - return (0); + return 0; } /* XXX Allow 0.0.0.0 but not 0.1.2.3 */ if (byte_count == 1 && byte_val == 0 @@ -172,24 +172,25 @@ int acl_valid_ipv4_hostaddr(const char *addr, int gripe) if (gripe) acl_msg_warn("%s: bad initial octet" " value: %.100s", myname, addr); - return (0); + return 0; } in_byte = 0; } else { if (gripe) acl_msg_warn("%s: invalid character %d(decimal): %.100s", myname, ch, addr); - return (0); + return 0; } } - if (byte_count != BYTES_NEEDED) { + if (byte_count != BYTES_NEEDED && strcmp(addr, "0") != 0) { if (gripe) acl_msg_warn("%s: invalid octet count: %.100s", myname, addr); - return (0); + return 0; } - return (1); + + return 1; } /* acl_valid_ipv6_hostaddr - validate IPv6 address syntax */ @@ -224,15 +225,15 @@ int acl_valid_ipv6_hostaddr(const char *addr, int gripe) acl_msg_warn("%s: too few `:' in IPv6" " address: %.100s", myname, addr); - return (0); + return 0; } else if (len == 0 && null_field != field - 1) { if (gripe) acl_msg_warn("%s: bad null last field" " in IPv6 address: %.100s", myname, addr); - return (0); + return 0; } else - return (1); + return 1; case '.': /* Terminate the loop. */ if (field < 2 || field > 6) { @@ -240,10 +241,10 @@ int acl_valid_ipv6_hostaddr(const char *addr, int gripe) acl_msg_warn("%s: malformed IPv4-in-IPv6" " address: %.100s", myname, addr); - return (0); + return 0; } /* NOT: acl_valid_hostaddr(). Avoid recursion. */ - return (acl_valid_ipv4_hostaddr((const char *) cp - len, gripe)); + return acl_valid_ipv4_hostaddr((const char *) cp - len, gripe); case ':': /* advance by exactly 1 character position or terminate. */ if (field == 0 && len == 0 && ACL_ISALNUM(cp[1])) { @@ -251,7 +252,7 @@ int acl_valid_ipv6_hostaddr(const char *addr, int gripe) acl_msg_warn("%s: bad null first field" " in IPv6 address: %.100s", myname, addr); - return (0); + return 0; } field++; if (field > 7) { @@ -259,7 +260,7 @@ int acl_valid_ipv6_hostaddr(const char *addr, int gripe) acl_msg_warn("%s: too many `:' in" " IPv6 address: %.100s", myname, addr); - return (0); + return 0; } cp++; len = 0; @@ -269,7 +270,7 @@ int acl_valid_ipv6_hostaddr(const char *addr, int gripe) acl_msg_warn("%s: too many `::'" " in IPv6 address: %.100s", myname, addr); - return (0); + return 0; } null_field = field; } @@ -281,14 +282,14 @@ int acl_valid_ipv6_hostaddr(const char *addr, int gripe) if (gripe) acl_msg_warn("%s: malformed IPv6 address: %.100s", myname, addr); - return (0); + return 0; } if (len <= 0) { if (gripe) acl_msg_warn("%s: invalid character" " %d(decimal) in IPv6 address: %.100s", myname, *cp, addr); - return (0); + return 0; } cp += len; break; diff --git a/lib_acl/src/net/connect/acl_inet_connect.c b/lib_acl/src/net/connect/acl_inet_connect.c index d4c118e4a..92c251f2d 100644 --- a/lib_acl/src/net/connect/acl_inet_connect.c +++ b/lib_acl/src/net/connect/acl_inet_connect.c @@ -33,107 +33,31 @@ #endif -static ACL_SOCKET inet_connect_one(const char *ip, int port, - const char *local_ip, int b_mode, int timeout); - -/* acl_inet_connect - connect to TCP listener */ - -ACL_SOCKET acl_inet_connect(const char *addr, int block_mode, int timeout) -{ - int h_error = 0; - - return (acl_inet_connect_ex(addr, block_mode, timeout, &h_error)); -} - -ACL_SOCKET acl_inet_connect_ex(const char *addr, int b_mode, - int timeout, int *h_error) +static int bind_local(ACL_SOCKET sock, int family, const struct addrinfo *res0) { - const char *myname = "acl_inet_connect_ex"; - ACL_SOCKET sock = ACL_SOCKET_INVALID; - char buf[256], *ptr; - const char *ip, *remote, *local_ip; - int port, i, n; - ACL_DNS_DB *h_dns_db; - - if (h_error) - *h_error = 0; + const struct addrinfo *res; - snprintf(buf, sizeof(buf) - 1, "%s", addr); - ptr = strchr(buf, ':'); - if (ptr == NULL) { - acl_msg_error("%s, %s(%d): invalid addr(%s)", - __FILE__, myname, __LINE__, addr); - return (ACL_SOCKET_INVALID); - } - - *ptr++ = 0; - port = atoi(ptr); - if (port <= 0) { - acl_msg_error("%s, %s(%d): invalid port(%d)", - __FILE__, myname, __LINE__, port); - return (ACL_SOCKET_INVALID); - } + for (res = res0; res != NULL; res = res->ai_next) { + if (res->ai_family != family) + continue; - ptr = strchr(buf, '@'); - if (ptr != NULL) { - *ptr++ = 0; - local_ip = buf; - remote = ptr; - } else { - local_ip = NULL; - remote = buf; - } - - if (strlen(remote) == 0) { - acl_msg_error("%s, %s(%d): ip buf's length is 0", - __FILE__, myname, __LINE__); - return (ACL_SOCKET_INVALID); + if (bind(sock, res->ai_addr, res->ai_addrlen) == 0) + return 0; } - h_dns_db = acl_gethostbyname(remote, h_error); - if (h_dns_db == NULL) { - n = h_error ? *h_error : -1; - - acl_msg_error("%s, %s(%d): gethostbyname error(%s), addr=%s", - __FILE__, myname, __LINE__, - acl_netdb_strerror(n), remote); - return (ACL_SOCKET_INVALID); - } - - sock = ACL_SOCKET_INVALID; - n = acl_netdb_size(h_dns_db); - - for (i = 0; i < n; i++) { - ip = acl_netdb_index_ip(h_dns_db, i); - if (ip == NULL) - break; - - sock = inet_connect_one(ip, port, local_ip, b_mode, timeout); - if (sock != ACL_SOCKET_INVALID) - break; - acl_msg_error("%s(%d): connect error: %s, addr: %s:%d, fd: %d", - myname, __LINE__, acl_last_serror(), ip, port, sock); - } - - acl_netdb_free(h_dns_db); - - return (sock); + return -1; } /* inet_connect_one - try to connect to one address */ -static ACL_SOCKET inet_connect_one(const char *ip, int port, - const char *local_ip, int b_mode, int timeout) +static ACL_SOCKET inet_connect_one(const struct addrinfo *peer, + const struct addrinfo *local0, int blocking, int timeout) { const char *myname = "inet_connect_one"; - ACL_SOCKET sock; - struct sockaddr_in saddr; + ACL_SOCKET sock; + + sock = socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); - /* - * Create a client socket. - */ - /* sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); */ - sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == ACL_SOCKET_INVALID) { acl_msg_error("%s(%d): create socket error: %s", myname, __LINE__, acl_last_serror()); @@ -143,56 +67,43 @@ static ACL_SOCKET inet_connect_one(const char *ip, int port, acl_tcp_set_rcvbuf(sock, ACL_SOCKET_RBUF_SIZE); acl_tcp_set_sndbuf(sock, ACL_SOCKET_WBUF_SIZE); - if (local_ip != NULL && *local_ip != 0) { - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = inet_addr(local_ip); - if (bind(sock, (struct sockaddr *) &saddr, - sizeof(struct sockaddr)) < 0) - { - acl_socket_close(sock); - acl_msg_error("%s(%d): bind ip(%s) error: %s, fd: %d", - myname, __LINE__, local_ip, - acl_last_serror(), sock); - return ACL_SOCKET_INVALID; - } + if (local0 != NULL && bind_local(sock, peer->ai_family, local0) < 0) + { + acl_msg_error("%s(%d): bind local error %s, fd=%d", + myname, __LINE__, acl_last_serror(), sock); + acl_socket_close(sock); + return ACL_SOCKET_INVALID; } - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = htons((short) port); - saddr.sin_addr.s_addr = inet_addr(ip); - /* * Timed connect. */ if (timeout > 0) { acl_non_blocking(sock, ACL_NON_BLOCKING); - if (acl_timed_connect(sock, (const struct sockaddr *) &saddr, - sizeof(struct sockaddr), timeout) < 0) + if (acl_timed_connect(sock, peer->ai_addr, + peer->ai_addrlen, timeout) < 0) { acl_socket_close(sock); - return (ACL_SOCKET_INVALID); + return ACL_SOCKET_INVALID; } - if (b_mode != ACL_NON_BLOCKING) - acl_non_blocking(sock, b_mode); + if (blocking != ACL_NON_BLOCKING) + acl_non_blocking(sock, blocking); return sock; } /* * Maybe block until connected. */ - acl_non_blocking(sock, b_mode); - if (acl_sane_connect(sock, (const struct sockaddr *) &saddr, - sizeof(saddr)) < 0) - { - int ret, err, errnum; + acl_non_blocking(sock, blocking); + if (acl_sane_connect(sock, peer->ai_addr, peer->ai_addrlen) < 0) { + int err, errnum; socklen_t len; errnum = acl_last_error(); len = sizeof(err); - ret = getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len); - if (ret < 0) { + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, + (char *) &err, &len) < 0) + { #ifdef SUNOS5 /* * Solaris 2.4's socket emulation doesn't allow you @@ -220,5 +131,105 @@ static ACL_SOCKET inet_connect_one(const char *ip, int port, acl_socket_close(sock); return ACL_SOCKET_INVALID; } + + return sock; +} + +/* acl_inet_connect - connect to TCP listener */ + +ACL_SOCKET acl_inet_connect(const char *addr, int blocking, int timeout) +{ + int h_error = 0; + return acl_inet_connect_ex(addr, blocking, timeout, &h_error); +} + +ACL_SOCKET acl_inet_connect_ex(const char *addr, int blocking, + int timeout, int *h_error) +{ + const char *myname = "acl_inet_connect_ex"; + int err; + ACL_SOCKET sock; + char buf[256], *ptr; + const char *peer, *local, *port; + struct addrinfo hints, *peer_res0, *res, *local_res0; + + if (h_error) + *h_error = 0; + + snprintf(buf, sizeof(buf) - 1, "%s", addr); + ptr = strrchr(buf, ':'); + if (ptr == NULL) { + acl_msg_error("%s, %s(%d): invalid addr(%s)", + __FILE__, myname, __LINE__, addr); + return ACL_SOCKET_INVALID; + } + + *ptr++ = 0; + port = ptr; + if (atoi(port) <= 0) { + acl_msg_error("%s, %s(%d): invalid port(%s)", + __FILE__, myname, __LINE__, port); + return ACL_SOCKET_INVALID; + } + + ptr = strchr(buf, '@'); + if (ptr != NULL) { + *ptr++ = 0; + local = buf; + peer = ptr; + } else { + local = NULL; + peer = buf; + } + + if (strlen(peer) == 0) { + acl_msg_error("%s, %s(%d): ip buf's length is 0", + __FILE__, myname, __LINE__); + return ACL_SOCKET_INVALID; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; +#ifdef ACL_MACOSX + hints.ai_flags = AI_DEFAULT; +#elif defined(ACL_ANDROID) + hints.ai_flags = AI_ADDRCONFIG; +#else + hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; +#endif + + if ((err = getaddrinfo(peer, port, &hints, &peer_res0))) { + acl_msg_error("%s(%d), %s: getaddrinfo error %s, peer=%s", + __FILE__, __LINE__, myname, gai_strerror(err), peer); + return ACL_SOCKET_INVALID; + } + + if (local == NULL) + local_res0 = NULL; + else if ((err = getaddrinfo(local, "0", &hints, &local_res0))) { + acl_msg_error("%s(%d), %s: getaddrinfo error %s, local=%s", + __FILE__, __LINE__, myname, gai_strerror(err), local); + return ACL_SOCKET_INVALID; + } + + sock = ACL_SOCKET_INVALID; + + for (res = peer_res0; res != NULL ; res = res->ai_next) { + sock = inet_connect_one(res, local_res0, blocking, timeout); + if (sock != ACL_SOCKET_INVALID) + break; + } + + if (sock == ACL_SOCKET_INVALID) + acl_msg_error("%s(%d) %s: connect error %s, addr=%s:%s", + __FILE__, __LINE__, myname, + acl_last_serror(), peer, port); + + if (peer_res0) + freeaddrinfo(peer_res0); + if (local_res0) + freeaddrinfo(local_res0); + return sock; } diff --git a/lib_acl/src/net/connect/acl_sane_connect.c b/lib_acl/src/net/connect/acl_sane_connect.c index 94110989a..95547cccd 100644 --- a/lib_acl/src/net/connect/acl_sane_connect.c +++ b/lib_acl/src/net/connect/acl_sane_connect.c @@ -23,7 +23,7 @@ /* acl_sane_connect - sanitize connect() results */ -int acl_sane_connect(ACL_SOCKET sock, const struct sockaddr * sa, socklen_t len) +int acl_sane_connect(ACL_SOCKET sock, const struct sockaddr *sa, socklen_t len) { int on; @@ -35,7 +35,11 @@ int acl_sane_connect(ACL_SOCKET sock, const struct sockaddr * sa, socklen_t len) * the Postfix watchdog timer. */ +#ifdef AF_INET6 + if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) { +#else if (sa->sa_family == AF_INET) { +#endif /* default set to nodelay --- zsx, 2008.9.4*/ acl_tcp_nodelay(sock, 1); #if defined(BROKEN_READ_SELECT_ON_TCP_SOCKET) && defined(SO_KEEPALIVE) @@ -47,13 +51,13 @@ int acl_sane_connect(ACL_SOCKET sock, const struct sockaddr * sa, socklen_t len) on = 1; +#ifdef SO_REUSEADDR if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) { acl_msg_error("acl_sane_connect: setsockopt error(%s)", acl_last_serror()); } - +#endif return connect(sock, sa, len); } - diff --git a/lib_acl/src/net/connect/acl_timed_connect.c b/lib_acl/src/net/connect/acl_timed_connect.c index 1b7bff301..d7cff9185 100644 --- a/lib_acl/src/net/connect/acl_timed_connect.c +++ b/lib_acl/src/net/connect/acl_timed_connect.c @@ -37,16 +37,16 @@ int acl_timed_connect(ACL_SOCKET sock, const struct sockaddr * sa, * Start the connection, and handle all possible results. */ if (acl_sane_connect(sock, sa, len) == 0) - return (0); + return 0; errno = acl_last_error(); #ifdef ACL_UNIX if (errno != ACL_EINPROGRESS) - return (-1); + return -1; #elif defined(ACL_WINDOWS) if (errno != ACL_EINPROGRESS && errno != ACL_EWOULDBLOCK) - return (-1); + return -1; #endif /* @@ -54,7 +54,7 @@ int acl_timed_connect(ACL_SOCKET sock, const struct sockaddr * sa, * something to happen. If nothing happens, report an error. */ if (acl_write_wait(sock, timeout) < 0) - return (-1); + return -1; /* * Something happened. Some Solaris 2 versions have getsockopt() itself @@ -72,12 +72,12 @@ int acl_timed_connect(ACL_SOCKET sock, const struct sockaddr * sa, if (errno == EPIPE) acl_set_error(ACL_ENOTCONN); #endif - return (-1); + return -1; } if (err != 0) { acl_set_error(err); - return (-1); + return -1; } else - return (0); + return 0; } diff --git a/lib_acl/src/net/ipv6_patch.h b/lib_acl/src/net/ipv6_patch.h new file mode 100644 index 000000000..32e02fe6a --- /dev/null +++ b/lib_acl/src/net/ipv6_patch.h @@ -0,0 +1,24 @@ +#ifndef ACL_IPV6_PATCH_INCLUDE_H +#define ACL_IPV6_PATCH_INCLUDE_H + +#if 1 +#if defined(AF_INET6) +# define ACL_IPV6 +#endif +#endif + +#if defined(ACL_IPV6) +# define ACL_AF_INET AF_INET6 +# define acl_sockaddr_in sockaddr_in6 +# define acl_sin_family sin6_family +# define acl_sin_addr sin6_addr +# define acl_sin_port sin6_port +#else +# define ACL_AF_INET AF_INET +# define acl_sockaddr_in sockaddr_in +# define acl_sin_family sin_family +# define acl_sin_addr sin_addr +# define acl_sin_port sin_port +#endif + +#endif diff --git a/lib_acl/src/net/listen/acl_inet_listen.c b/lib_acl/src/net/listen/acl_inet_listen.c index 52f623a81..a08daef95 100644 --- a/lib_acl/src/net/listen/acl_inet_listen.c +++ b/lib_acl/src/net/listen/acl_inet_listen.c @@ -33,55 +33,14 @@ #endif -/* acl_inet_listen - create TCP listener */ - -ACL_SOCKET acl_inet_listen(const char *addr, int backlog, int block_mode) +static ACL_SOCKET inet_listen(const char *addr, const struct addrinfo *res, + int backlog, int blocking) { - const char *myname = "acl_inet_listen"; + const char *myname = "inet_listen"; ACL_SOCKET sock; - int on, nport; - char *buf, *host = NULL, *sport = NULL; - const char *ptr; - struct sockaddr_in sa; - - /* - * Translate address information to internal form. - */ - buf = acl_mystrdup(addr); - ptr = acl_host_port(buf, &host, "", &sport, (char *) 0); - if (ptr) { - acl_msg_error("%s(%d): %s, %s invalid", myname, __LINE__, addr, ptr); - acl_myfree(buf); - return ACL_SOCKET_INVALID; - } - - if (host && *host == 0) - host = 0; - if (host == NULL) - host = "0.0.0.0"; - - if (sport == NULL) { - acl_msg_error("%s(%d): no port given from addr(%s)", myname, __LINE__, addr); - acl_myfree(buf); - return ACL_SOCKET_INVALID; - } - nport = atoi(sport); - if (nport < 0) { - acl_msg_error("%s: port(%d) < 0 invalid from addr(%s)", - myname, nport, addr); - acl_myfree(buf); - return ACL_SOCKET_INVALID; - } - - memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons((short) nport); - sa.sin_addr.s_addr = inet_addr(host); - - acl_myfree(buf); + int on; - /* Create a listener socket. */ - sock = socket(AF_INET, SOCK_STREAM, 0); + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock == ACL_SOCKET_INVALID) { acl_msg_error("%s: socket %s", myname, acl_last_serror()); return ACL_SOCKET_INVALID; @@ -91,7 +50,7 @@ ACL_SOCKET acl_inet_listen(const char *addr, int backlog, int block_mode) if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &on, sizeof(on)) < 0) { - acl_msg_error("%s: setsockopt(SO_REUSEADDR): %s", + acl_msg_warn("%s: setsockopt(SO_REUSEADDR): %s", myname, acl_last_serror()); } @@ -100,7 +59,7 @@ ACL_SOCKET acl_inet_listen(const char *addr, int backlog, int block_mode) if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const void *) &on, sizeof(on)) < 0) { - acl_msg_error("%s: setsocket(SO_REUSEPORT): %s", + acl_msg_warn("%s: setsocket(SO_REUSEPORT): %s", myname, acl_last_serror()); } #endif @@ -110,22 +69,22 @@ ACL_SOCKET acl_inet_listen(const char *addr, int backlog, int block_mode) if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, (const void *) &on, sizeof(on)) < 0) { - acl_msg_error("%s: setsocket(TCP_FASTOPEN): %s", + acl_msg_warn("%s: setsocket(TCP_FASTOPEN): %s", myname, acl_last_serror()); } #endif - if (bind(sock, (struct sockaddr *) &sa, sizeof(struct sockaddr)) < 0) { - acl_msg_error("%s: bind %s error %s", - myname, addr, acl_last_serror()); + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { + acl_msg_error("%s: bind %s error %s, addr=%s", + myname, addr, acl_last_serror(), addr); acl_socket_close(sock); return ACL_SOCKET_INVALID; } - acl_non_blocking(sock, block_mode); + acl_non_blocking(sock, blocking); if (listen(sock, backlog) < 0) { - acl_msg_error("%s: listen error: %s, addr(%s)", + acl_msg_error("%s: listen error: %s, addr=%s", myname, acl_last_serror(), addr); acl_socket_close(sock); return ACL_SOCKET_INVALID; @@ -134,6 +93,80 @@ ACL_SOCKET acl_inet_listen(const char *addr, int backlog, int block_mode) return sock; } +/* acl_inet_listen - create TCP listener */ + +ACL_SOCKET acl_inet_listen(const char *addr, int backlog, int blocking) +{ + const char *myname = "acl_inet_listen"; + char *buf, *host = NULL, *port = NULL; + const char *ptr; + struct addrinfo hints, *res0, *res; + ACL_SOCKET sock; + int err; + + /* + * Translate address information to internal form. + */ + buf = acl_mystrdup(addr); + ptr = acl_host_port(buf, &host, "", &port, (char *) 0); + if (ptr) { + acl_msg_error("%s(%d): %s, %s invalid", + myname, __LINE__, addr, ptr); + acl_myfree(buf); + return ACL_SOCKET_INVALID; + } + + if (host && *host == 0) + host = 0; + if (host == NULL) + host = "0"; + + if (port == NULL) { + acl_msg_error("%s(%d): no port given from addr(%s)", + myname, __LINE__, addr); + acl_myfree(buf); + return ACL_SOCKET_INVALID; + } else if (atoi(port) < 0) { + acl_msg_error("%s: port(%s) < 0 invalid from addr(%s)", + myname, port, addr); + acl_myfree(buf); + return ACL_SOCKET_INVALID; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; +#ifdef ACL_MACOSX + hints.ai_flags = AI_DEFAULT; +#elif defined(ACL_ANDROID) + hints.ai_flags = AI_ADDRCONFIG; +#else + hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; +#endif + + if ((err = getaddrinfo(host, port, &hints, &res0))) { + acl_msg_error("%s(%d), %s: getaddrinfo error %s, host=%s", + __FILE__, __LINE__, myname, gai_strerror(err), host); + acl_myfree(buf); + return ACL_SOCKET_INVALID; + } + + acl_myfree(buf); + + sock = ACL_SOCKET_INVALID; + + for (res = res0; res != NULL; res = res->ai_next) { + sock = inet_listen(addr, res, backlog, blocking); + if (sock != ACL_SOCKET_INVALID) + break; + } + + if (res0) + freeaddrinfo(res0); + + return sock; +} + ACL_SOCKET acl_inet_accept(ACL_SOCKET listen_fd) { return acl_inet_accept_ex(listen_fd, NULL, 0); @@ -141,19 +174,19 @@ ACL_SOCKET acl_inet_accept(ACL_SOCKET listen_fd) ACL_SOCKET acl_inet_accept_ex(ACL_SOCKET listen_fd, char *ipbuf, size_t size) { - struct sockaddr_in client_addr; - socklen_t addr_len; + struct sockaddr_storage sa; + socklen_t len = sizeof(sa); ACL_SOCKET fd; - memset(&client_addr, 0, sizeof(client_addr)); - addr_len = sizeof(client_addr); + memset(&sa, 0, sizeof(sa)); /* when client_addr not null and protocol is AF_INET, acl_sane_accept * will set nodelay on the accepted socket, 2008.9.4, zsx */ - fd = acl_sane_accept(listen_fd, (struct sockaddr *)&client_addr, &addr_len); + fd = acl_sane_accept(listen_fd, (struct sockaddr *)&sa, &len); if (fd == ACL_SOCKET_INVALID) return fd; + if (ipbuf != NULL && size > 0 && acl_getpeername(fd, ipbuf, size) < 0) ipbuf[0] = 0; diff --git a/lib_acl/src/stdlib/acl_atomic.c b/lib_acl/src/stdlib/acl_atomic.c index 58fd41610..7a2e1fd8b 100644 --- a/lib_acl/src/stdlib/acl_atomic.c +++ b/lib_acl/src/stdlib/acl_atomic.c @@ -38,8 +38,8 @@ void acl_atomic_free(ACL_ATOMIC *self) self->value = NULL; #ifndef HAS_ATOMIC acl_pthread_mutex_destroy(&self->lock); - acl_myfree(self); #endif + acl_myfree(self); } void acl_atomic_set(ACL_ATOMIC *self, void *value) diff --git a/lib_acl/src/stdlib/acl_mbox.c b/lib_acl/src/stdlib/acl_mbox.c index 5b362be78..708128042 100644 --- a/lib_acl/src/stdlib/acl_mbox.c +++ b/lib_acl/src/stdlib/acl_mbox.c @@ -45,7 +45,7 @@ ACL_MBOX *acl_mbox_create(void) mbox->nsend = 0; mbox->nread = 0; mbox->ypipe = acl_ypipe_new(); - mbox->lock = acl_pthread_mutex_create(); + mbox->lock = acl_thread_mutex_create(); return mbox; } @@ -56,6 +56,7 @@ void acl_mbox_free(ACL_MBOX *mbox, void (*free_fn)(void*)) acl_vstream_close(mbox->out); acl_ypipe_free(mbox->ypipe, free_fn); acl_pthread_mutex_destroy(mbox->lock); + acl_myfree(mbox->lock); acl_myfree(mbox); } @@ -89,7 +90,7 @@ void *acl_mbox_read(ACL_MBOX *mbox, int timeout, int *success) if (msg != NULL) { if (success) - *success = 0; + *success = 1; return msg; } @@ -100,12 +101,12 @@ void *acl_mbox_read(ACL_MBOX *mbox, int timeout, int *success) if (ret == ACL_VSTREAM_EOF) { if (mbox->in->errnum == ACL_ETIMEDOUT) { if (success) - *success = 0; + *success = 1; return NULL; } if (success) - *success = -1; + *success = 0; return NULL; } @@ -113,12 +114,12 @@ void *acl_mbox_read(ACL_MBOX *mbox, int timeout, int *success) acl_msg_error("%s(%d), %s: read invalid: %c", __FILE__, __LINE__, __FUNCTION__, kbuf[0]); if (success) - *success = -1; + *success = 0; return NULL; } if (success) - *success = 0; + *success = 1; return acl_ypipe_read(mbox->ypipe); } diff --git a/lib_acl/src/stdlib/common/acl_yqueue.c b/lib_acl/src/stdlib/common/acl_yqueue.c index 7c1bac851..90f7dec25 100644 --- a/lib_acl/src/stdlib/common/acl_yqueue.c +++ b/lib_acl/src/stdlib/common/acl_yqueue.c @@ -99,6 +99,7 @@ void acl_yqueue_free(ACL_YQUEUE *self, void(*free_fn)(void*)) if (cs) acl_myfree(cs); + acl_atomic_free(self->spare_chunk); acl_myfree(self); } diff --git a/lib_acl/src/stdlib/iostuff/acl_write_wait.c b/lib_acl/src/stdlib/iostuff/acl_write_wait.c index 401b15746..dd479e4d8 100644 --- a/lib_acl/src/stdlib/iostuff/acl_write_wait.c +++ b/lib_acl/src/stdlib/iostuff/acl_write_wait.c @@ -52,11 +52,14 @@ int acl_write_wait(ACL_SOCKET fd, int timeout) return -1; default: if ((fds.revents & (POLLHUP | POLLERR))) { + /* acl_msg_error("%s(%d), %s: fd: %d," "POLLHUP: %s, POLLERR: %s", __FILE__, __LINE__, myname, fd, fds.revents & POLLHUP ? "yes" : "no", fds.revents & POLLERR ? "yes" : "no"); + */ + errno = ECONNREFUSED; return -1; } if (fds.revents & POLLOUT) diff --git a/lib_acl/src/stdlib/sys/acl_sys_socket.c b/lib_acl/src/stdlib/sys/acl_sys_socket.c index cf67c41a9..ae76959e1 100644 --- a/lib_acl/src/stdlib/sys/acl_sys_socket.c +++ b/lib_acl/src/stdlib/sys/acl_sys_socket.c @@ -321,3 +321,8 @@ int acl_socket_writev(ACL_SOCKET fd, const struct iovec *vec, int count, #else # error "unknown OS type" #endif + +int acl_socket_shutdown(ACL_SOCKET fd, int how) +{ + return shutdown(fd, how); +} diff --git a/lib_acl/src/thread/acl_pthread_cond.c b/lib_acl/src/thread/acl_pthread_cond.c index 8a0a0c369..fb29b4b14 100644 --- a/lib_acl/src/thread/acl_pthread_cond.c +++ b/lib_acl/src/thread/acl_pthread_cond.c @@ -22,16 +22,13 @@ int acl_pthread_cond_init(acl_pthread_cond_t *cond, { const char *myname = "acl_pthread_cond_init"; - if (cond == NULL) { - acl_msg_error("%s, %s(%d): input invalid", + if (cond == NULL) + acl_msg_fatal("%s, %s(%d): input invalid", __FILE__, myname, __LINE__); - return -1; - } - - cond_attr = cond_attr; + (void) cond_attr; cond->dynamic = 0; - cond->lock = acl_pthread_mutex_create(); + cond->lock = acl_thread_mutex_create(); cond->wait_sem = acl_sem_create(0); cond->wait_done = acl_sem_create(0); cond->waiting = cond->signals = 0; @@ -42,9 +39,9 @@ int acl_pthread_cond_init(acl_pthread_cond_t *cond, } /* Create a condition variable */ -acl_pthread_cond_t * acl_pthread_cond_create(void) +acl_pthread_cond_t * acl_thread_cond_create(void) { - const char *myname = "acl_pthread_cond_create"; + const char *myname = "acl_thread_cond_create"; acl_pthread_cond_t *cond; cond = (acl_pthread_cond_t *) @@ -75,8 +72,10 @@ int acl_pthread_cond_destroy(acl_pthread_cond_t *cond) acl_sem_destroy(cond->wait_sem); if (cond->wait_done) acl_sem_destroy(cond->wait_done); - if ( cond->lock ) + if (cond->lock) { acl_pthread_mutex_destroy(cond->lock); + acl_myfree(cond->lock); + } if (cond->dynamic) acl_myfree(cond); @@ -237,4 +236,4 @@ int acl_pthread_cond_wait(acl_pthread_cond_t *cond, acl_pthread_mutex_t *mutex) return acl_pthread_cond_timedwait(cond, mutex, NULL); } -#endif /* ACL_HAS_PTHREAD */ +#endif /* !ACL_HAS_PTHREAD */ diff --git a/lib_acl/src/thread/acl_pthread_mutex.c b/lib_acl/src/thread/acl_pthread_mutex.c index 53361cdd0..247b8ce49 100644 --- a/lib_acl/src/thread/acl_pthread_mutex.c +++ b/lib_acl/src/thread/acl_pthread_mutex.c @@ -13,7 +13,6 @@ #include "stdlib/acl_mymalloc.h" #include "stdlib/acl_msg.h" #include "thread/acl_pthread.h" - #endif #ifdef ACL_WINDOWS @@ -43,9 +42,9 @@ int acl_pthread_mutex_init(acl_pthread_mutex_t *mutex, return 0; } -acl_pthread_mutex_t *acl_pthread_mutex_create(void) +acl_pthread_mutex_t *acl_thread_mutex_create(void) { - const char *myname = "acl_pthread_mutex_create"; + const char *myname = "acl_thread_mutex_create"; acl_pthread_mutex_t *mutex; mutex = acl_mycalloc(1, sizeof(acl_pthread_mutex_t)); @@ -126,9 +125,9 @@ int acl_pthread_mutex_unlock(acl_pthread_mutex_t *mutex) #include -acl_pthread_mutex_t *acl_pthread_mutex_create(void) +acl_pthread_mutex_t *acl_thread_mutex_create(void) { - const char *myname = "acl_pthread_mutex_create"; + const char *myname = "acl_thread_mutex_create"; acl_pthread_mutex_t *mutex; int status; @@ -148,6 +147,11 @@ acl_pthread_mutex_t *acl_pthread_mutex_create(void) return mutex; } +int acl_pthread_mutex_destroy(acl_pthread_mutex_t *mutex) +{ + return pthread_mutex_destroy(mutex); +} + #endif /* ACL_WINDOWS/ACL_UNIX */ typedef struct acl_pthread_nested_mutex_t acl_pthread_nested_mutex_t; diff --git a/lib_acl_cpp/acl_cpp.xcodeproj/project.pbxproj b/lib_acl_cpp/acl_cpp.xcodeproj/project.pbxproj index 130c33a83..fb16eb245 100644 --- a/lib_acl_cpp/acl_cpp.xcodeproj/project.pbxproj +++ b/lib_acl_cpp/acl_cpp.xcodeproj/project.pbxproj @@ -190,6 +190,7 @@ 07A468731E6FCCF1002C9B3C /* stdin_stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A467BD1E6FCCF1002C9B3C /* stdin_stream.cpp */; }; 07A468741E6FCCF1002C9B3C /* stdout_stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A467BE1E6FCCF1002C9B3C /* stdout_stream.cpp */; }; 07A468751E6FCCF1002C9B3C /* stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A467BF1E6FCCF1002C9B3C /* stream.cpp */; }; + 07A4D1731E94E4BC00790E12 /* mbox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A4D1721E94E4BC00790E12 /* mbox.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -593,6 +594,8 @@ 07A4694A1E6FD404002C9B3C /* stdout_stream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stdout_stream.hpp; sourceTree = ""; }; 07A4694B1E6FD404002C9B3C /* stream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stream.hpp; sourceTree = ""; }; 07A4694C1E6FD404002C9B3C /* stream_hook.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = stream_hook.hpp; sourceTree = ""; }; + 07A4D1711E94E4A000790E12 /* mbox.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = mbox.hpp; sourceTree = ""; }; + 07A4D1721E94E4BC00790E12 /* mbox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mbox.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -958,6 +961,7 @@ 07A4678C1E6FCCF1002C9B3C /* stdlib */ = { isa = PBXGroup; children = ( + 07A4D1721E94E4BC00790E12 /* mbox.cpp */, 07A4678D1E6FCCF1002C9B3C /* charset_conv.cpp */, 07A4678E1E6FCCF1002C9B3C /* dbuf_pool.cpp */, 07A4678F1E6FCCF1002C9B3C /* dns_service.cpp */, @@ -1339,6 +1343,7 @@ 07A469191E6FD404002C9B3C /* stdlib */ = { isa = PBXGroup; children = ( + 07A4D1711E94E4A000790E12 /* mbox.hpp */, 07A4691A1E6FD404002C9B3C /* charset_conv.hpp */, 07A4691B1E6FD404002C9B3C /* dbuf_pool.hpp */, 07A4691C1E6FD404002C9B3C /* dns_service.hpp */, @@ -1497,6 +1502,7 @@ 07A4684D1E6FCCF1002C9B3C /* json.cpp in Sources */, 07A468201E6FCCF1002C9B3C /* mime_image.cpp in Sources */, 07A4685A1E6FCCF1002C9B3C /* url_coder.cpp in Sources */, + 07A4D1731E94E4BC00790E12 /* mbox.cpp in Sources */, 07A467DA1E6FCCF1002C9B3C /* db_service_mysql.cpp in Sources */, 07A4683D1E6FCCF1002C9B3C /* redis_string.cpp in Sources */, 07A468051E6FCCF1002C9B3C /* master_conf.cpp in Sources */, diff --git a/lib_acl_cpp/changes.txt b/lib_acl_cpp/changes.txt index 44fca0b97..e8fbedf36 100644 --- a/lib_acl_cpp/changes.txt +++ b/lib_acl_cpp/changes.txt @@ -1,6 +1,8 @@ 修改历史列表: ----------------------------------------------------------------------- +471) 2017.4.5 +471.1) feature: 增加 mbox 类用于消息队列的发送与读取,该类封装了 C 对象 ACL_MBOX 470) 2017.3.30 470.1) feature: json 类对象在创建 json 字符串时默认不自动添加空格,但允许调用者 diff --git a/lib_acl_cpp/include/acl_cpp/lib_acl.hpp b/lib_acl_cpp/include/acl_cpp/lib_acl.hpp index ace517c1d..d42fca1fa 100644 --- a/lib_acl_cpp/include/acl_cpp/lib_acl.hpp +++ b/lib_acl_cpp/include/acl_cpp/lib_acl.hpp @@ -31,6 +31,7 @@ #include "acl_cpp/stdlib/thread_queue.hpp" #include "acl_cpp/stdlib/scan_dir.hpp" #include "acl_cpp/stdlib/dbuf_pool.hpp" +#include "acl_cpp/stdlib/mbox.hpp" #include "acl_cpp/serialize/gsoner.hpp" diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/mbox.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/mbox.hpp new file mode 100644 index 000000000..bd4f9b008 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/mbox.hpp @@ -0,0 +1,56 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/noncopyable.hpp" + +struct ACL_MBOX; + +namespace acl +{ + +class ACL_CPP_API mobj +{ +public: + mobj(void) {} + virtual ~mobj(void) {} +}; + +class ACL_CPP_API mbox : public noncopyable +{ +public: + mbox(void); + ~mbox(void); + + /** + * 发送消息对象 + * @param o {mobj*} 非空消息对象 + * @return {bool} 发送是否成功 + */ + bool push(mobj* o); + + /** + * 接收消息对象 + * @param timeout {int} 大于 0 时设置读等待超时时间(秒),否则永远等待 + * 直到读到消息对象或出错 + * @param success {bool*} 可以用于辅助确定读操作是否成功 + * @return {mobj*} 非 NULL 表示读到一个消息对象,为 NULL 时,还需通过 + * success 参数的返回值检查操作是否成功 + */ + mobj* pop(int timeout = 0, bool* success = NULL); + + /** + * 统计当前已经发送的消息数 + * @return {size_t} + */ + size_t push_count(void) const; + + /** + * 统计当前已经接收到的消息数 + * @return {size_t} + */ + size_t pop_count(void) const; + +private: + ACL_MBOX* mbox_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/socket_stream.hpp b/lib_acl_cpp/include/acl_cpp/stream/socket_stream.hpp index 4a2a89938..a5f8c7627 100644 --- a/lib_acl_cpp/include/acl_cpp/stream/socket_stream.hpp +++ b/lib_acl_cpp/include/acl_cpp/stream/socket_stream.hpp @@ -57,6 +57,24 @@ class ACL_CPP_API socket_stream */ bool bind_udp(const char* addr, int rw_timeout = 0); + /** + * 关闭套接口读操作 + * @return {bool} + */ + bool shutdown_read(void); + + /** + * 关闭套接口写操作 + * @return {bool} + */ + bool shutdown_write(void); + + /** + * 关闭套接口读写操作 + * @return {bool} + */ + bool shutdown_readwrite(void); + /** * 获得网络连接流的套接字连接句柄 * @return {ACL_SOCKET} 若出错,则返回 - 1(UNIX 平台) diff --git a/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj b/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj index 27a9236ed..89f1fd8e7 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj +++ b/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj @@ -396,6 +396,9 @@ copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + @@ -1044,6 +1047,9 @@ copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2008.vcproj b/lib_acl_cpp/lib_acl_cpp_vc2008.vcproj index 54144bc87..b20d7d221 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2008.vcproj +++ b/lib_acl_cpp/lib_acl_cpp_vc2008.vcproj @@ -957,6 +957,10 @@ RelativePath=".\src\stdlib\malloc.cpp" > + + @@ -1683,6 +1687,10 @@ RelativePath=".\include\acl_cpp\stdlib\malloc.hpp" > + + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj index dc5c69039..752017731 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj +++ b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj @@ -333,6 +333,7 @@ copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + @@ -495,6 +496,7 @@ copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters index 156f26460..ad385b9de 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters +++ b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters @@ -289,6 +289,9 @@ src\stdlib + + src\stdlib + src\stdlib @@ -753,6 +756,9 @@ include\stdlib + + include\stdlib + include\stdlib diff --git a/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj index e4f6cac43..334becd1d 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj +++ b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj @@ -527,6 +527,7 @@ copy $(TargetName).pdb ..\dist\lib\win64\$(TargetName).pdb /Y + @@ -689,6 +690,7 @@ copy $(TargetName).pdb ..\dist\lib\win64\$(TargetName).pdb /Y + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters index c26593b13..bdde0d506 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters +++ b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters @@ -286,6 +286,9 @@ Source Files\stdlib + + Source Files\stdlib + Source Files\stdlib @@ -747,6 +750,9 @@ Header Files\stdlib + + Header Files\stdlib + Header Files\stdlib @@ -1199,4 +1205,4 @@ doc - \ No newline at end of file + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2015.vcxproj b/lib_acl_cpp/lib_acl_cpp_vc2015.vcxproj index dac99a1f9..2859dab6e 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2015.vcxproj +++ b/lib_acl_cpp/lib_acl_cpp_vc2015.vcxproj @@ -527,6 +527,7 @@ copy $(TargetName).pdb ..\dist\lib\win64\$(TargetName).pdb /Y + @@ -689,6 +690,7 @@ copy $(TargetName).pdb ..\dist\lib\win64\$(TargetName).pdb /Y + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2015.vcxproj.filters b/lib_acl_cpp/lib_acl_cpp_vc2015.vcxproj.filters index 24cee223a..5eedaafc4 100644 --- a/lib_acl_cpp/lib_acl_cpp_vc2015.vcxproj.filters +++ b/lib_acl_cpp/lib_acl_cpp_vc2015.vcxproj.filters @@ -286,6 +286,9 @@ Source Files\stdlib + + Source Files\stdlib + Source Files\stdlib @@ -747,6 +750,9 @@ Header Files\stdlib + + Header Files\stdlib + Header Files\stdlib diff --git a/lib_acl_cpp/samples/json/json1/json.cpp b/lib_acl_cpp/samples/json/json1/json.cpp index 3e829cd36..f166565e4 100644 --- a/lib_acl_cpp/samples/json/json1/json.cpp +++ b/lib_acl_cpp/samples/json/json1/json.cpp @@ -145,7 +145,7 @@ static void test(void) printf("-------------------------------------------------\r\n"); acl::string buf; - json.build_json(buf, true); + json.build_json(buf); printf("-----------------json------------------------\r\n"); printf("%s\r\n", buf.c_str()); diff --git a/lib_acl_cpp/src/serialize/gsoner.cpp b/lib_acl_cpp/src/serialize/gsoner.cpp index a6cfff368..2319852c2 100644 --- a/lib_acl_cpp/src/serialize/gsoner.cpp +++ b/lib_acl_cpp/src/serialize/gsoner.cpp @@ -262,11 +262,11 @@ std::string gsoner::get_unpack_code(const std::string &obj_name, { return tab_ + "if(!" + field.name_ + " ||" - + "!(result = gson(*" + field.name_ + ", &$obj." - + field.name_ + "), result.first))\n" + tab_ + tab_ + + "!($result = gson(*" + field.name_ + ", &$obj." + + field.name_ + "), $result.first))\n" + tab_ + tab_ + "return std::make_pair(false, \"required [" + obj_name + "." + field.name_ - + "] failed:{\"+result.second+\"}\");"; + + "] failed:{\"+$result.second+\"}\");"; } else return tab_ + @@ -277,11 +277,11 @@ std::string gsoner::get_unpack_code(const std::string &obj_name, { return tab_ + "if(!" + field.name_ + " ||" + "!" + field.name_ - + "->get_obj()||" + "!(result = gson(*" + field.name_ - + "->get_obj(), &$obj." + field.name_ + "), result.first))\n" + + "->get_obj()||" + "!($result = gson(*" + field.name_ + + "->get_obj(), &$obj." + field.name_ + "), $result.first))\n" + tab_ + tab_ + "return std::make_pair(false, \"required [" + obj_name + "." + field.name_ - + "] failed:{\"+result.second+\"}\");"; + + "] failed:{\"+$result.second+\"}\");"; } return tab_ + "if(" + field.name_ + "&& " + field.name_ @@ -319,7 +319,7 @@ gsoner::function_code_t gsoner::gen_unpack_code(const object_t &obj) code.definition_ += *itr; code.definition_ += "\n"; } - code.definition_ += tab_ + "std::pair result;\n\n"; + code.definition_ += tab_ + "std::pair $result;\n\n"; for (std::list::iterator itr = unpack_codes.begin(); itr != unpack_codes.end(); ++itr) { diff --git a/lib_acl_cpp/src/stdlib/mbox.cpp b/lib_acl_cpp/src/stdlib/mbox.cpp new file mode 100644 index 000000000..e7ca80f24 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/mbox.cpp @@ -0,0 +1,51 @@ +#include "acl_stdafx.hpp" +#ifndef ACL_PREPARE_COMPILE +#include +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/mbox.hpp" +#endif + +namespace acl +{ + +static void free_callback(void *ctx) +{ + mbox* o = (mbox*) ctx; + delete o; +} + +mbox::mbox(void) +{ + mbox_ = acl_mbox_create(); +} + +mbox::~mbox(void) +{ + acl_mbox_free(mbox_, free_callback); +} + +bool mbox::push(mobj* o) +{ + return acl_mbox_send(mbox_, o) == 0; +} + +mobj* mbox::pop(int timeout /* = 0 */, bool* success /* = NULL */) +{ + int ok; + mobj* o = (mobj*) acl_mbox_read(mbox_, timeout, &ok); + if (success) + *success = ok ? true : false; + return o; +} + +size_t mbox::push_count(void) const +{ + return acl_mbox_nsend(mbox_); +} + +size_t mbox::pop_count(void) const +{ + return acl_mbox_nread(mbox_); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/socket_stream.cpp b/lib_acl_cpp/src/stream/socket_stream.cpp index 564afed9c..aeadc6fae 100644 --- a/lib_acl_cpp/src/stream/socket_stream.cpp +++ b/lib_acl_cpp/src/stream/socket_stream.cpp @@ -61,6 +61,36 @@ bool socket_stream::bind_udp(const char* addr, int rw_timeout /* = 0 */) return true; } +bool socket_stream::shutdown_read() +{ + if (stream_ == NULL) + { + logger_error("stream_ null"); + return false; + } + return acl_socket_shutdown(ACL_VSTREAM_SOCK(stream_), SHUT_RD) == 0; +} + +bool socket_stream::shutdown_write() +{ + if (stream_ == NULL) + { + logger_error("stream_ null"); + return false; + } + return acl_socket_shutdown(ACL_VSTREAM_SOCK(stream_), SHUT_WR) == 0; +} + +bool socket_stream::shutdown_readwrite() +{ + if (stream_ == NULL) + { + logger_error("stream_ null"); + return false; + } + return acl_socket_shutdown(ACL_VSTREAM_SOCK(stream_), SHUT_RDWR) == 0; +} + ACL_SOCKET socket_stream::sock_handle() const { if (stream_ == NULL) diff --git a/lib_fiber/c/src/fiber.c.star b/lib_fiber/c/src/fiber.c.star new file mode 100644 index 000000000..6038c20a2 --- /dev/null +++ b/lib_fiber/c/src/fiber.c.star @@ -0,0 +1,636 @@ +#include "stdafx.h" +#define __USE_GNU +#include + +#ifdef USE_VALGRIND +#include +#endif + +#include "fiber/lib_fiber.h" +#include "event_epoll.h" /* just for hook_epoll */ +#include "fiber.h" + +#define MAX_CACHE 1000 + +typedef int *(*errno_fn)(void); +typedef int (*fcntl_fn)(int, int, ...); + +static errno_fn __sys_errno = NULL; +static fcntl_fn __sys_fcntl = NULL; + +typedef struct { + ACL_RING ready; /* ready fiber queue */ + ACL_FIBER **fibers; + unsigned size; + unsigned slot; + int exitcode; + ACL_FIBER *running; + ACL_FIBER original; + int errnum; + unsigned idgen; + int count; + int switched; + int nlocal; +} FIBER_TLS; + +static void fiber_init(void) __attribute__ ((constructor)); + +static FIBER_TLS *__main_fiber = NULL; +static __thread FIBER_TLS *__thread_fiber = NULL; +__thread int acl_var_hook_sys_api = 0; + +static acl_pthread_key_t __fiber_key; + +/* forward declare */ +static ACL_FIBER *fiber_alloc(void (*fn)(ACL_FIBER *, void *), + void *arg, size_t size); + +void acl_fiber_hook_api(int onoff) +{ + acl_var_hook_sys_api = onoff; +} + +static void thread_free(void *ctx) +{ + FIBER_TLS *tf = (FIBER_TLS *) ctx; + + if (__thread_fiber == NULL) + return; + + if (tf->fibers) + acl_myfree(tf->fibers); + if (tf->original.context) + acl_myfree(tf->original.context); + acl_myfree(tf); + + if (__main_fiber == __thread_fiber) + __main_fiber = NULL; + __thread_fiber = NULL; +} + +static void fiber_schedule_main_free(void) +{ + if (__main_fiber) { + thread_free(__main_fiber); + if (__thread_fiber == __main_fiber) + __thread_fiber = NULL; + __main_fiber = NULL; + } +} + +static void thread_init(void) +{ + if (acl_pthread_key_create(&__fiber_key, thread_free) != 0) + acl_msg_fatal("%s(%d), %s: pthread_key_create error %s", + __FILE__, __LINE__, __FUNCTION__, acl_last_serror()); +} + +static acl_pthread_once_t __once_control = ACL_PTHREAD_ONCE_INIT; + +static void fiber_check(void) +{ + if (__thread_fiber != NULL) + return; + + if (acl_pthread_once(&__once_control, thread_init) != 0) + acl_msg_fatal("%s(%d), %s: pthread_once error %s", + __FILE__, __LINE__, __FUNCTION__, acl_last_serror()); + + __thread_fiber = (FIBER_TLS *) acl_mycalloc(1, sizeof(FIBER_TLS)); + __thread_fiber->original.context = (ucontext_t *) + acl_mycalloc(1, sizeof(ucontext_t)); + __thread_fiber->fibers = NULL; + __thread_fiber->size = 0; + __thread_fiber->slot = 0; + __thread_fiber->idgen = 0; + __thread_fiber->count = 0; + __thread_fiber->nlocal = 0; + + acl_ring_init(&__thread_fiber->ready); + + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { + __main_fiber = __thread_fiber; + atexit(fiber_schedule_main_free); + } else if (acl_pthread_setspecific(__fiber_key, __thread_fiber) != 0) + acl_msg_fatal("acl_pthread_setspecific error!"); +} + +/* see /usr/include/bits/errno.h for __errno_location */ +#ifdef ACL_ARM_LINUX +volatile int* __errno(void) +#else +int *__errno_location(void) +#endif +{ + if (!acl_var_hook_sys_api) { + if (__sys_errno == NULL) + fiber_init(); + + return __sys_errno(); + } + + if (__thread_fiber == NULL) + fiber_check(); + + if (__thread_fiber->running) + return &__thread_fiber->running->errnum; + else + return &__thread_fiber->original.errnum; +} + +int fcntl(int fd, int cmd, ...) +{ + long arg; + struct flock *lock; + va_list ap; + int ret; + + if (__sys_fcntl == NULL) + fiber_init(); + + va_start(ap, cmd); + + switch (cmd) { + case F_GETFD: + case F_GETFL: + ret = __sys_fcntl(fd, cmd); + break; + case F_SETFD: + case F_SETFL: + arg = va_arg(ap, long); + ret = __sys_fcntl(fd, cmd, arg); + break; + case F_GETLK: + case F_SETLK: + case F_SETLKW: + lock = va_arg(ap, struct flock*); + ret = __sys_fcntl(fd, cmd, lock); + break; + default: + ret = -1; + acl_msg_error("%s(%d), %s: unknown cmd: %d, fd: %d", + __FILE__, __LINE__, __FUNCTION__, cmd, fd); + break; + } + + va_end(ap); + + if (ret < 0) + fiber_save_errno(); + + return ret; +} + +void acl_fiber_set_errno(ACL_FIBER *fiber, int errnum) +{ + if (fiber == NULL) + fiber = acl_fiber_running(); + if (fiber) + fiber->errnum = errnum; +} + +int acl_fiber_errno(ACL_FIBER *fiber) +{ + if (fiber == NULL) + fiber = acl_fiber_running(); + return fiber ? fiber->errnum : 0; +} + +void acl_fiber_keep_errno(ACL_FIBER *fiber, int yesno) +{ + if (fiber == NULL) + fiber = acl_fiber_running(); + if (fiber) { + if (yesno) + fiber->flag |= FIBER_F_SAVE_ERRNO; + else + fiber->flag &= ~FIBER_F_SAVE_ERRNO; + } +} + +void fiber_save_errno(void) +{ + ACL_FIBER *curr; + + if (__thread_fiber == NULL) + fiber_check(); + + if ((curr = __thread_fiber->running) == NULL) + curr = &__thread_fiber->original; + + if (curr->flag & FIBER_F_SAVE_ERRNO) { + //curr->flag &= ~FIBER_F_SAVE_ERRNO; + return; + } + + if (__sys_errno != NULL) + acl_fiber_set_errno(curr, *__sys_errno()); + else + acl_fiber_set_errno(curr, errno); +} + +static void fiber_swap(ACL_FIBER *from, ACL_FIBER *to) +{ + if (swapcontext(from->context, to->context) < 0) + acl_msg_fatal("%s(%d), %s: swapcontext error %s", + __FILE__, __LINE__, __FUNCTION__, acl_last_serror()); +} + +ACL_FIBER *acl_fiber_running(void) +{ + fiber_check(); + return __thread_fiber->running; +} + +void acl_fiber_kill(ACL_FIBER *fiber) +{ + acl_fiber_signal(fiber, SIGKILL); +} + +int acl_fiber_killed(ACL_FIBER *fiber) +{ + if (!fiber) + fiber = acl_fiber_running(); + return fiber && (fiber->flag & FIBER_F_KILLED); +} + +void acl_fiber_signal(ACL_FIBER *fiber, int signum) +{ + ACL_FIBER *curr = __thread_fiber->running; + + if (fiber == NULL) { + acl_msg_error("%s(%d), %s: fiber NULL", + __FILE__, __LINE__, __FUNCTION__); + return; + } + + if (curr == NULL) { + acl_msg_error("%s(%d), %s: current fiber NULL", + __FILE__, __LINE__, __FUNCTION__); + return; + } + + if (signum == SIGKILL || signum == SIGTERM || signum == SIGQUIT) { + fiber->errnum = ECANCELED; + fiber->flag |= FIBER_F_KILLED; + } + + fiber->signum = signum; + + if (fiber == curr) // just return if kill myself + return; + + acl_ring_detach(&curr->me); + acl_ring_detach(&fiber->me); + + /* add the current fiber and signed fiber in the head of the ready */ +#if 0 + acl_fiber_ready(fiber); + acl_fiber_yield(); +#else + curr->status = FIBER_STATUS_READY; + acl_ring_append(&__thread_fiber->ready, &curr->me); + + fiber->status = FIBER_STATUS_READY; + acl_ring_append(&__thread_fiber->ready, &fiber->me); + + acl_fiber_switch(); +#endif +} + +int acl_fiber_signum(ACL_FIBER *fiber) +{ + if (fiber) + fiber = acl_fiber_running(); + return fiber ? fiber->signum : 0; +} + +void fiber_exit(int exit_code) +{ + fiber_check(); + + __thread_fiber->exitcode = exit_code; + __thread_fiber->running->status = FIBER_STATUS_EXITING; + + acl_fiber_switch(); +} + +void acl_fiber_ready(ACL_FIBER *fiber) +{ + if (fiber->status != FIBER_STATUS_EXITING) { + fiber->status = FIBER_STATUS_READY; + acl_ring_prepend(&__thread_fiber->ready, &fiber->me); + } +} + +int acl_fiber_yield(void) +{ + int n; + + if (acl_ring_size(&__thread_fiber->ready) == 0) + return 0; + + n = __thread_fiber->switched; + acl_fiber_ready(__thread_fiber->running); + acl_fiber_switch(); + + return __thread_fiber->switched - n - 1; +} + +union cc_arg +{ + void *p; + int i[2]; +}; + +static void fiber_start(unsigned int x, unsigned int y) +{ + union cc_arg arg; + ACL_FIBER *fiber; + int i; + + arg.i[0] = x; + arg.i[1] = y; + + fiber = (ACL_FIBER *) arg.p; + + fiber->fn(fiber, fiber->arg); + + for (i = 0; i < fiber->nlocal; i++) { + if (fiber->locals[i] == NULL) + continue; + if (fiber->locals[i]->free_fn) + fiber->locals[i]->free_fn(fiber->locals[i]->ctx); + acl_myfree(fiber->locals[i]); + } + + if (fiber->locals) { + acl_myfree(fiber->locals); + fiber->locals = NULL; + fiber->nlocal = 0; + } + + fiber_exit(0); +} + +void fiber_free(ACL_FIBER *fiber) +{ +#ifdef USE_VALGRIND + VALGRIND_STACK_DEREGISTER(fiber->vid); +#endif + if (fiber->context) + acl_myfree(fiber->context); + acl_myfree(fiber->buff); + acl_myfree(fiber); +} + +static ACL_FIBER *fiber_alloc(void (*fn)(ACL_FIBER *, void *), + void *arg, size_t size) +{ + ACL_FIBER *fiber; + sigset_t zero; + union cc_arg carg; + + fiber_check(); + +#define APPL ACL_RING_TO_APPL + + fiber = (ACL_FIBER *) acl_mycalloc(1, sizeof(ACL_FIBER)); + /* no using calloc just avoiding using real memory */ + fiber->buff = (char *) acl_mymalloc(size); + + fiber->errnum = 0; + fiber->signum = 0; + fiber->fn = fn; + fiber->arg = arg; + fiber->size = size; + __thread_fiber->idgen++; + if (__thread_fiber->idgen == 0) /* overflow ? */ + __thread_fiber->idgen++; + fiber->id = __thread_fiber->idgen; + fiber->flag = 0; + fiber->status = FIBER_STATUS_READY; + + carg.p = fiber; + + if (fiber->context == NULL) + fiber->context = (ucontext_t *) acl_mymalloc(sizeof(ucontext_t)); + sigemptyset(&zero); + sigprocmask(SIG_BLOCK, &zero, &fiber->context->uc_sigmask); + + if (getcontext(fiber->context) < 0) + acl_msg_fatal("%s(%d), %s: getcontext error: %s", + __FILE__, __LINE__, __FUNCTION__, acl_last_serror()); + + fiber->context->uc_stack.ss_sp = fiber->buff + 8; + fiber->context->uc_stack.ss_size = fiber->size - 64; + + fiber->context->uc_link = __thread_fiber->original.context; + +#ifdef USE_VALGRIND + /* avoding the valgrind's warning */ + fiber->vid = VALGRIND_STACK_REGISTER(fiber->context->uc_stack.ss_sp, + (char*) fiber->context->uc_stack.ss_sp + + fiber->context->uc_stack.ss_size); +#endif + makecontext(fiber->context, (void(*)(void)) fiber_start, + 2, carg.i[0], carg.i[1]); + + return fiber; +} + +ACL_FIBER *acl_fiber_create(void (*fn)(ACL_FIBER *, void *), + void *arg, size_t size) +{ + ACL_FIBER *fiber = fiber_alloc(fn, arg, size); + + __thread_fiber->count++; + + if (__thread_fiber->slot >= __thread_fiber->size) { + __thread_fiber->size += 128; + __thread_fiber->fibers = (ACL_FIBER **) acl_myrealloc( + __thread_fiber->fibers, + __thread_fiber->size * sizeof(ACL_FIBER *)); + } + + fiber->slot = __thread_fiber->slot; + __thread_fiber->fibers[__thread_fiber->slot++] = fiber; + + acl_fiber_ready(fiber); + + return fiber; +} + +unsigned int acl_fiber_id(const ACL_FIBER *fiber) +{ + return fiber ? fiber->id : 0; +} + +unsigned int acl_fiber_self(void) +{ + ACL_FIBER *curr = acl_fiber_running(); + return acl_fiber_id(curr); +} + +int acl_fiber_status(const ACL_FIBER *fiber) +{ + if (fiber == NULL) + fiber = acl_fiber_running(); + return fiber ? fiber->status : 0; +} + +static void fiber_init(void) +{ + static int __called = 0; + + if (__called != 0) + return; + + __called++; + +#ifdef ACL_ARM_LINUX + __sys_errno = (errno_fn) dlsym(RTLD_NEXT, "__errno"); +#else + __sys_errno = (errno_fn) dlsym(RTLD_NEXT, "__errno_location"); +#endif + __sys_fcntl = (fcntl_fn) dlsym(RTLD_NEXT, "fcntl"); + + hook_io(); + hook_net(); + hook_epoll(); +} + +void acl_fiber_schedule(void) +{ + ACL_FIBER *fiber; + ACL_RING *head; + + acl_fiber_hook_api(1); + + for (;;) { + head = acl_ring_pop_head(&__thread_fiber->ready); + if (head == NULL) { + acl_msg_info("------- NO ACL_FIBER NOW --------"); + break; + } + + fiber = ACL_RING_TO_APPL(head, ACL_FIBER, me); + fiber->status = FIBER_STATUS_READY; + + __thread_fiber->running = fiber; + __thread_fiber->switched++; + + fiber_swap(&__thread_fiber->original, fiber); + __thread_fiber->running = NULL; + + if (fiber->status == FIBER_STATUS_EXITING) { + size_t slot = fiber->slot; + + if (!fiber->sys) + __thread_fiber->count--; + + __thread_fiber->fibers[slot] = + __thread_fiber->fibers[--__thread_fiber->slot]; + __thread_fiber->fibers[slot]->slot = slot; + + fiber_free(fiber); + } + } + + acl_fiber_hook_api(0); +} + +void fiber_system(void) +{ + if (!__thread_fiber->running->sys) { + __thread_fiber->running->sys = 1; + __thread_fiber->count--; + } +} + +void fiber_count_inc(void) +{ + __thread_fiber->count++; +} + +void fiber_count_dec(void) +{ + __thread_fiber->count--; +} + +void acl_fiber_switch(void) +{ + fiber_swap(__thread_fiber->running, &__thread_fiber->original); +} + +int acl_fiber_set_specific(int *key, void *ctx, void (*free_fn)(void *)) +{ + FIBER_LOCAL *local; + ACL_FIBER *curr; + + if (key == NULL) { + acl_msg_error("%s(%d), %s: key NULL", + __FILE__, __LINE__, __FUNCTION__); + return -1; + } + + if (__thread_fiber == NULL) { + acl_msg_error("%s(%d), %s: __thread_fiber: NULL", + __FILE__, __LINE__, __FUNCTION__); + return -1; + } else if (__thread_fiber->running == NULL) { + acl_msg_error("%s(%d), %s: running: NULL", + __FILE__, __LINE__, __FUNCTION__); + return -1; + } else + curr = __thread_fiber->running; + + if (*key <= 0) + *key = ++__thread_fiber->nlocal; + else if (*key > __thread_fiber->nlocal) { + acl_msg_error("%s(%d), %s: invalid key: %d > nlocal: %d", + __FILE__, __LINE__, __FUNCTION__, + *key, __thread_fiber->nlocal); + return -1; + } + + if (curr->nlocal < __thread_fiber->nlocal) { + curr->nlocal = __thread_fiber->nlocal; + curr->locals = (FIBER_LOCAL **) acl_myrealloc(curr->locals, + curr->nlocal * sizeof(FIBER_LOCAL*)); + } + + local = (FIBER_LOCAL *) acl_mycalloc(1, sizeof(FIBER_LOCAL)); + local->ctx = ctx; + local->free_fn = free_fn; + curr->locals[*key - 1] = local; + + return *key; +} + +void *acl_fiber_get_specific(int key) +{ + FIBER_LOCAL *local; + ACL_FIBER *curr; + + if (key <= 0) + return NULL; + + if (__thread_fiber == NULL) { + acl_msg_error("%s(%d), %s: __thread_fiber NULL", + __FILE__, __LINE__, __FUNCTION__); + return NULL; + } else if (__thread_fiber->running == NULL) { + acl_msg_error("%s(%d), %s: running fiber NULL", + __FILE__, __LINE__, __FUNCTION__); + return NULL; + } else + curr = __thread_fiber->running; + + if (key > curr->nlocal) + return NULL; + + local = curr->locals[key - 1]; + + return local ? local->ctx : NULL; +} diff --git a/lib_fiber/samples/mbox/Makefile b/lib_fiber/samples/mbox/Makefile new file mode 100644 index 000000000..c11c1cc11 --- /dev/null +++ b/lib_fiber/samples/mbox/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = mbox diff --git a/lib_fiber/samples/mbox/main.cpp b/lib_fiber/samples/mbox/main.cpp new file mode 100644 index 000000000..108813dc6 --- /dev/null +++ b/lib_fiber/samples/mbox/main.cpp @@ -0,0 +1,148 @@ +#include "stdafx.h" +#include +#include + +class myobj : public acl::mobj +{ +public: + myobj(void) : n_(0) {} + ~myobj(void) {} + + void run(void) + { + int i = 5; + printf("thread-%lu sleep %d seconds\r\n", + acl::thread::thread_self(), i); + sleep(i); + printf("thread-%lu wakeup\r\n", acl::thread::thread_self()); + + n_ ++; + } + + int get_result(void) const + { + return n_; + } + +private: + int n_; +}; + +class mythread : public acl::thread +{ +public: + mythread(acl::mbox& mb, myobj& o) : mb_(mb), o_(o) {} + ~mythread(void) {} + +protected: + // @override + void* run(void) + { + o_.run(); + mb_.push(&o_); + return NULL; + } + +private: + acl::mbox& mb_; + myobj& o_; +}; + +class myfiber : public acl::fiber +{ +public: + myfiber(acl::fiber_sem& sem) : sem_(sem) {} + ~myfiber(void) {} + +protected: + // @override + void run(void) + { + printf("fiber-%u: wait result from thread\r\n", get_id()); + + myobj mo; + mythread thr(mb_, mo); + thr.start(); + + myobj* o = (myobj*) mb_.pop(); + assert(o == &mo); + printf("fiber-%u: result = %d\r\n", get_id(), o->get_result()); + + sem_.post(); + delete this; + } + +private: + acl::mbox mb_; + acl::fiber_sem& sem_; +}; + +////////////////////////////////////////////////////////////////////////////// + +class sleepy_fiber : public acl::fiber +{ +public: + sleepy_fiber(acl::fiber_sem& sem) : sem_(sem) {} + ~sleepy_fiber(void) {} + +protected: + void run(void) + { + time_t begin = time(NULL); + int n = 0; + while (n++ < 6) + { + sleep(1); + printf("fiber-%u sleep %d second\r\n", get_id(), n); + } + + time_t end = time(NULL); + + printf("fiber-%u wait sem, spent: %ld\r\n", + get_id(), (long) (end - begin)); + sem_.wait(); + acl::fiber::schedule_stop(); + } + +private: + acl::fiber_sem& sem_; +}; + +////////////////////////////////////////////////////////////////////////////// + +static void usage(const char* procname) +{ + printf("usage: %s -h [help]\r\n", procname); +} + +int main(int argc, char *argv[]) +{ + int ch; + + acl::acl_cpp_init(); + acl::log::stdout_open(true); + + while ((ch = getopt(argc, argv, "h")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + default: + break; + } + } + + acl::fiber_sem sem(0); + + acl::fiber* f = new myfiber(sem); + f->start(); + + sleepy_fiber fb(sem); + fb.start(); + + acl::fiber::schedule(); + + return 0; +} diff --git a/lib_fiber/samples/mbox/stdafx.cpp b/lib_fiber/samples/mbox/stdafx.cpp new file mode 100644 index 000000000..a27b824da --- /dev/null +++ b/lib_fiber/samples/mbox/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" diff --git a/lib_fiber/samples/mbox/stdafx.h b/lib_fiber/samples/mbox/stdafx.h new file mode 100644 index 000000000..cee9a8583 --- /dev/null +++ b/lib_fiber/samples/mbox/stdafx.h @@ -0,0 +1,20 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" +#include "fiber/lib_fiber.hpp" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + diff --git a/lib_fiber/samples/mbox/valgrind.sh b/lib_fiber/samples/mbox/valgrind.sh new file mode 100644 index 000000000..83c4b9dd9 --- /dev/null +++ b/lib_fiber/samples/mbox/valgrind.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +#valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes --max-stackframe=3426305034400000 -v ./fiber -n 10 -m 20 +valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-reachable=yes -v ./mbox