From f850f459c434b1cac828693d6bd13c3976d03959 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 23 Jan 2019 08:58:47 +0000 Subject: [PATCH] removed all aio* files. all relevant functions are available in a different project, mio --- qse/include/qse/si/Makefile.am | 3 - qse/include/qse/si/Makefile.in | 18 +- qse/include/qse/si/aio-pro.h | 164 --- qse/include/qse/si/aio-sck.h | 597 ----------- qse/include/qse/si/aio.h | 438 -------- qse/lib/si/Makefile.am | 5 - qse/lib/si/Makefile.in | 43 +- qse/lib/si/aio-pro.c | 853 ---------------- qse/lib/si/aio-prv.h | 115 --- qse/lib/si/aio-sck.c | 1712 -------------------------------- qse/lib/si/aio-tmr.c | 234 ----- qse/lib/si/aio.c | 1468 --------------------------- qse/samples/si/Makefile.am | 2 - qse/samples/si/aio01.c | 713 ------------- 14 files changed, 10 insertions(+), 6355 deletions(-) delete mode 100644 qse/include/qse/si/aio-pro.h delete mode 100644 qse/include/qse/si/aio-sck.h delete mode 100644 qse/include/qse/si/aio.h delete mode 100644 qse/lib/si/aio-pro.c delete mode 100644 qse/lib/si/aio-prv.h delete mode 100644 qse/lib/si/aio-sck.c delete mode 100644 qse/lib/si/aio-tmr.c delete mode 100644 qse/lib/si/aio.c delete mode 100644 qse/samples/si/aio01.c diff --git a/qse/include/qse/si/Makefile.am b/qse/include/qse/si/Makefile.am index d436696f..66263de2 100644 --- a/qse/include/qse/si/Makefile.am +++ b/qse/include/qse/si/Makefile.am @@ -1,9 +1,6 @@ pkgincludedir = $(includedir)/qse/si pkginclude_HEADERS = \ - aio.h \ - aio-pro.h \ - aio-sck.h \ cnd.h \ dir.h \ fio.h \ diff --git a/qse/include/qse/si/Makefile.in b/qse/include/qse/si/Makefile.in index b11ceb08..37a81d3b 100644 --- a/qse/include/qse/si/Makefile.in +++ b/qse/include/qse/si/Makefile.in @@ -133,12 +133,11 @@ am__can_run_installinfo = \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac -am__pkginclude_HEADERS_DIST = aio.h aio-pro.h aio-sck.h cnd.h dir.h \ - fio.h fs.h glob.h intr.h log.h mtx.h mux.h netlink.h nwad.h \ - nwif.h nwio.h os.h pio.h rwl.h sck.h sinfo.h sio.h spl.h \ - task.h thr.h tio.h App.hpp Condition.hpp Mutex.hpp \ - SocketAddress.hpp Socket.hpp SpinLock.hpp TcpServer.hpp \ - Thread.hpp +am__pkginclude_HEADERS_DIST = cnd.h dir.h fio.h fs.h glob.h intr.h \ + log.h mtx.h mux.h netlink.h nwad.h nwif.h nwio.h os.h pio.h \ + rwl.h sck.h sinfo.h sio.h spl.h task.h thr.h tio.h App.hpp \ + Condition.hpp Mutex.hpp SocketAddress.hpp Socket.hpp \ + SpinLock.hpp TcpServer.hpp Thread.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ @@ -355,10 +354,9 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -pkginclude_HEADERS = aio.h aio-pro.h aio-sck.h cnd.h dir.h fio.h fs.h \ - glob.h intr.h log.h mtx.h mux.h netlink.h nwad.h nwif.h nwio.h \ - os.h pio.h rwl.h sck.h sinfo.h sio.h spl.h task.h thr.h tio.h \ - $(am__append_1) +pkginclude_HEADERS = cnd.h dir.h fio.h fs.h glob.h intr.h log.h mtx.h \ + mux.h netlink.h nwad.h nwif.h nwio.h os.h pio.h rwl.h sck.h \ + sinfo.h sio.h spl.h task.h thr.h tio.h $(am__append_1) all: all-am .SUFFIXES: diff --git a/qse/include/qse/si/aio-pro.h b/qse/include/qse/si/aio-pro.h deleted file mode 100644 index f619b083..00000000 --- a/qse/include/qse/si/aio-pro.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * $Id$ - * - Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _QSE_SI_AIO_PRO_H_ -#define _QSE_SI_AIO_PRO_H_ - -#include - -enum qse_aio_dev_pro_sid_t -{ - QSE_AIO_DEV_PRO_MASTER = -1, - QSE_AIO_DEV_PRO_IN = 0, - QSE_AIO_DEV_PRO_OUT = 1, - QSE_AIO_DEV_PRO_ERR = 2 -}; -typedef enum qse_aio_dev_pro_sid_t qse_aio_dev_pro_sid_t; - -typedef struct qse_aio_dev_pro_t qse_aio_dev_pro_t; -typedef struct qse_aio_dev_pro_slave_t qse_aio_dev_pro_slave_t; - -typedef int (*qse_aio_dev_pro_on_read_t) (qse_aio_dev_pro_t* dev, const void* data, qse_aio_iolen_t len, qse_aio_dev_pro_sid_t sid); -typedef int (*qse_aio_dev_pro_on_write_t) (qse_aio_dev_pro_t* dev, qse_aio_iolen_t wrlen, void* wrctx); -typedef void (*qse_aio_dev_pro_on_close_t) (qse_aio_dev_pro_t* dev, qse_aio_dev_pro_sid_t sid); - -struct qse_aio_dev_pro_t -{ - QSE_AIO_DEV_HEADERS; - - int flags; - qse_intptr_t child_pid; /* defined to qse_intptr_t to hide pid_t */ - qse_aio_dev_pro_slave_t* slave[3]; - int slave_count; - - qse_aio_dev_pro_on_read_t on_read; - qse_aio_dev_pro_on_write_t on_write; - qse_aio_dev_pro_on_close_t on_close; - - qse_mchar_t* mcmd; -}; - -struct qse_aio_dev_pro_slave_t -{ - QSE_AIO_DEV_HEADERS; - qse_aio_dev_pro_sid_t id; - qse_aio_syshnd_t pfd; - qse_aio_dev_pro_t* master; /* parent device */ -}; - -enum qse_aio_dev_pro_make_flag_t -{ - QSE_AIO_DEV_PRO_WRITEIN = (1 << 0), - QSE_AIO_DEV_PRO_READOUT = (1 << 1), - QSE_AIO_DEV_PRO_READERR = (1 << 2), - - QSE_AIO_DEV_PRO_ERRTOOUT = (1 << 3), - QSE_AIO_DEV_PRO_OUTTOERR = (1 << 4), - - QSE_AIO_DEV_PRO_INTONUL = (1 << 5), - QSE_AIO_DEV_PRO_OUTTONUL = (1 << 6), - QSE_AIO_DEV_PRO_ERRTONUL = (1 << 7), - - STUO_DEV_PRO_DROPIN = (1 << 8), - STUO_DEV_PRO_DROPOUT = (1 << 9), - STUO_DEV_PRO_DROPERR = (1 << 10), - - - QSE_AIO_DEV_PRO_SHELL = (1 << 13), - - /* perform no waitpid() on a child process upon device destruction. - * you should set this flag if your application has automatic child - * process reaping enabled. for instance, SIGCHLD is set to SIG_IGN - * on POSIX.1-2001 compliant systems */ - QSE_AIO_DEV_PRO_FORGET_CHILD = (1 << 14), - - - QSE_AIO_DEV_PRO_FORGET_DIEHARD_CHILD = (1 << 15) -}; -typedef enum qse_aio_dev_pro_make_flag_t qse_aio_dev_pro_make_flag_t; - -typedef struct qse_aio_dev_pro_make_t qse_aio_dev_pro_make_t; -struct qse_aio_dev_pro_make_t -{ - int flags; /**< bitwise-ORed of qse_aio_dev_pro_make_flag_t enumerators */ - const void* cmd; - qse_aio_dev_pro_on_write_t on_write; /* mandatory */ - qse_aio_dev_pro_on_read_t on_read; /* mandatory */ - qse_aio_dev_pro_on_close_t on_close; /* optional */ -}; - - -enum qse_aio_dev_pro_ioctl_cmd_t -{ - QSE_AIO_DEV_PRO_CLOSE, - QSE_AIO_DEV_PRO_KILL_CHILD -}; -typedef enum qse_aio_dev_pro_ioctl_cmd_t qse_aio_dev_pro_ioctl_cmd_t; - -#ifdef __cplusplus -extern "C" { -#endif - -QSE_EXPORT qse_aio_dev_pro_t* qse_aio_dev_pro_make ( - qse_aio_t* aio, - qse_size_t xtnsize, - const qse_aio_dev_pro_make_t* data -); - -QSE_EXPORT void qse_aio_dev_pro_kill ( - qse_aio_dev_pro_t* pro -); - -QSE_EXPORT int qse_aio_dev_pro_write ( - qse_aio_dev_pro_t* pro, - const void* data, - qse_aio_iolen_t len, - void* wrctx -); - -QSE_EXPORT int qse_aio_dev_pro_timedwrite ( - qse_aio_dev_pro_t* pro, - const void* data, - qse_aio_iolen_t len, - const qse_ntime_t* tmout, - void* wrctx -); - -QSE_EXPORT int qse_aio_dev_pro_close ( - qse_aio_dev_pro_t* pro, - qse_aio_dev_pro_sid_t sid -); - - -QSE_EXPORT int qse_aio_dev_pro_killchild ( - qse_aio_dev_pro_t* pro -); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/qse/include/qse/si/aio-sck.h b/qse/include/qse/si/aio-sck.h deleted file mode 100644 index 69ca6dcb..00000000 --- a/qse/include/qse/si/aio-sck.h +++ /dev/null @@ -1,597 +0,0 @@ -/* - * $Id$ - * - Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _QSE_SI_AIO_SCK_H_ -#define _QSE_SI_AIO_SCK_H_ - -#include - -/* ========================================================================= */ -/* TOOD: move these to a separte file */ - -#define QSE_AIO_ETHHDR_PROTO_IP4 0x0800 -#define QSE_AIO_ETHHDR_PROTO_ARP 0x0806 -#define QSE_AIO_ETHHDR_PROTO_8021Q 0x8100 /* 802.1Q VLAN */ -#define QSE_AIO_ETHHDR_PROTO_IP6 0x86DD - - -#define QSE_AIO_ARPHDR_OPCODE_REQUEST 1 -#define QSE_AIO_ARPHDR_OPCODE_REPLY 2 - -#define QSE_AIO_ARPHDR_HTYPE_ETH 0x0001 -#define QSE_AIO_ARPHDR_PTYPE_IP4 0x0800 - -#define QSE_AIO_ETHADDR_LEN 6 -#define QSE_AIO_IP4ADDR_LEN 4 -#define QSE_AIO_IP6ADDR_LEN 16 - - -#if defined(__GNUC__) -# define QSE_AIO_PACKED __attribute__((__packed__)) - -#else -# define QSE_AIO_PACKED -# QSE_AIO_PACK_PUSH pack(push) -# QSE_AIO_PACK_PUSH pack(push) -# QSE_AIO_PACK(x) pack(x) -#endif - - -#if defined(__GNUC__) - /* nothing */ -#else - #pragma pack(push) - #pragma pack(1) -#endif -struct QSE_AIO_PACKED qse_aio_ethaddr_t -{ - qse_uint8_t v[QSE_AIO_ETHADDR_LEN]; -}; -typedef struct qse_aio_ethaddr_t qse_aio_ethaddr_t; - -struct QSE_AIO_PACKED qse_aio_ip4addr_t -{ - qse_uint8_t v[QSE_AIO_IP4ADDR_LEN]; -}; -typedef struct qse_aio_ip4addr_t qse_aio_ip4addr_t; - -struct QSE_AIO_PACKED qse_aio_ip6addr_t -{ - qse_uint8_t v[QSE_AIO_IP6ADDR_LEN]; -}; -typedef struct qse_aio_ip6addr_t qse_aio_ip6addr_t; - -struct QSE_AIO_PACKED qse_aio_ethhdr_t -{ - qse_uint8_t dest[QSE_AIO_ETHADDR_LEN]; - qse_uint8_t source[QSE_AIO_ETHADDR_LEN]; - qse_uint16_t proto; -}; -typedef struct qse_aio_ethhdr_t qse_aio_ethhdr_t; - -struct QSE_AIO_PACKED qse_aio_arphdr_t -{ - qse_uint16_t htype; /* hardware type (ethernet: 0x0001) */ - qse_uint16_t ptype; /* protocol type (ipv4: 0x0800) */ - qse_uint8_t hlen; /* hardware address length (ethernet: 6) */ - qse_uint8_t plen; /* protocol address length (ipv4 :4) */ - qse_uint16_t opcode; /* operation code */ -}; -typedef struct qse_aio_arphdr_t qse_aio_arphdr_t; - -/* arp payload for ipv4 over ethernet */ -struct QSE_AIO_PACKED qse_aio_etharp_t -{ - qse_uint8_t sha[QSE_AIO_ETHADDR_LEN]; /* source hardware address */ - qse_uint8_t spa[QSE_AIO_IP4ADDR_LEN]; /* source protocol address */ - qse_uint8_t tha[QSE_AIO_ETHADDR_LEN]; /* target hardware address */ - qse_uint8_t tpa[QSE_AIO_IP4ADDR_LEN]; /* target protocol address */ -}; -typedef struct qse_aio_etharp_t qse_aio_etharp_t; - -struct QSE_AIO_PACKED qse_aio_etharp_pkt_t -{ - qse_aio_ethhdr_t ethhdr; - qse_aio_arphdr_t arphdr; - qse_aio_etharp_t arppld; -}; -typedef struct qse_aio_etharp_pkt_t qse_aio_etharp_pkt_t; - - -struct qse_aio_iphdr_t -{ -#if defined(QSE_ENDIAN_LITTLE) - qse_uint8_t ihl:4; - qse_uint8_t version:4; -#elif defined(QSE_ENDIAN_BIG) - qse_uint8_t version:4; - qse_uint8_t ihl:4; -#else -# UNSUPPORTED ENDIAN -#endif - qse_int8_t tos; - qse_int16_t tot_len; - qse_int16_t id; - qse_int16_t frag_off; - qse_int8_t ttl; - qse_int8_t protocol; - qse_int16_t check; - qse_int32_t saddr; - qse_int32_t daddr; - /*The options start here. */ -}; -typedef struct qse_aio_iphdr_t qse_aio_iphdr_t; - - -struct QSE_AIO_PACKED qse_aio_icmphdr_t -{ - qse_uint8_t type; /* message type */ - qse_uint8_t code; /* subcode */ - qse_uint16_t checksum; - union - { - struct - { - qse_uint16_t id; - qse_uint16_t seq; - } echo; - - qse_uint32_t gateway; - - struct - { - qse_uint16_t frag_unused; - qse_uint16_t mtu; - } frag; /* path mut discovery */ - } u; -}; -typedef struct qse_aio_icmphdr_t qse_aio_icmphdr_t; - -#if defined(__GNUC__) - /* nothing */ -#else - #pragma pack(pop) -#endif - -/* ICMP types */ -#define QSE_AIO_ICMP_ECHO_REPLY 0 -#define QSE_AIO_ICMP_UNREACH 3 /* destination unreachable */ -#define QSE_AIO_ICMP_SOURCE_QUENCE 4 -#define QSE_AIO_ICMP_REDIRECT 5 -#define QSE_AIO_ICMP_ECHO_REQUEST 8 -#define QSE_AIO_ICMP_TIME_EXCEEDED 11 -#define QSE_AIO_ICMP_PARAM_PROBLEM 12 -#define QSE_AIO_ICMP_TIMESTAMP_REQUEST 13 -#define QSE_AIO_ICMP_TIMESTAMP_REPLY 14 -#define QSE_AIO_ICMP_INFO_REQUEST 15 -#define QSE_AIO_ICMP_INFO_REPLY 16 -#define QSE_AIO_ICMP_ADDR_MASK_REQUEST 17 -#define QSE_AIO_ICMP_ADDR_MASK_REPLY 18 - -/* Subcode for QSE_AIO_ICMP_UNREACH */ -#define QSE_AIO_ICMP_UNREACH_NET 0 -#define QSE_AIO_ICMP_UNREACH_HOST 1 -#define QSE_AIO_ICMP_UNREACH_PROTOCOL 2 -#define QSE_AIO_ICMP_UNREACH_PORT 3 -#define QSE_AIO_ICMP_UNREACH_FRAG_NEEDED 4 - -/* Subcode for QSE_AIO_ICMP_REDIRECT */ -#define QSE_AIO_ICMP_REDIRECT_NET 0 -#define QSE_AIO_ICMP_REDIRECT_HOST 1 -#define QSE_AIO_ICMP_REDIRECT_NETTOS 2 -#define QSE_AIO_ICMP_REDIRECT_HOSTTOS 3 - -/* Subcode for QSE_AIO_ICMP_TIME_EXCEEDED */ -#define QSE_AIO_ICMP_TIME_EXCEEDED_TTL 0 -#define QSE_AIO_ICMP_TIME_EXCEEDED_FRAGTIME 1 - -/* ========================================================================= */ - -typedef int qse_aio_sckfam_t; - -struct qse_aio_sckaddr_t -{ - qse_aio_sckfam_t family; - qse_uint8_t data[128]; /* TODO: use the actual sockaddr size */ -}; -typedef struct qse_aio_sckaddr_t qse_aio_sckaddr_t; - -#if (QSE_SIZEOF_SOCKLEN_T == QSE_SIZEOF_INT) - #if defined(QSE_AIO_SOCKLEN_T_IS_SIGNED) - typedef int qse_aio_scklen_t; - #else - typedef unsigned int qse_aio_scklen_t; - #endif -#elif (QSE_SIZEOF_SOCKLEN_T == QSE_SIZEOF_LONG) - #if defined(QSE_AIO_SOCKLEN_T_IS_SIGNED) - typedef long qse_aio_scklen_t; - #else - typedef unsigned long qse_aio_scklen_t; - #endif -#else - typedef int qse_aio_scklen_t; -#endif - -#if defined(_WIN32) -# define QSE_AIO_IOCP_KEY 1 - /* - typedef HANDLE qse_aio_syshnd_t; - typedef SOCKET qse_aio_sckhnd_t; -# define QSE_AIO_SCKHND_INVALID (INVALID_SOCKET) - */ - - typedef qse_uintptr_t qse_aio_sckhnd_t; -# define QSE_AIO_SCKHND_INVALID (~(qse_aio_sck_hnd_t)0) - -#else - typedef int qse_aio_sckhnd_t; -# define QSE_AIO_SCKHND_INVALID (-1) - -#endif - - -/* ========================================================================= */ - -enum qse_aio_dev_sck_ioctl_cmd_t -{ - QSE_AIO_DEV_SCK_BIND, - QSE_AIO_DEV_SCK_CONNECT, - QSE_AIO_DEV_SCK_LISTEN -}; -typedef enum qse_aio_dev_sck_ioctl_cmd_t qse_aio_dev_sck_ioctl_cmd_t; - - -#define QSE_AIO_DEV_SCK_SET_PROGRESS(dev,bit) do { \ - (dev)->state &= ~QSE_AIO_DEV_SCK_ALL_PROGRESS_BITS; \ - (dev)->state |= (bit); \ -} while(0) - -#define QSE_AIO_DEV_SCK_GET_PROGRESS(dev) ((dev)->state & QSE_AIO_DEV_SCK_ALL_PROGRESS_BITS) - -enum qse_aio_dev_sck_state_t -{ - /* the following items(progress bits) are mutually exclusive */ - QSE_AIO_DEV_SCK_CONNECTING = (1 << 0), - QSE_AIO_DEV_SCK_CONNECTING_SSL = (1 << 1), - QSE_AIO_DEV_SCK_CONNECTED = (1 << 2), - QSE_AIO_DEV_SCK_LISTENING = (1 << 3), - QSE_AIO_DEV_SCK_ACCEPTING_SSL = (1 << 4), - QSE_AIO_DEV_SCK_ACCEPTED = (1 << 5), - - /* the following items can be bitwise-ORed with an exclusive item above */ - QSE_AIO_DEV_SCK_INTERCEPTED = (1 << 15), - - - /* convenience bit masks */ - QSE_AIO_DEV_SCK_ALL_PROGRESS_BITS = (QSE_AIO_DEV_SCK_CONNECTING | - QSE_AIO_DEV_SCK_CONNECTING_SSL | - QSE_AIO_DEV_SCK_CONNECTED | - QSE_AIO_DEV_SCK_LISTENING | - QSE_AIO_DEV_SCK_ACCEPTING_SSL | - QSE_AIO_DEV_SCK_ACCEPTED) -}; -typedef enum qse_aio_dev_sck_state_t qse_aio_dev_sck_state_t; - -typedef struct qse_aio_dev_sck_t qse_aio_dev_sck_t; - -typedef int (*qse_aio_dev_sck_on_read_t) ( - qse_aio_dev_sck_t* dev, - const void* data, - qse_aio_iolen_t dlen, - const qse_aio_sckaddr_t* srcaddr -); - -typedef int (*qse_aio_dev_sck_on_write_t) ( - qse_aio_dev_sck_t* dev, - qse_aio_iolen_t wrlen, - void* wrctx, - const qse_aio_sckaddr_t* dstaddr -); - -typedef void (*qse_aio_dev_sck_on_disconnect_t) ( - qse_aio_dev_sck_t* dev -); - -typedef int (*qse_aio_dev_sck_on_connect_t) ( - qse_aio_dev_sck_t* dev -); - -enum qse_aio_dev_sck_type_t -{ - QSE_AIO_DEV_SCK_TCP4, - QSE_AIO_DEV_SCK_TCP6, - QSE_AIO_DEV_SCK_UPD4, - QSE_AIO_DEV_SCK_UDP6, - - /* ARP at the ethernet layer */ - QSE_AIO_DEV_SCK_ARP, - QSE_AIO_DEV_SCK_ARP_DGRAM, - - /* ICMP at the IPv4 layer */ - QSE_AIO_DEV_SCK_ICMP4, - - /* ICMP at the IPv6 layer */ - QSE_AIO_DEV_SCK_ICMP6 - -#if 0 - QSE_AIO_DEV_SCK_RAW, /* raw L2-level packet */ -#endif -}; -typedef enum qse_aio_dev_sck_type_t qse_aio_dev_sck_type_t; - -typedef struct qse_aio_dev_sck_make_t qse_aio_dev_sck_make_t; -struct qse_aio_dev_sck_make_t -{ - qse_aio_dev_sck_type_t type; - qse_aio_dev_sck_on_write_t on_write; - qse_aio_dev_sck_on_read_t on_read; - qse_aio_dev_sck_on_disconnect_t on_disconnect; -}; - -enum qse_aio_dev_sck_bind_option_t -{ - QSE_AIO_DEV_SCK_BIND_BROADCAST = (1 << 0), - QSE_AIO_DEV_SCK_BIND_REUSEADDR = (1 << 1), - QSE_AIO_DEV_SCK_BIND_REUSEPORT = (1 << 2), - QSE_AIO_DEV_SCK_BIND_TRANSPARENT = (1 << 3), - -/* TODO: more options --- SO_RCVBUF, SO_SNDBUF, SO_RCVTIMEO, SO_SNDTIMEO, SO_KEEPALIVE */ -/* BINDTODEVICE??? */ - - QSE_AIO_DEV_SCK_BIND_SSL = (1 << 15) -}; -typedef enum qse_aio_dev_sck_bind_option_t qse_aio_dev_sck_bind_option_t; - -typedef struct qse_aio_dev_sck_bind_t qse_aio_dev_sck_bind_t; -struct qse_aio_dev_sck_bind_t -{ - int options; - qse_aio_sckaddr_t localaddr; - /* TODO: add device name for BIND_TO_DEVICE */ - - const qse_mchar_t* ssl_certfile; - const qse_mchar_t* ssl_keyfile; - qse_ntime_t accept_tmout; -}; - -enum qse_aio_def_sck_connect_option_t -{ - QSE_AIO_DEV_SCK_CONNECT_SSL = (1 << 15) -}; -typedef enum qse_aio_dev_sck_connect_option_t qse_aio_dev_sck_connect_option_t; - -typedef struct qse_aio_dev_sck_connect_t qse_aio_dev_sck_connect_t; -struct qse_aio_dev_sck_connect_t -{ - int options; - qse_aio_sckaddr_t remoteaddr; - qse_ntime_t connect_tmout; - qse_aio_dev_sck_on_connect_t on_connect; -}; - -typedef struct qse_aio_dev_sck_listen_t qse_aio_dev_sck_listen_t; -struct qse_aio_dev_sck_listen_t -{ - int backlogs; - qse_aio_dev_sck_on_connect_t on_connect; /* optional, but new connections are dropped immediately without this */ -}; - -typedef struct qse_aio_dev_sck_accept_t qse_aio_dev_sck_accept_t; -struct qse_aio_dev_sck_accept_t -{ - qse_aio_syshnd_t sck; -/* TODO: add timeout */ - qse_aio_sckaddr_t remoteaddr; -}; - -struct qse_aio_dev_sck_t -{ - QSE_AIO_DEV_HEADERS; - - qse_aio_dev_sck_type_t type; - qse_aio_sckhnd_t sck; - - int state; - - /* remote peer address for a stateful stream socket. valid if one of the - * followings is set in state: - * QSE_AIO_DEV_TCP_ACCEPTING_SSL - * QSE_AIO_DEV_TCP_ACCEPTED - * QSE_AIO_DEV_TCP_CONNECTED - * QSE_AIO_DEV_TCP_CONNECTING - * QSE_AIO_DEV_TCP_CONNECTING_SSL - * - * also used as a placeholder to store source address for - * a stateless socket */ - qse_aio_sckaddr_t remoteaddr; - - /* local socket address */ - qse_aio_sckaddr_t localaddr; - - /* original destination address */ - qse_aio_sckaddr_t orgdstaddr; - - qse_aio_dev_sck_on_write_t on_write; - qse_aio_dev_sck_on_read_t on_read; - - /* return 0 on succes, -1 on failure. - * called on a new tcp device for an accepted client or - * on a tcp device conntected to a remote server */ - qse_aio_dev_sck_on_connect_t on_connect; - qse_aio_dev_sck_on_disconnect_t on_disconnect; - - /* timer job index for handling - * - connect() timeout for a connecting socket. - * - SSL_accept() timeout for a socket accepting SSL */ - qse_aio_tmridx_t tmrjob_index; - - /* connect timeout, ssl-connect timeout, ssl-accept timeout. - * it denotes timeout duration under some circumstances - * or an absolute expiry time under some other circumstances. */ - qse_ntime_t tmout; - - void* ssl_ctx; - void* ssl; - -}; - -#ifdef __cplusplus -extern "C" { -#endif - -QSE_EXPORT qse_aio_sckhnd_t qse_aio_openasyncsck ( - qse_aio_t* aio, - int domain, - int type, - int proto -); - -QSE_EXPORT void qse_aio_closeasyncsck ( - qse_aio_t* aio, - qse_aio_sckhnd_t sck -); - -QSE_EXPORT int qse_aio_makesckasync ( - qse_aio_t* aio, - qse_aio_sckhnd_t sck -); - -QSE_EXPORT int qse_aio_getsckaddrinfo ( - qse_aio_t* aio, - const qse_aio_sckaddr_t* addr, - qse_aio_scklen_t* len, - qse_aio_sckfam_t* family -); - -/* - * The qse_aio_getsckaddrport() function returns the port number of a socket - * address in the host byte order. If the address doesn't support the port - * number, it returns 0. - */ -QSE_EXPORT qse_uint16_t qse_aio_getsckaddrport ( - const qse_aio_sckaddr_t* addr -); - -/* - * The qse_aio_getsckaddrifindex() function returns an interface number. - * If the address doesn't support the interface number, it returns 0. */ -QSE_EXPORT int qse_aio_getsckaddrifindex ( - const qse_aio_sckaddr_t* addr -); - - -QSE_EXPORT void qse_aio_sckaddr_initforip4 ( - qse_aio_sckaddr_t* sckaddr, - qse_uint16_t port, - qse_aio_ip4addr_t* ip4addr -); - -QSE_EXPORT void qse_aio_sckaddr_initforip6 ( - qse_aio_sckaddr_t* sckaddr, - qse_uint16_t port, - qse_aio_ip6addr_t* ip6addr -); - -QSE_EXPORT void qse_aio_sckaddr_initforeth ( - qse_aio_sckaddr_t* sckaddr, - int ifindex, - qse_aio_ethaddr_t* ethaddr -); - -/* ========================================================================= */ - -QSE_EXPORT qse_aio_dev_sck_t* qse_aio_dev_sck_make ( - qse_aio_t* aio, - qse_size_t xtnsize, - const qse_aio_dev_sck_make_t* info -); - -QSE_EXPORT int qse_aio_dev_sck_bind ( - qse_aio_dev_sck_t* dev, - qse_aio_dev_sck_bind_t* info -); - -QSE_EXPORT int qse_aio_dev_sck_connect ( - qse_aio_dev_sck_t* dev, - qse_aio_dev_sck_connect_t* info -); - -QSE_EXPORT int qse_aio_dev_sck_listen ( - qse_aio_dev_sck_t* dev, - qse_aio_dev_sck_listen_t* info -); - -QSE_EXPORT int qse_aio_dev_sck_write ( - qse_aio_dev_sck_t* dev, - const void* data, - qse_aio_iolen_t len, - void* wrctx, - const qse_aio_sckaddr_t* dstaddr -); - -QSE_EXPORT int qse_aio_dev_sck_timedwrite ( - qse_aio_dev_sck_t* dev, - const void* data, - qse_aio_iolen_t len, - const qse_ntime_t* tmout, - void* wrctx, - const qse_aio_sckaddr_t* dstaddr -); - -#if defined(QSE_AIO_HAVE_INLINE) - -static QSE_INLINE void qse_aio_dev_sck_halt (qse_aio_dev_sck_t* sck) -{ - qse_aio_dev_halt ((qse_aio_dev_t*)sck); -} - -static QSE_INLINE int qse_aio_dev_sck_read (qse_aio_dev_sck_t* sck, int enabled) -{ - return qse_aio_dev_read ((qse_aio_dev_t*)sck, enabled); -} - -#else - -#define qse_aio_dev_sck_halt(sck) qse_aio_dev_halt((qse_aio_dev_t*)sck) -#define qse_aio_dev_sck_read(sck,enabled) qse_aio_dev_read((qse_aio_dev_t*)sck, enabled) - -#endif - - -QSE_EXPORT qse_uint16_t qse_aio_checksumip ( - const void* hdr, - qse_size_t len -); - - -#ifdef __cplusplus -} -#endif - - - - -#endif diff --git a/qse/include/qse/si/aio.h b/qse/include/qse/si/aio.h deleted file mode 100644 index 638c9c01..00000000 --- a/qse/include/qse/si/aio.h +++ /dev/null @@ -1,438 +0,0 @@ -/* - * $Id$ - * - Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _QSE_SI_AIO_H_ -#define _QSE_SI_AIO_H_ - -#include -#include -#include - -#if defined(_WIN32) - typedef qse_uintptr_t qse_aio_syshnd_t; - #define QSE_AIO_SYSHND_INVALID (~(qse_uintptr_t)0) -#else - typedef int qse_aio_syshnd_t; - #define QSE_AIO_SYSHND_INVALID (-1) -#endif - -typedef struct qse_aio_devaddr_t qse_aio_devaddr_t; -struct qse_aio_devaddr_t -{ - int len; - void* ptr; -}; - -/* ========================================================================= */ - -typedef struct qse_aio_t qse_aio_t; -typedef struct qse_aio_dev_t qse_aio_dev_t; -typedef struct qse_aio_dev_mth_t qse_aio_dev_mth_t; -typedef struct qse_aio_dev_evcb_t qse_aio_dev_evcb_t; - -typedef struct qse_aio_wq_t qse_aio_wq_t; -typedef qse_intptr_t qse_aio_iolen_t; /* NOTE: this is a signed type */ - -enum qse_aio_errnum_t -{ - QSE_AIO_ENOERR, - QSE_AIO_ENOIMPL, - QSE_AIO_ESYSERR, - QSE_AIO_EINTERN, - - QSE_AIO_ENOMEM, - QSE_AIO_EINVAL, - QSE_AIO_EEXIST, - QSE_AIO_ENOENT, - QSE_AIO_ENOSUP, /* not supported */ - QSE_AIO_EMFILE, /* too many open files */ - QSE_AIO_ENFILE, - QSE_AIO_EAGAIN, - QSE_AIO_ECONRF, /* connection refused */ - QSE_AIO_ECONRS, /* connection reset */ - QSE_AIO_ENOCAPA, /* no capability */ - QSE_AIO_ETMOUT, /* timed out */ - QSE_AIO_EPERM, /* operation not permitted */ - - QSE_AIO_EDEVMAKE, - QSE_AIO_EDEVERR, - QSE_AIO_EDEVHUP -}; - -typedef enum qse_aio_errnum_t qse_aio_errnum_t; - -enum qse_aio_stopreq_t -{ - QSE_AIO_STOPREQ_NONE = 0, - QSE_AIO_STOPREQ_TERMINATION, - QSE_AIO_STOPREQ_WATCHER_ERROR -}; -typedef enum qse_aio_stopreq_t qse_aio_stopreq_t; - -/* ========================================================================= */ - -#define QSE_AIO_TMRIDX_INVALID ((qse_aio_tmridx_t)-1) - -typedef qse_size_t qse_aio_tmridx_t; - -typedef struct qse_aio_tmrjob_t qse_aio_tmrjob_t; - -typedef void (*qse_aio_tmrjob_handler_t) ( - qse_aio_t* aio, - const qse_ntime_t* now, - qse_aio_tmrjob_t* tmrjob -); - -struct qse_aio_tmrjob_t -{ - void* ctx; - qse_ntime_t when; - qse_aio_tmrjob_handler_t handler; - qse_aio_tmridx_t* idxptr; /* pointer to the index holder */ -}; - -/* ========================================================================= */ - -struct qse_aio_dev_mth_t -{ - /* ------------------------------------------------------------------ */ - /* mandatory. called in qse_aio_makedev() */ - int (*make) (qse_aio_dev_t* dev, void* ctx); - - /* ------------------------------------------------------------------ */ - /* mandatory. called in qse_aio_killdev(). also called in qse_aio_makedev() upon - * failure after make() success. - * - * when 'force' is 0, the return value of -1 causes the device to be a - * zombie. the kill method is called periodically on a zombie device - * until the method returns 0. - * - * when 'force' is 1, the called should not return -1. If it does, the - * method is called once more only with the 'force' value of 2. - * - * when 'force' is 2, the device is destroyed regardless of the return value. - */ - int (*kill) (qse_aio_dev_t* dev, int force); - - /* ------------------------------------------------------------------ */ - qse_aio_syshnd_t (*getsyshnd) (qse_aio_dev_t* dev); /* mandatory. called in qse_aio_makedev() after successful make() */ - - - /* ------------------------------------------------------------------ */ - /* return -1 on failure, 0 if no data is availble, 1 otherwise. - * when returning 1, *len must be sent to the length of data read. - * if *len is set to 0, it's treated as EOF. */ - int (*read) (qse_aio_dev_t* dev, void* data, qse_aio_iolen_t* len, qse_aio_devaddr_t* srcaddr); - - /* ------------------------------------------------------------------ */ - int (*write) (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t* len, const qse_aio_devaddr_t* dstaddr); - - /* ------------------------------------------------------------------ */ - int (*ioctl) (qse_aio_dev_t* dev, int cmd, void* arg); - -}; - -struct qse_aio_dev_evcb_t -{ - /* return -1 on failure. 0 or 1 on success. - * when 0 is returned, it doesn't attempt to perform actual I/O. - * when 1 is returned, it attempts to perform actual I/O. */ - int (*ready) (qse_aio_dev_t* dev, int events); - - /* return -1 on failure, 0 or 1 on success. - * when 0 is returned, the main loop stops the attempt to read more data. - * when 1 is returned, the main loop attempts to read more data without*/ - int (*on_read) (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t len, const qse_aio_devaddr_t* srcaddr); - - /* return -1 on failure, 0 on success. - * wrlen is the length of data written. it is the length of the originally - * posted writing request for a stream device. For a non stream device, it - * may be shorter than the originally posted length. */ - int (*on_write) (qse_aio_dev_t* dev, qse_aio_iolen_t wrlen, void* wrctx, const qse_aio_devaddr_t* dstaddr); -}; - -struct qse_aio_wq_t -{ - qse_aio_wq_t* next; - qse_aio_wq_t* prev; - - qse_aio_iolen_t olen; /* original data length */ - qse_uint8_t* ptr; /* pointer to data */ - qse_aio_iolen_t len; /* remaining data length */ - void* ctx; - qse_aio_dev_t* dev; /* back-pointer to the device */ - - qse_aio_tmridx_t tmridx; - qse_aio_devaddr_t dstaddr; -}; - -#define QSE_AIO_WQ_INIT(wq) ((wq)->next = (wq)->prev = (wq)) -#define QSE_AIO_WQ_TAIL(wq) ((wq)->prev) -#define QSE_AIO_WQ_HEAD(wq) ((wq)->next) -#define QSE_AIO_WQ_ISEMPTY(wq) (QSE_AIO_WQ_HEAD(wq) == (wq)) -#define QSE_AIO_WQ_ISNODE(wq,x) ((wq) != (x)) -#define QSE_AIO_WQ_ISHEAD(wq,x) (QSE_AIO_WQ_HEAD(wq) == (x)) -#define QSE_AIO_WQ_ISTAIL(wq,x) (QSE_AIO_WQ_TAIL(wq) == (x)) - -#define QSE_AIO_WQ_NEXT(x) ((x)->next) -#define QSE_AIO_WQ_PREV(x) ((x)->prev) - -#define QSE_AIO_WQ_LINK(p,x,n) do { \ - qse_aio_wq_t* pp = (p), * nn = (n); \ - (x)->prev = (p); \ - (x)->next = (n); \ - nn->prev = (x); \ - pp->next = (x); \ -} while (0) - -#define QSE_AIO_WQ_UNLINK(x) do { \ - qse_aio_wq_t* pp = (x)->prev, * nn = (x)->next; \ - nn->prev = pp; pp->next = nn; \ -} while (0) - -#define QSE_AIO_WQ_REPL(o,n) do { \ - qse_aio_wq_t* oo = (o), * nn = (n); \ - nn->next = oo->next; \ - nn->next->prev = nn; \ - nn->prev = oo->prev; \ - nn->prev->next = nn; \ -} while (0) - -/* insert an item at the back of the queue */ -/*#define QSE_AIO_WQ_ENQ(wq,x) QSE_AIO_WQ_LINK(QSE_AIO_WQ_TAIL(wq), x, QSE_AIO_WQ_TAIL(wq)->next)*/ -#define QSE_AIO_WQ_ENQ(wq,x) QSE_AIO_WQ_LINK(QSE_AIO_WQ_TAIL(wq), x, wq) - -/* remove an item in the front from the queue */ -#define QSE_AIO_WQ_DEQ(wq) QSE_AIO_WQ_UNLINK(QSE_AIO_WQ_HEAD(wq)) - -#define QSE_AIO_DEV_HEADERS \ - qse_aio_t* aio; \ - qse_size_t dev_size; \ - int dev_capa; \ - qse_aio_dev_mth_t* dev_mth; \ - qse_aio_dev_evcb_t* dev_evcb; \ - qse_aio_wq_t wq; \ - qse_aio_dev_t* dev_prev; \ - qse_aio_dev_t* dev_next - -struct qse_aio_dev_t -{ - QSE_AIO_DEV_HEADERS; -}; - -enum qse_aio_dev_capa_t -{ - QSE_AIO_DEV_CAPA_VIRTUAL = (1 << 0), - QSE_AIO_DEV_CAPA_IN = (1 << 1), - QSE_AIO_DEV_CAPA_OUT = (1 << 2), - /* #QSE_AIO_DEV_CAPA_PRI is meaningful only if #QSE_AIO_DEV_CAPA_IN is set */ - QSE_AIO_DEV_CAPA_PRI = (1 << 3), - QSE_AIO_DEV_CAPA_STREAM = (1 << 4), - QSE_AIO_DEV_CAPA_OUT_QUEUED = (1 << 5), - - /* internal use only. never set this bit to the dev_capa field */ - QSE_AIO_DEV_CAPA_IN_DISABLED = (1 << 9), - QSE_AIO_DEV_CAPA_IN_CLOSED = (1 << 10), - QSE_AIO_DEV_CAPA_OUT_CLOSED = (1 << 11), - QSE_AIO_DEV_CAPA_IN_WATCHED = (1 << 12), - QSE_AIO_DEV_CAPA_OUT_WATCHED = (1 << 13), - QSE_AIO_DEV_CAPA_PRI_WATCHED = (1 << 14), /**< can be set only if QSE_AIO_DEV_CAPA_IN_WATCHED is set */ - - QSE_AIO_DEV_CAPA_ACTIVE = (1 << 15), - QSE_AIO_DEV_CAPA_HALTED = (1 << 16), - QSE_AIO_DEV_CAPA_ZOMBIE = (1 << 17) -}; -typedef enum qse_aio_dev_capa_t qse_aio_dev_capa_t; - -enum qse_aio_dev_watch_cmd_t -{ - QSE_AIO_DEV_WATCH_START, - QSE_AIO_DEV_WATCH_UPDATE, - QSE_AIO_DEV_WATCH_RENEW, /* automatic update */ - QSE_AIO_DEV_WATCH_STOP -}; -typedef enum qse_aio_dev_watch_cmd_t qse_aio_dev_watch_cmd_t; - -enum qse_aio_dev_event_t -{ - QSE_AIO_DEV_EVENT_IN = (1 << 0), - QSE_AIO_DEV_EVENT_OUT = (1 << 1), - - QSE_AIO_DEV_EVENT_PRI = (1 << 2), - QSE_AIO_DEV_EVENT_HUP = (1 << 3), - QSE_AIO_DEV_EVENT_ERR = (1 << 4) -}; -typedef enum qse_aio_dev_event_t qse_aio_dev_event_t; - - -/* ========================================================================= */ - -#ifdef __cplusplus -extern "C" { -#endif - -QSE_EXPORT qse_aio_t* qse_aio_open ( - qse_mmgr_t* mmgr, - qse_size_t xtnsize, - qse_size_t tmrcapa, /**< initial timer capacity */ - qse_aio_errnum_t* errnum -); - -QSE_EXPORT void qse_aio_close ( - qse_aio_t* aio -); - -QSE_EXPORT int qse_aio_init ( - qse_aio_t* aio, - qse_mmgr_t* mmgr, - qse_size_t tmrcapa -); - -QSE_EXPORT void qse_aio_fini ( - qse_aio_t* aio -); - -QSE_EXPORT int qse_aio_exec ( - qse_aio_t* aio -); - -QSE_EXPORT int qse_aio_loop ( - qse_aio_t* aio -); - -QSE_EXPORT void qse_aio_stop ( - qse_aio_t* aio, - qse_aio_stopreq_t stopreq -); - -QSE_EXPORT qse_aio_dev_t* qse_aio_makedev ( - qse_aio_t* aio, - qse_size_t dev_size, - qse_aio_dev_mth_t* dev_mth, - qse_aio_dev_evcb_t* dev_evcb, - void* make_ctx -); - -QSE_EXPORT void qse_aio_killdev ( - qse_aio_t* aio, - qse_aio_dev_t* dev -); - -QSE_EXPORT int qse_aio_dev_ioctl ( - qse_aio_dev_t* dev, - int cmd, - void* arg -); - -QSE_EXPORT int qse_aio_dev_watch ( - qse_aio_dev_t* dev, - qse_aio_dev_watch_cmd_t cmd, - /** 0 or bitwise-ORed of #QSE_AIO_DEV_EVENT_IN and #QSE_AIO_DEV_EVENT_OUT */ - int events -); - -QSE_EXPORT int qse_aio_dev_read ( - qse_aio_dev_t* dev, - int enabled -); - -/** - * The qse_aio_dev_write() function posts a writing request. - * It attempts to write data immediately if there is no pending requests. - * If writing fails, it returns -1. If writing succeeds, it calls the - * on_write callback. If the callback fails, it returns -1. If the callback - * succeeds, it returns 1. If no immediate writing is possible, the request - * is enqueued to a pending request list. If enqueing gets successful, - * it returns 0. otherwise it returns -1. - */ -QSE_EXPORT int qse_aio_dev_write ( - qse_aio_dev_t* dev, - const void* data, - qse_aio_iolen_t len, - void* wrctx, - const qse_aio_devaddr_t* dstaddr -); - - -QSE_EXPORT int qse_aio_dev_timedwrite ( - qse_aio_dev_t* dev, - const void* data, - qse_aio_iolen_t len, - const qse_ntime_t* tmout, - void* wrctx, - const qse_aio_devaddr_t* dstaddr -); - -QSE_EXPORT void qse_aio_dev_halt ( - qse_aio_dev_t* dev -); - -/** - * The qse_aio_instmrjob() function schedules a new event. - * - * \return #QSE_AIO_TMRIDX_INVALID on failure, valid index on success. - */ - -QSE_EXPORT qse_aio_tmridx_t qse_aio_instmrjob ( - qse_aio_t* aio, - const qse_aio_tmrjob_t* job -); - -QSE_EXPORT qse_aio_tmridx_t qse_aio_updtmrjob ( - qse_aio_t* aio, - qse_aio_tmridx_t index, - const qse_aio_tmrjob_t* job -); - -QSE_EXPORT void qse_aio_deltmrjob ( - qse_aio_t* aio, - qse_aio_tmridx_t index -); - -/** - * The qse_aio_gettmrjob() function returns the - * pointer to the registered event at the given index. - */ -QSE_EXPORT qse_aio_tmrjob_t* qse_aio_gettmrjob ( - qse_aio_t* aio, - qse_aio_tmridx_t index -); - -QSE_EXPORT int qse_aio_gettmrjobdeadline ( - qse_aio_t* aio, - qse_aio_tmridx_t index, - qse_ntime_t* deadline -); - -/* ========================================================================= */ - - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/qse/lib/si/Makefile.am b/qse/lib/si/Makefile.am index 0455df40..97d7ec84 100644 --- a/qse/lib/si/Makefile.am +++ b/qse/lib/si/Makefile.am @@ -5,16 +5,11 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/include noinst_HEADERS = \ - aio-prv.h \ fs-prv.h \ glob-imp.h lib_LTLIBRARIES = libqsesi.la libqsesi_la_SOURCES = \ - aio.c \ - aio-pro.c \ - aio-sck.c \ - aio-tmr.c \ cnd.c \ dir.c \ fio.c \ diff --git a/qse/lib/si/Makefile.in b/qse/lib/si/Makefile.in index 9b9c7c61..ca63c01a 100644 --- a/qse/lib/si/Makefile.in +++ b/qse/lib/si/Makefile.in @@ -138,10 +138,8 @@ am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libqsesi_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -am_libqsesi_la_OBJECTS = libqsesi_la-aio.lo libqsesi_la-aio-pro.lo \ - libqsesi_la-aio-sck.lo libqsesi_la-aio-tmr.lo \ - libqsesi_la-cnd.lo libqsesi_la-dir.lo libqsesi_la-fio.lo \ - libqsesi_la-fs.lo libqsesi_la-fs-attr.lo \ +am_libqsesi_la_OBJECTS = libqsesi_la-cnd.lo libqsesi_la-dir.lo \ + libqsesi_la-fio.lo libqsesi_la-fs.lo libqsesi_la-fs-attr.lo \ libqsesi_la-fs-copy.lo libqsesi_la-fs-delete.lo \ libqsesi_la-fs-err.lo libqsesi_la-fs-make.lo \ libqsesi_la-fs-move.lo libqsesi_la-glob.lo libqsesi_la-intr.lo \ @@ -424,16 +422,11 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/include noinst_HEADERS = \ - aio-prv.h \ fs-prv.h \ glob-imp.h lib_LTLIBRARIES = libqsesi.la $(am__append_1) libqsesi_la_SOURCES = \ - aio.c \ - aio-pro.c \ - aio-sck.c \ - aio-tmr.c \ cnd.c \ dir.c \ fio.c \ @@ -564,10 +557,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SocketAddress.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TcpServer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Thread.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-aio-pro.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-aio-sck.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-aio-tmr.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-aio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-cnd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-dir.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesi_la-fio.Plo@am__quote@ @@ -620,34 +609,6 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< -libqsesi_la-aio.lo: aio.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -MT libqsesi_la-aio.lo -MD -MP -MF $(DEPDIR)/libqsesi_la-aio.Tpo -c -o libqsesi_la-aio.lo `test -f 'aio.c' || echo '$(srcdir)/'`aio.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesi_la-aio.Tpo $(DEPDIR)/libqsesi_la-aio.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='aio.c' object='libqsesi_la-aio.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -c -o libqsesi_la-aio.lo `test -f 'aio.c' || echo '$(srcdir)/'`aio.c - -libqsesi_la-aio-pro.lo: aio-pro.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -MT libqsesi_la-aio-pro.lo -MD -MP -MF $(DEPDIR)/libqsesi_la-aio-pro.Tpo -c -o libqsesi_la-aio-pro.lo `test -f 'aio-pro.c' || echo '$(srcdir)/'`aio-pro.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesi_la-aio-pro.Tpo $(DEPDIR)/libqsesi_la-aio-pro.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='aio-pro.c' object='libqsesi_la-aio-pro.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -c -o libqsesi_la-aio-pro.lo `test -f 'aio-pro.c' || echo '$(srcdir)/'`aio-pro.c - -libqsesi_la-aio-sck.lo: aio-sck.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -MT libqsesi_la-aio-sck.lo -MD -MP -MF $(DEPDIR)/libqsesi_la-aio-sck.Tpo -c -o libqsesi_la-aio-sck.lo `test -f 'aio-sck.c' || echo '$(srcdir)/'`aio-sck.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesi_la-aio-sck.Tpo $(DEPDIR)/libqsesi_la-aio-sck.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='aio-sck.c' object='libqsesi_la-aio-sck.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -c -o libqsesi_la-aio-sck.lo `test -f 'aio-sck.c' || echo '$(srcdir)/'`aio-sck.c - -libqsesi_la-aio-tmr.lo: aio-tmr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -MT libqsesi_la-aio-tmr.lo -MD -MP -MF $(DEPDIR)/libqsesi_la-aio-tmr.Tpo -c -o libqsesi_la-aio-tmr.lo `test -f 'aio-tmr.c' || echo '$(srcdir)/'`aio-tmr.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesi_la-aio-tmr.Tpo $(DEPDIR)/libqsesi_la-aio-tmr.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='aio-tmr.c' object='libqsesi_la-aio-tmr.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -c -o libqsesi_la-aio-tmr.lo `test -f 'aio-tmr.c' || echo '$(srcdir)/'`aio-tmr.c - libqsesi_la-cnd.lo: cnd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesi_la_CFLAGS) $(CFLAGS) -MT libqsesi_la-cnd.lo -MD -MP -MF $(DEPDIR)/libqsesi_la-cnd.Tpo -c -o libqsesi_la-cnd.lo `test -f 'cnd.c' || echo '$(srcdir)/'`cnd.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesi_la-cnd.Tpo $(DEPDIR)/libqsesi_la-cnd.Plo diff --git a/qse/lib/si/aio-pro.c b/qse/lib/si/aio-pro.c deleted file mode 100644 index db141065..00000000 --- a/qse/lib/si/aio-pro.c +++ /dev/null @@ -1,853 +0,0 @@ -/* - * $Id$ - * - Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "aio-prv.h" - -#include - -#include -#include -#include -#include -#include - -/* ========================================================================= */ - -struct slave_info_t -{ - qse_aio_dev_pro_make_t* mi; - qse_aio_syshnd_t pfd; - int dev_capa; - qse_aio_dev_pro_sid_t id; -}; - -typedef struct slave_info_t slave_info_t; - -static qse_aio_dev_pro_slave_t* make_slave (qse_aio_t* aio, slave_info_t* si); - -/* ========================================================================= */ - -struct param_t -{ - qse_mchar_t* mcmd; - qse_mchar_t* fixed_argv[4]; - qse_mchar_t** argv; -}; -typedef struct param_t param_t; - -static void free_param (qse_aio_t* aio, param_t* param) -{ - if (param->argv && param->argv != param->fixed_argv) - QSE_MMGR_FREE (aio->mmgr, param->argv); - if (param->mcmd) QSE_MMGR_FREE (aio->mmgr, param->mcmd); - QSE_MEMSET (param, 0, QSE_SIZEOF(*param)); -} - -static int make_param (qse_aio_t* aio, const qse_mchar_t* cmd, int flags, param_t* param) -{ - int fcnt = 0; - qse_mchar_t* mcmd = QSE_NULL; - - QSE_MEMSET (param, 0, QSE_SIZEOF(*param)); - - if (flags & QSE_AIO_DEV_PRO_SHELL) - { - mcmd = (qse_mchar_t*)cmd; - - param->argv = param->fixed_argv; - param->argv[0] = QSE_MT("/bin/sh"); - param->argv[1] = QSE_MT("-c"); - param->argv[2] = mcmd; - param->argv[3] = QSE_NULL; - } - else - { - int i; - qse_mchar_t** argv; - qse_mchar_t* mcmdptr; - - mcmd = qse_mbsdup (cmd, aio->mmgr); - if (!mcmd) - { - aio->errnum = QSE_AIO_ENOMEM; - goto oops; - } - - fcnt = qse_mbsspl (mcmd, QSE_MT(""), QSE_MT('\"'), QSE_MT('\"'), QSE_MT('\\')); - if (fcnt <= 0) - { - /* no field or an error */ - aio->errnum = QSE_AIO_EINVAL; - goto oops; - } - - if (fcnt < QSE_COUNTOF(param->fixed_argv)) - { - param->argv = param->fixed_argv; - } - else - { - param->argv = QSE_MMGR_ALLOC (aio->mmgr, (fcnt + 1) * QSE_SIZEOF(argv[0])); - if (param->argv == QSE_NULL) - { - aio->errnum = QSE_AIO_ENOMEM; - goto oops; - } - } - - mcmdptr = mcmd; - for (i = 0; i < fcnt; i++) - { - param->argv[i] = mcmdptr; - while (*mcmdptr != QSE_MT('\0')) mcmdptr++; - mcmdptr++; - } - param->argv[i] = QSE_NULL; - } - - if (mcmd && mcmd != (qse_mchar_t*)cmd) param->mcmd = mcmd; - return 0; - -oops: - if (mcmd && mcmd != cmd) QSE_MMGR_FREE (aio->mmgr, mcmd); - return -1; -} - -static pid_t standard_fork_and_exec (qse_aio_t* aio, int pfds[], int flags, param_t* param) -{ - pid_t pid; - - pid = fork (); - if (pid == -1) - { - aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - if (pid == 0) - { - /* slave process */ - - qse_aio_syshnd_t devnull = QSE_AIO_SYSHND_INVALID; - -/* TODO: close all uneeded fds */ - - if (flags & QSE_AIO_DEV_PRO_WRITEIN) - { - /* slave should read */ - close (pfds[1]); - pfds[1] = QSE_AIO_SYSHND_INVALID; - - /* let the pipe be standard input */ - if (dup2 (pfds[0], 0) <= -1) goto slave_oops; - - close (pfds[0]); - pfds[0] = QSE_AIO_SYSHND_INVALID; - } - - if (flags & QSE_AIO_DEV_PRO_READOUT) - { - /* slave should write */ - close (pfds[2]); - pfds[2] = QSE_AIO_SYSHND_INVALID; - - if (dup2(pfds[3], 1) == -1) goto slave_oops; - - if (flags & QSE_AIO_DEV_PRO_ERRTOOUT) - { - if (dup2(pfds[3], 2) == -1) goto slave_oops; - } - - close (pfds[3]); - pfds[3] = QSE_AIO_SYSHND_INVALID; - } - - if (flags & QSE_AIO_DEV_PRO_READERR) - { - close (pfds[4]); - pfds[4] = QSE_AIO_SYSHND_INVALID; - - if (dup2(pfds[5], 2) == -1) goto slave_oops; - - if (flags & QSE_AIO_DEV_PRO_OUTTOERR) - { - if (dup2(pfds[5], 1) == -1) goto slave_oops; - } - - close (pfds[5]); - pfds[5] = QSE_AIO_SYSHND_INVALID; - } - - if ((flags & QSE_AIO_DEV_PRO_INTONUL) || - (flags & QSE_AIO_DEV_PRO_OUTTONUL) || - (flags & QSE_AIO_DEV_PRO_ERRTONUL)) - { - #if defined(O_LARGEFILE) - devnull = open (QSE_MT("/dev/null"), O_RDWR | O_LARGEFILE, 0); - #else - devnull = open (QSE_MT("/dev/null"), O_RDWR, 0); - #endif - if (devnull == QSE_AIO_SYSHND_INVALID) goto slave_oops; - } - - execv (param->argv[0], param->argv); - - /* if exec fails, free 'param' parameter which is an inherited pointer */ - free_param (aio, param); - - slave_oops: - if (devnull != QSE_AIO_SYSHND_INVALID) close(devnull); - _exit (128); - } - - /* parent process */ - return pid; -} - -static int dev_pro_make_master (qse_aio_dev_t* dev, void* ctx) -{ - qse_aio_dev_pro_t* rdev = (qse_aio_dev_pro_t*)dev; - qse_aio_dev_pro_make_t* info = (qse_aio_dev_pro_make_t*)ctx; - qse_aio_syshnd_t pfds[6]; - int i, minidx = -1, maxidx = -1; - param_t param; - pid_t pid; - - if (info->flags & QSE_AIO_DEV_PRO_WRITEIN) - { - if (pipe(&pfds[0]) == -1) - { - dev->aio->errnum = qse_aio_syserrtoerrnum(errno); - goto oops; - } - minidx = 0; maxidx = 1; - } - - if (info->flags & QSE_AIO_DEV_PRO_READOUT) - { - if (pipe(&pfds[2]) == -1) - { - dev->aio->errnum = qse_aio_syserrtoerrnum(errno); - goto oops; - } - if (minidx == -1) minidx = 2; - maxidx = 3; - } - - if (info->flags & QSE_AIO_DEV_PRO_READERR) - { - if (pipe(&pfds[4]) == -1) - { - dev->aio->errnum = qse_aio_syserrtoerrnum(errno); - goto oops; - } - if (minidx == -1) minidx = 4; - maxidx = 5; - } - - if (maxidx == -1) - { - dev->aio->errnum = QSE_AIO_EINVAL; - goto oops; - } - - if (make_param (rdev->aio, info->cmd, info->flags, ¶m) <= -1) goto oops; - -/* TODO: more advanced fork and exec .. */ - pid = standard_fork_and_exec (rdev->aio, pfds, info->flags, ¶m); - if (pid <= -1) - { - free_param (rdev->aio, ¶m); - goto oops; - } - - free_param (rdev->aio, ¶m); - rdev->child_pid = pid; - - /* this is the parent process */ - if (info->flags & QSE_AIO_DEV_PRO_WRITEIN) - { - /* - * 012345 - * rw---- - * X - * WRITE => 1 - */ - close (pfds[0]); - pfds[0] = QSE_AIO_SYSHND_INVALID; - - if (qse_aio_makesyshndasync (dev->aio, pfds[1]) <= -1) goto oops; - } - - if (info->flags & QSE_AIO_DEV_PRO_READOUT) - { - /* - * 012345 - * --rw-- - * X - * READ => 2 - */ - close (pfds[3]); - pfds[3] = QSE_AIO_SYSHND_INVALID; - - if (qse_aio_makesyshndasync (dev->aio, pfds[2]) <= -1) goto oops; - } - - if (info->flags & QSE_AIO_DEV_PRO_READERR) - { - /* - * 012345 - * ----rw - * X - * READ => 4 - */ - close (pfds[5]); - pfds[5] = QSE_AIO_SYSHND_INVALID; - - if (qse_aio_makesyshndasync (dev->aio, pfds[4]) <= -1) goto oops; - } - - if (pfds[1] != QSE_AIO_SYSHND_INVALID) - { - /* hand over pfds[2] to the first slave device */ - slave_info_t si; - - si.mi = info; - si.pfd = pfds[1]; - si.dev_capa = QSE_AIO_DEV_CAPA_OUT | QSE_AIO_DEV_CAPA_OUT_QUEUED | QSE_AIO_DEV_CAPA_STREAM; - si.id = QSE_AIO_DEV_PRO_IN; - - rdev->slave[QSE_AIO_DEV_PRO_IN] = make_slave (dev->aio, &si); - if (!rdev->slave[QSE_AIO_DEV_PRO_IN]) goto oops; - - pfds[1] = QSE_AIO_SYSHND_INVALID; - rdev->slave_count++; - } - - if (pfds[2] != QSE_AIO_SYSHND_INVALID) - { - /* hand over pfds[2] to the first slave device */ - slave_info_t si; - - si.mi = info; - si.pfd = pfds[2]; - si.dev_capa = QSE_AIO_DEV_CAPA_IN | QSE_AIO_DEV_CAPA_STREAM; - si.id = QSE_AIO_DEV_PRO_OUT; - - rdev->slave[QSE_AIO_DEV_PRO_OUT] = make_slave (dev->aio, &si); - if (!rdev->slave[QSE_AIO_DEV_PRO_OUT]) goto oops; - - pfds[2] = QSE_AIO_SYSHND_INVALID; - rdev->slave_count++; - } - - if (pfds[4] != QSE_AIO_SYSHND_INVALID) - { - /* hand over pfds[4] to the second slave device */ - slave_info_t si; - - si.mi = info; - si.pfd = pfds[4]; - si.dev_capa = QSE_AIO_DEV_CAPA_IN | QSE_AIO_DEV_CAPA_STREAM; - si.id = QSE_AIO_DEV_PRO_ERR; - - rdev->slave[QSE_AIO_DEV_PRO_ERR] = make_slave (dev->aio, &si); - if (!rdev->slave[QSE_AIO_DEV_PRO_ERR]) goto oops; - - pfds[4] = QSE_AIO_SYSHND_INVALID; - rdev->slave_count++; - } - - for (i = 0; i < QSE_COUNTOF(rdev->slave); i++) - { - if (rdev->slave[i]) rdev->slave[i]->master = rdev; - } - - rdev->dev_capa = QSE_AIO_DEV_CAPA_VIRTUAL; /* the master device doesn't perform I/O */ - rdev->flags = info->flags; - rdev->on_read = info->on_read; - rdev->on_write = info->on_write; - rdev->on_close = info->on_close; - return 0; - -oops: - for (i = minidx; i < maxidx; i++) - { - if (pfds[i] != QSE_AIO_SYSHND_INVALID) close (pfds[i]); - } - - if (rdev->mcmd) - { - QSE_MMGR_FREE (rdev->aio->mmgr, rdev->mcmd); - free_param (rdev->aio, ¶m); - } - - for (i = QSE_COUNTOF(rdev->slave); i > 0; ) - { - i--; - if (rdev->slave[i]) - { - qse_aio_killdev (rdev->aio, (qse_aio_dev_t*)rdev->slave[i]); - rdev->slave[i] = QSE_NULL; - } - } - rdev->slave_count = 0; - - return -1; -} - -static int dev_pro_make_slave (qse_aio_dev_t* dev, void* ctx) -{ - qse_aio_dev_pro_slave_t* rdev = (qse_aio_dev_pro_slave_t*)dev; - slave_info_t* si = (slave_info_t*)ctx; - - rdev->dev_capa = si->dev_capa; - rdev->id = si->id; - rdev->pfd = si->pfd; - /* keep rdev->master to QSE_NULL. it's set to the right master - * device in dev_pro_make() */ - - return 0; -} - -static int dev_pro_kill_master (qse_aio_dev_t* dev, int force) -{ - qse_aio_dev_pro_t* rdev = (qse_aio_dev_pro_t*)dev; - int i, status; - pid_t wpid; - - if (rdev->slave_count > 0) - { - for (i = 0; i < QSE_COUNTOF(rdev->slave); i++) - { - if (rdev->slave[i]) - { - qse_aio_dev_pro_slave_t* sdev = rdev->slave[i]; - - /* nullify the pointer to the slave device - * before calling qse_aio_killdev() on the slave device. - * the slave device can check this pointer to tell from - * self-initiated termination or master-driven termination */ - rdev->slave[i] = QSE_NULL; - - qse_aio_killdev (rdev->aio, (qse_aio_dev_t*)sdev); - } - } - } - - if (rdev->child_pid >= 0) - { - if (!(rdev->flags & QSE_AIO_DEV_PRO_FORGET_CHILD)) - { - int killed = 0; - - await_child: - wpid = waitpid (rdev->child_pid, &status, WNOHANG); - if (wpid == 0) - { - if (force && !killed) - { - if (!(rdev->flags & QSE_AIO_DEV_PRO_FORGET_DIEHARD_CHILD)) - { - kill (rdev->child_pid, SIGKILL); - killed = 1; - goto await_child; - } - } - else - { - /* child process is still alive */ - rdev->aio->errnum = QSE_AIO_EAGAIN; - return -1; /* call me again */ - } - } - - /* wpid == rdev->child_pid => full success - * wpid == -1 && errno == ECHILD => no such process. it's waitpid()'ed by some other part of the program? - * other cases ==> can't really handle properly. forget it by returning success - * no need not worry about EINTR because errno can't have the value when WNOHANG is set. - */ - } - -printf (">>>>>>>>>>>>>>>>>>> REAPED CHILD %d\n", (int)rdev->child_pid); - rdev->child_pid = -1; - } - - if (rdev->on_close) rdev->on_close (rdev, QSE_AIO_DEV_PRO_MASTER); - return 0; -} - -static int dev_pro_kill_slave (qse_aio_dev_t* dev, int force) -{ - qse_aio_dev_pro_slave_t* rdev = (qse_aio_dev_pro_slave_t*)dev; - - if (rdev->master) - { - qse_aio_dev_pro_t* master; - - master = rdev->master; - rdev->master = QSE_NULL; - - /* indicate EOF */ - if (master->on_close) master->on_close (master, rdev->id); - - QSE_ASSERT (master->slave_count > 0); - master->slave_count--; - - if (master->slave[rdev->id]) - { - /* this call is started by the slave device itself. - * if this is the last slave, kill the master also */ - if (master->slave_count <= 0) - { - qse_aio_killdev (rdev->aio, (qse_aio_dev_t*)master); - /* the master pointer is not valid from this point onwards - * as the actual master device object is freed in qse_aio_killdev() */ - } - } - else - { - /* this call is initiated by this slave device itself. - * if it were by the master device, it would be QSE_NULL as - * nullified by the dev_pro_kill() */ - master->slave[rdev->id] = QSE_NULL; - } - } - - if (rdev->pfd != QSE_AIO_SYSHND_INVALID) - { - close (rdev->pfd); - rdev->pfd = QSE_AIO_SYSHND_INVALID; - } - - return 0; -} - -static int dev_pro_read_slave (qse_aio_dev_t* dev, void* buf, qse_aio_iolen_t* len, qse_aio_devaddr_t* srcaddr) -{ - qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev; - ssize_t x; - - x = read (pro->pfd, buf, *len); - if (x <= -1) - { - if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0; /* no data available */ - if (errno == EINTR) return 0; - pro->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - *len = x; - return 1; -} - -static int dev_pro_write_slave (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t* len, const qse_aio_devaddr_t* dstaddr) -{ - qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev; - ssize_t x; - - x = write (pro->pfd, data, *len); - if (x <= -1) - { - if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0; /* no data can be written */ - if (errno == EINTR) return 0; - pro->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - *len = x; - return 1; -} - -static qse_aio_syshnd_t dev_pro_getsyshnd (qse_aio_dev_t* dev) -{ - return QSE_AIO_SYSHND_INVALID; -} - -static qse_aio_syshnd_t dev_pro_getsyshnd_slave (qse_aio_dev_t* dev) -{ - qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev; - return (qse_aio_syshnd_t)pro->pfd; -} - -static int dev_pro_ioctl (qse_aio_dev_t* dev, int cmd, void* arg) -{ - qse_aio_dev_pro_t* rdev = (qse_aio_dev_pro_t*)dev; - - switch (cmd) - { - case QSE_AIO_DEV_PRO_CLOSE: - { - qse_aio_dev_pro_sid_t sid = *(qse_aio_dev_pro_sid_t*)arg; - - if (sid < QSE_AIO_DEV_PRO_IN || sid > QSE_AIO_DEV_PRO_ERR) - { - rdev->aio->errnum = QSE_AIO_EINVAL; - return -1; - } - - if (rdev->slave[sid]) - { - /* unlike dev_pro_kill_master(), i don't nullify rdev->slave[sid]. - * so i treat the closing ioctl as if it's a kill request - * initiated by the slave device itself. */ - qse_aio_killdev (rdev->aio, (qse_aio_dev_t*)rdev->slave[sid]); - } - return 0; - } - - case QSE_AIO_DEV_PRO_KILL_CHILD: - if (rdev->child_pid >= 0) - { - if (kill (rdev->child_pid, SIGKILL) == -1) - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - } - - return 0; - - default: - dev->aio->errnum = QSE_AIO_EINVAL; - return -1; - } -} - -static qse_aio_dev_mth_t dev_pro_methods = -{ - dev_pro_make_master, - dev_pro_kill_master, - dev_pro_getsyshnd, - - QSE_NULL, - QSE_NULL, - dev_pro_ioctl -}; - -static qse_aio_dev_mth_t dev_pro_methods_slave = -{ - dev_pro_make_slave, - dev_pro_kill_slave, - dev_pro_getsyshnd_slave, - - dev_pro_read_slave, - dev_pro_write_slave, - dev_pro_ioctl -}; - -/* ========================================================================= */ - -static int pro_ready (qse_aio_dev_t* dev, int events) -{ - /* virtual device. no I/O */ - dev->aio->errnum = QSE_AIO_EINTERN; - return -1; -} - -static int pro_on_read (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t len, const qse_aio_devaddr_t* srcaddr) -{ - /* virtual device. no I/O */ - dev->aio->errnum = QSE_AIO_EINTERN; - return -1; -} - -static int pro_on_write (qse_aio_dev_t* dev, qse_aio_iolen_t wrlen, void* wrctx, const qse_aio_devaddr_t* dstaddr) -{ - /* virtual device. no I/O */ - dev->aio->errnum = QSE_AIO_EINTERN; - return -1; -} - -static qse_aio_dev_evcb_t dev_pro_event_callbacks = -{ - pro_ready, - pro_on_read, - pro_on_write -}; - -/* ========================================================================= */ - -static int pro_ready_slave (qse_aio_dev_t* dev, int events) -{ - qse_aio_dev_pro_t* pro = (qse_aio_dev_pro_t*)dev; - - if (events & QSE_AIO_DEV_EVENT_ERR) - { - pro->aio->errnum = QSE_AIO_EDEVERR; - return -1; - } - - if (events & QSE_AIO_DEV_EVENT_HUP) - { - if (events & (QSE_AIO_DEV_EVENT_PRI | QSE_AIO_DEV_EVENT_IN | QSE_AIO_DEV_EVENT_OUT)) - { - /* probably half-open? */ - return 1; - } - - pro->aio->errnum = QSE_AIO_EDEVHUP; - return -1; - } - - return 1; /* the device is ok. carry on reading or writing */ -} - - -static int pro_on_read_slave_out (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t len, const qse_aio_devaddr_t* srcaddr) -{ - qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev; - return pro->master->on_read (pro->master, data, len, QSE_AIO_DEV_PRO_OUT); -} - -static int pro_on_read_slave_err (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t len, const qse_aio_devaddr_t* srcaddr) -{ - qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev; - return pro->master->on_read (pro->master, data, len, QSE_AIO_DEV_PRO_ERR); -} - -static int pro_on_write_slave (qse_aio_dev_t* dev, qse_aio_iolen_t wrlen, void* wrctx, const qse_aio_devaddr_t* dstaddr) -{ - qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev; - return pro->master->on_write (pro->master, wrlen, wrctx); -} - -static qse_aio_dev_evcb_t dev_pro_event_callbacks_slave_in = -{ - pro_ready_slave, - QSE_NULL, - pro_on_write_slave -}; - -static qse_aio_dev_evcb_t dev_pro_event_callbacks_slave_out = -{ - pro_ready_slave, - pro_on_read_slave_out, - QSE_NULL -}; - -static qse_aio_dev_evcb_t dev_pro_event_callbacks_slave_err = -{ - pro_ready_slave, - pro_on_read_slave_err, - QSE_NULL -}; - -/* ========================================================================= */ - -static qse_aio_dev_pro_slave_t* make_slave (qse_aio_t* aio, slave_info_t* si) -{ - switch (si->id) - { - case QSE_AIO_DEV_PRO_IN: - return (qse_aio_dev_pro_slave_t*)qse_aio_makedev ( - aio, QSE_SIZEOF(qse_aio_dev_pro_t), - &dev_pro_methods_slave, &dev_pro_event_callbacks_slave_in, si); - - case QSE_AIO_DEV_PRO_OUT: - return (qse_aio_dev_pro_slave_t*)qse_aio_makedev ( - aio, QSE_SIZEOF(qse_aio_dev_pro_t), - &dev_pro_methods_slave, &dev_pro_event_callbacks_slave_out, si); - - case QSE_AIO_DEV_PRO_ERR: - return (qse_aio_dev_pro_slave_t*)qse_aio_makedev ( - aio, QSE_SIZEOF(qse_aio_dev_pro_t), - &dev_pro_methods_slave, &dev_pro_event_callbacks_slave_err, si); - - default: - aio->errnum = QSE_AIO_EINVAL; - return QSE_NULL; - } -} - -qse_aio_dev_pro_t* qse_aio_dev_pro_make (qse_aio_t* aio, qse_size_t xtnsize, const qse_aio_dev_pro_make_t* info) -{ - return (qse_aio_dev_pro_t*)qse_aio_makedev ( - aio, QSE_SIZEOF(qse_aio_dev_pro_t) + xtnsize, - &dev_pro_methods, &dev_pro_event_callbacks, (void*)info); -} - -void qse_aio_dev_pro_kill (qse_aio_dev_pro_t* dev) -{ - qse_aio_killdev (dev->aio, (qse_aio_dev_t*)dev); -} - -int qse_aio_dev_pro_write (qse_aio_dev_pro_t* dev, const void* data, qse_aio_iolen_t dlen, void* wrctx) -{ - if (dev->slave[0]) - { - return qse_aio_dev_write ((qse_aio_dev_t*)dev->slave[0], data, dlen, wrctx, QSE_NULL); - } - else - { - dev->aio->errnum = QSE_AIO_ENOCAPA; /* TODO: is it the right error number? */ - return -1; - } -} - -int qse_aio_dev_pro_timedwrite (qse_aio_dev_pro_t* dev, const void* data, qse_aio_iolen_t dlen, const qse_ntime_t* tmout, void* wrctx) -{ - if (dev->slave[0]) - { - return qse_aio_dev_timedwrite ((qse_aio_dev_t*)dev->slave[0], data, dlen, tmout, wrctx, QSE_NULL); - } - else - { - dev->aio->errnum = QSE_AIO_ENOCAPA; /* TODO: is it the right error number? */ - return -1; - } -} - -int qse_aio_dev_pro_close (qse_aio_dev_pro_t* dev, qse_aio_dev_pro_sid_t sid) -{ - return qse_aio_dev_ioctl ((qse_aio_dev_t*)dev, QSE_AIO_DEV_PRO_CLOSE, &sid); -} - -int qse_aio_dev_pro_killchild (qse_aio_dev_pro_t* dev) -{ - return qse_aio_dev_ioctl ((qse_aio_dev_t*)dev, QSE_AIO_DEV_PRO_KILL_CHILD, QSE_NULL); -} - -#if 0 -qse_aio_dev_pro_t* qse_aio_dev_pro_getdev (qse_aio_dev_pro_t* pro, qse_aio_dev_pro_sid_t sid) -{ - switch (type) - { - case QSE_AIO_DEV_PRO_IN: - return XXX; - - case QSE_AIO_DEV_PRO_OUT: - return XXX; - - case QSE_AIO_DEV_PRO_ERR: - return XXX; - } - - pro->dev->aio = QSE_AIO_EINVAL; - return QSE_NULL; -} -#endif diff --git a/qse/lib/si/aio-prv.h b/qse/lib/si/aio-prv.h deleted file mode 100644 index 42e6c60f..00000000 --- a/qse/lib/si/aio-prv.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * $Id$ - * - Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _QSE_LIB_SI_AIO_PRV_H_ -#define _QSE_LIB_SI_AIO_PRV_H_ - -#include -#include "../cmn/mem-prv.h" - - -typedef struct qse_aio_mux_t qse_aio_mux_t; - -struct qse_aio_t -{ - qse_mmgr_t* mmgr; - - qse_aio_errnum_t errnum; - qse_aio_stopreq_t stopreq; /* stop request to abort qse_aio_loop() */ - - struct - { - qse_aio_dev_t* head; - qse_aio_dev_t* tail; - } actdev; /* active devices */ - - struct - { - qse_aio_dev_t* head; - qse_aio_dev_t* tail; - } hltdev; /* halted devices */ - - struct - { - qse_aio_dev_t* head; - qse_aio_dev_t* tail; - } zmbdev; /* zombie devices */ - - qse_uint8_t bigbuf[65535]; /* TODO: make this dynamic depending on devices added. device may indicate a buffer size required??? */ - - unsigned int renew_watch: 1; - unsigned int in_exec: 1; - - struct - { - qse_size_t capa; - qse_size_t size; - qse_aio_tmrjob_t* jobs; - } tmr; - - /* platform specific fields below */ -#if defined(_WIN32) - HANDLE iocp; -#else - qse_aio_mux_t* mux; -#endif -}; - -#ifdef __cplusplus -extern "C" { -#endif - -int qse_aio_makesyshndasync ( - qse_aio_t* aio, - qse_aio_syshnd_t hnd -); - -qse_aio_errnum_t qse_aio_syserrtoerrnum ( - int no -); - -void qse_aio_cleartmrjobs ( - qse_aio_t* aio -); - -void qse_aio_firetmrjobs ( - qse_aio_t* aio, - const qse_ntime_t* tmbase, - qse_size_t* firecnt -); - -int qse_aio_gettmrtmout ( - qse_aio_t* aio, - const qse_ntime_t* tmbase, - qse_ntime_t* tmout -); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/qse/lib/si/aio-sck.c b/qse/lib/si/aio-sck.c deleted file mode 100644 index a4f2b983..00000000 --- a/qse/lib/si/aio-sck.c +++ /dev/null @@ -1,1712 +0,0 @@ -/* - * $Id$ - * - Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include -#include "aio-prv.h" - -#include - -#include -#include -#include -#include - -#include -#include - -#if defined(HAVE_NETPACKET_PACKET_H) -# include -#endif - -#if defined(HAVE_NET_IF_DL_H) -# include -#endif - - -#if defined(__linux__) -# include -# if defined(HAVE_LINUX_NETFILTER_IPV4_H) -# include /* SO_ORIGINAL_DST */ -# endif -# if !defined(SO_ORIGINAL_DST) -# define SO_ORIGINAL_DST 80 -# endif -# if !defined(IP_TRANSPARENT) -# define IP_TRANSPARENT 19 -# endif -# if !defined(SO_REUSEPORT) -# define SO_REUSEPORT 15 -# endif -#endif - -#if defined(HAVE_OPENSSL_SSL_H) && defined(HAVE_SSL) -# include -# if defined(HAVE_OPENSSL_ERR_H) -# include -# endif -# if defined(HAVE_OPENSSL_ENGINE_H) -# include -# endif -# define USE_SSL -#endif - - -/* ========================================================================= */ -void qse_aio_closeasyncsck (qse_aio_t* aio, qse_aio_sckhnd_t sck) -{ -#if defined(_WIN32) - closesocket (sck); -#else - close (sck); -#endif -} - -int qse_aio_makesckasync (qse_aio_t* aio, qse_aio_sckhnd_t sck) -{ - return qse_aio_makesyshndasync(aio, (qse_aio_syshnd_t)sck); -} - -qse_aio_sckhnd_t qse_aio_openasyncsck (qse_aio_t* aio, int domain, int type, int proto) -{ - qse_aio_sckhnd_t sck; - -#if defined(_WIN32) - sck = WSASocket (domain, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT); - if (sck == QSE_AIO_SCKHND_INVALID) - { - /* qse_aio_seterrnum (dev->aio, QSE_AIO_ESYSERR); or translate errno to aio errnum */ - return QSE_AIO_SCKHND_INVALID; - } -#else - sck = socket (domain, type, proto); - if (sck == QSE_AIO_SCKHND_INVALID) - { - aio->errnum = qse_aio_syserrtoerrnum(errno); - return QSE_AIO_SCKHND_INVALID; - } - -#if defined(FD_CLOEXEC) - { - int flags = fcntl (sck, F_GETFD, 0); - if (fcntl (sck, F_SETFD, flags | FD_CLOEXEC) == -1) - { - aio->errnum = qse_aio_syserrtoerrnum(errno); - return QSE_AIO_SCKHND_INVALID; - } - } -#endif - - if (qse_aio_makesckasync (aio, sck) <= -1) - { - close (sck); - return QSE_AIO_SCKHND_INVALID; - } - -#endif - - return sck; -} - -int qse_aio_getsckaddrinfo (qse_aio_t* aio, const qse_aio_sckaddr_t* addr, qse_aio_scklen_t* len, qse_aio_sckfam_t* family) -{ - struct sockaddr* saddr = (struct sockaddr*)addr; - - switch (saddr->sa_family) - { - case AF_INET: - if (len) *len = QSE_SIZEOF(struct sockaddr_in); - if (family) *family = AF_INET; - return 0; - - case AF_INET6: - if (len) *len = QSE_SIZEOF(struct sockaddr_in6); - if (family) *family = AF_INET6; - return 0; - - #if defined(AF_PACKET) && (QSE_SIZEOF_STRUCT_SOCKADDR_LL > 0) - case AF_PACKET: - if (len) *len = QSE_SIZEOF(struct sockaddr_ll); - if (family) *family = AF_PACKET; - return 0; - #elif defined(AF_LINK) && (QSE_SIZEOF_STRUCT_SOCKADDR_DL > 0) - case AF_LINK: - if (len) *len = QSE_SIZEOF(struct sockaddr_dl); - if (family) *family = AF_LINK; - return 0; - #endif - - /* TODO: more address type */ - } - - aio->errnum = QSE_AIO_EINVAL; - return -1; -} - -qse_uint16_t qse_aio_getsckaddrport (const qse_aio_sckaddr_t* addr) -{ - struct sockaddr* saddr = (struct sockaddr*)addr; - - switch (saddr->sa_family) - { - case AF_INET: - return qse_ntoh16(((struct sockaddr_in*)addr)->sin_port); - - case AF_INET6: - return qse_ntoh16(((struct sockaddr_in6*)addr)->sin6_port); - } - - return 0; -} - -int qse_aio_getsckaddrifindex (const qse_aio_sckaddr_t* addr) -{ - struct sockaddr* saddr = (struct sockaddr*)addr; - -#if defined(AF_PACKET) && (QSE_SIZEOF_STRUCT_SOCKADDR_LL > 0) - if (saddr->sa_family == AF_PACKET) - { - return ((struct sockaddr_ll*)addr)->sll_ifindex; - } - -#elif defined(AF_LINK) && (QSE_SIZEOF_STRUCT_SOCKADDR_DL > 0) - if (saddr->sa_family == AF_LINK) - { - return ((struct sockaddr_dl*)addr)->sdl_index; - } -#endif - - return 0; -} - -int qse_aio_equalsckaddrs (qse_aio_t* aio, const qse_aio_sckaddr_t* addr1, const qse_aio_sckaddr_t* addr2) -{ - qse_aio_sckfam_t fam1, fam2; - qse_aio_scklen_t len1, len2; - - qse_aio_getsckaddrinfo (aio, addr1, &len1, &fam1); - qse_aio_getsckaddrinfo (aio, addr2, &len2, &fam2); - return fam1 == fam2 && len1 == len2 && QSE_MEMCMP (addr1, addr2, len1) == 0; -} - -/* ========================================================================= */ - -void qse_aio_sckaddr_initforip4 (qse_aio_sckaddr_t* sckaddr, qse_uint16_t port, qse_aio_ip4addr_t* ip4addr) -{ - struct sockaddr_in* sin = (struct sockaddr_in*)sckaddr; - - QSE_MEMSET (sin, 0, QSE_SIZEOF(*sin)); - sin->sin_family = AF_INET; - sin->sin_port = qse_hton16(port); - if (ip4addr) QSE_MEMCPY (&sin->sin_addr, ip4addr, QSE_AIO_IP4ADDR_LEN); -} - -void qse_aio_sckaddr_initforip6 (qse_aio_sckaddr_t* sckaddr, qse_uint16_t port, qse_aio_ip6addr_t* ip6addr) -{ - struct sockaddr_in6* sin = (struct sockaddr_in6*)sckaddr; - -/* TODO: include sin6_scope_id */ - QSE_MEMSET (sin, 0, QSE_SIZEOF(*sin)); - sin->sin6_family = AF_INET; - sin->sin6_port = qse_hton16(port); - if (ip6addr) QSE_MEMCPY (&sin->sin6_addr, ip6addr, QSE_AIO_IP6ADDR_LEN); -} - -void qse_aio_sckaddr_initforeth (qse_aio_sckaddr_t* sckaddr, int ifindex, qse_aio_ethaddr_t* ethaddr) -{ -#if defined(AF_PACKET) && (QSE_SIZEOF_STRUCT_SOCKADDR_LL > 0) - struct sockaddr_ll* sll = (struct sockaddr_ll*)sckaddr; - QSE_MEMSET (sll, 0, QSE_SIZEOF(*sll)); - sll->sll_family = AF_PACKET; - sll->sll_ifindex = ifindex; - if (ethaddr) - { - sll->sll_halen = QSE_AIO_ETHADDR_LEN; - QSE_MEMCPY (sll->sll_addr, ethaddr, QSE_AIO_ETHADDR_LEN); - } - -#elif defined(AF_LINK) && (QSE_SIZEOF_STRUCT_SOCKADDR_DL > 0) - struct sockaddr_dl* sll = (struct sockaddr_dl*)sckaddr; - QSE_MEMSET (sll, 0, QSE_SIZEOF(*sll)); - sll->sdl_family = AF_LINK; - sll->sdl_index = ifindex; - if (ethaddr) - { - sll->sdl_alen = QSE_AIO_ETHADDR_LEN; - QSE_MEMCPY (sll->sdl_data, ethaddr, QSE_AIO_ETHADDR_LEN); - } -#else -# error UNSUPPORTED DATALINK SOCKET ADDRESS -#endif -} - -/* ========================================================================= */ - -static qse_aio_devaddr_t* sckaddr_to_devaddr (qse_aio_dev_sck_t* dev, const qse_aio_sckaddr_t* sckaddr, qse_aio_devaddr_t* devaddr) -{ - if (sckaddr) - { - qse_aio_scklen_t len; - - qse_aio_getsckaddrinfo (dev->aio, sckaddr, &len, QSE_NULL); - devaddr->ptr = (void*)sckaddr; - devaddr->len = len; - return devaddr; - } - - return QSE_NULL; -} - -static QSE_INLINE qse_aio_sckaddr_t* devaddr_to_sckaddr (qse_aio_dev_sck_t* dev, const qse_aio_devaddr_t* devaddr, qse_aio_sckaddr_t* sckaddr) -{ - return (qse_aio_sckaddr_t*)devaddr->ptr; -} - -/* ========================================================================= */ - -#define IS_STATEFUL(sck) ((sck)->dev_capa & QSE_AIO_DEV_CAPA_STREAM) - -struct sck_type_map_t -{ - int domain; - int type; - int proto; - int extra_dev_capa; -}; - -#define PROTO_ETHARP QSE_CONST_HTON16(QSE_AIO_ETHHDR_PROTO_ARP) - -static struct sck_type_map_t sck_type_map[] = -{ - /* QSE_AIO_DEV_SCK_TCP4 */ - { AF_INET, SOCK_STREAM, 0, QSE_AIO_DEV_CAPA_STREAM | QSE_AIO_DEV_CAPA_OUT_QUEUED }, - - /* QSE_AIO_DEV_SCK_TCP6 */ - { AF_INET6, SOCK_STREAM, 0, QSE_AIO_DEV_CAPA_STREAM | QSE_AIO_DEV_CAPA_OUT_QUEUED }, - - /* QSE_AIO_DEV_SCK_UPD4 */ - { AF_INET, SOCK_DGRAM, 0, 0 }, - - /* QSE_AIO_DEV_SCK_UDP6 */ - { AF_INET6, SOCK_DGRAM, 0, 0 }, - - -#if defined(AF_PACKET) && (QSE_SIZEOF_STRUCT_SOCKADDR_LL > 0) - /* QSE_AIO_DEV_SCK_ARP - Ethernet type is 2 bytes long. Protocol must be specified in the network byte order */ - { AF_PACKET, SOCK_RAW, PROTO_ETHARP, 0 }, - - /* QSE_AIO_DEV_SCK_DGRAM */ - { AF_PACKET, SOCK_DGRAM, PROTO_ETHARP, 0 }, - -#elif defined(AF_LINK) && (QSE_SIZEOF_STRUCT_SOCKADDR_DL > 0) - /* QSE_AIO_DEV_SCK_ARP */ - { AF_LINK, SOCK_RAW, PROTO_ETHARP, 0 }, - - /* QSE_AIO_DEV_SCK_DGRAM */ - { AF_LINK, SOCK_DGRAM, PROTO_ETHARP, 0 }, -#else - { -1, 0, 0, 0 }, - { -1, 0, 0, 0 }, -#endif - - /* QSE_AIO_DEV_SCK_ICMP4 - IP protocol field is 1 byte only. no byte order conversion is needed */ - { AF_INET, SOCK_RAW, IPPROTO_ICMP, 0 }, - - /* QSE_AIO_DEV_SCK_ICMP6 - IP protocol field is 1 byte only. no byte order conversion is needed */ - { AF_INET6, SOCK_RAW, IPPROTO_ICMP, 0 } -}; - -/* ======================================================================== */ - -static void connect_timedout (qse_aio_t* aio, const qse_ntime_t* now, qse_aio_tmrjob_t* job) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)job->ctx; - - QSE_ASSERT (IS_STATEFUL(rdev)); - - if (rdev->state & QSE_AIO_DEV_SCK_CONNECTING) - { - /* the state check for QSE_AIO_DEV_TCP_CONNECTING is actually redundant - * as it must not be fired after it gets connected. the timer job - * doesn't need to be deleted when it gets connected for this check - * here. this libarary, however, deletes the job when it gets - * connected. */ - qse_aio_dev_sck_halt (rdev); - } -} - -static void ssl_accept_timedout (qse_aio_t* aio, const qse_ntime_t* now, qse_aio_tmrjob_t* job) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)job->ctx; - - QSE_ASSERT (IS_STATEFUL(rdev)); - - if (rdev->state & QSE_AIO_DEV_SCK_ACCEPTING_SSL) - { - qse_aio_dev_sck_halt(rdev); - } -} - -static void ssl_connect_timedout (qse_aio_t* aio, const qse_ntime_t* now, qse_aio_tmrjob_t* job) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)job->ctx; - - QSE_ASSERT (IS_STATEFUL(rdev)); - - if (rdev->state & QSE_AIO_DEV_SCK_CONNECTING_SSL) - { - qse_aio_dev_sck_halt(rdev); - } -} - -static int schedule_timer_job_at (qse_aio_dev_sck_t* dev, const qse_ntime_t* fire_at, qse_aio_tmrjob_handler_t handler) -{ - qse_aio_tmrjob_t tmrjob; - - QSE_MEMSET (&tmrjob, 0, QSE_SIZEOF(tmrjob)); - tmrjob.ctx = dev; - tmrjob.when = *fire_at; - - tmrjob.handler = handler; - tmrjob.idxptr = &dev->tmrjob_index; - - QSE_ASSERT (dev->tmrjob_index == QSE_AIO_TMRIDX_INVALID); - dev->tmrjob_index = qse_aio_instmrjob (dev->aio, &tmrjob); - return dev->tmrjob_index == QSE_AIO_TMRIDX_INVALID? -1: 0; -} - -static int schedule_timer_job_after (qse_aio_dev_sck_t* dev, const qse_ntime_t* fire_after, qse_aio_tmrjob_handler_t handler) -{ - qse_ntime_t fire_at; - - QSE_ASSERT (qse_ispostime(fire_after)); - - qse_gettime (&fire_at); - qse_addtime (&fire_at, fire_after, &fire_at); - - return schedule_timer_job_at (dev, &fire_at, handler); -} - -/* ======================================================================== */ - -static int dev_sck_make (qse_aio_dev_t* dev, void* ctx) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - qse_aio_dev_sck_make_t* arg = (qse_aio_dev_sck_make_t*)ctx; - - QSE_ASSERT (arg->type >= 0 && arg->type < QSE_COUNTOF(sck_type_map)); - - if (sck_type_map[arg->type].domain <= -1) - { - dev->aio->errnum = QSE_AIO_ENOIMPL; - return -1; - } - - rdev->sck = qse_aio_openasyncsck (dev->aio, sck_type_map[arg->type].domain, sck_type_map[arg->type].type, sck_type_map[arg->type].proto); - if (rdev->sck == QSE_AIO_SCKHND_INVALID) goto oops; - - rdev->dev_capa = QSE_AIO_DEV_CAPA_IN | QSE_AIO_DEV_CAPA_OUT | sck_type_map[arg->type].extra_dev_capa; - rdev->on_write = arg->on_write; - rdev->on_read = arg->on_read; - rdev->on_disconnect = arg->on_disconnect; - rdev->type = arg->type; - rdev->tmrjob_index = QSE_AIO_TMRIDX_INVALID; - - return 0; - -oops: - if (rdev->sck != QSE_AIO_SCKHND_INVALID) - { - qse_aio_closeasyncsck (rdev->aio, rdev->sck); - rdev->sck = QSE_AIO_SCKHND_INVALID; - } - return -1; -} - -static int dev_sck_make_client (qse_aio_dev_t* dev, void* ctx) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - qse_aio_syshnd_t* sck = (qse_aio_syshnd_t*)ctx; - - /* nothing special is done here except setting the socket handle. - * most of the initialization is done by the listening socket device - * after a client socket has been created. */ - - rdev->sck = *sck; - rdev->tmrjob_index = QSE_AIO_TMRIDX_INVALID; - - if (qse_aio_makesckasync (rdev->aio, rdev->sck) <= -1) return -1; -#if defined(FD_CLOEXEC) - { - int flags = fcntl (rdev->sck, F_GETFD, 0); - if (fcntl (rdev->sck, F_SETFD, flags | FD_CLOEXEC) == -1) - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - } -#endif - - return 0; -} - -static int dev_sck_kill (qse_aio_dev_t* dev, int force) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - - if (IS_STATEFUL(rdev)) - { - /*if (QSE_AIO_DEV_SCK_GET_PROGRESS(rdev)) - {*/ - /* for QSE_AIO_DEV_SCK_CONNECTING, QSE_AIO_DEV_SCK_CONNECTING_SSL, and QSE_AIO_DEV_ACCEPTING_SSL - * on_disconnect() is called without corresponding on_connect() */ - if (rdev->on_disconnect) rdev->on_disconnect (rdev); - /*}*/ - - if (rdev->tmrjob_index != QSE_AIO_TMRIDX_INVALID) - { - qse_aio_deltmrjob (dev->aio, rdev->tmrjob_index); - QSE_ASSERT (rdev->tmrjob_index == QSE_AIO_TMRIDX_INVALID); - } - } - else - { - QSE_ASSERT (rdev->state == 0); - QSE_ASSERT (rdev->tmrjob_index == QSE_AIO_TMRIDX_INVALID); - - if (rdev->on_disconnect) rdev->on_disconnect (rdev); - } - -#if defined(USE_SSL) - if (rdev->ssl) - { - SSL_shutdown ((SSL*)rdev->ssl); /* is this needed? */ - SSL_free ((SSL*)rdev->ssl); - rdev->ssl = QSE_NULL; - } - if (!(rdev->state & (QSE_AIO_DEV_SCK_ACCEPTED | QSE_AIO_DEV_SCK_ACCEPTING_SSL)) && rdev->ssl_ctx) - { - SSL_CTX_free ((SSL_CTX*)rdev->ssl_ctx); - rdev->ssl_ctx = QSE_NULL; - } -#endif - - if (rdev->sck != QSE_AIO_SCKHND_INVALID) - { - qse_aio_closeasyncsck (rdev->aio, rdev->sck); - rdev->sck = QSE_AIO_SCKHND_INVALID; - } - - return 0; -} - -static qse_aio_syshnd_t dev_sck_getsyshnd (qse_aio_dev_t* dev) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - return (qse_aio_syshnd_t)rdev->sck; -} - -static int dev_sck_read_stateful (qse_aio_dev_t* dev, void* buf, qse_aio_iolen_t* len, qse_aio_devaddr_t* srcaddr) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - -#if defined(USE_SSL) - if (rdev->ssl) - { - int x; - - x = SSL_read ((SSL*)rdev->ssl, buf, *len); - if (x <= -1) - { - int err = SSL_get_error ((SSL*)rdev->ssl, x); - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) return 0; - rdev->aio->errnum = QSE_AIO_ESYSERR; - return -1; - } - - *len = x; - } - else - { -#endif - ssize_t x; - - x = recv (rdev->sck, buf, *len, 0); - if (x == -1) - { - if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0; /* no data available */ - if (errno == EINTR) return 0; - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - *len = x; -#if defined(USE_SSL) - } -#endif - return 1; -} - -static int dev_sck_read_stateless (qse_aio_dev_t* dev, void* buf, qse_aio_iolen_t* len, qse_aio_devaddr_t* srcaddr) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - qse_aio_scklen_t srcaddrlen; - ssize_t x; - - srcaddrlen = QSE_SIZEOF(rdev->remoteaddr); - x = recvfrom (rdev->sck, buf, *len, 0, (struct sockaddr*)&rdev->remoteaddr, &srcaddrlen); - if (x <= -1) - { - if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0; /* no data available */ - if (errno == EINTR) return 0; - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - srcaddr->ptr = &rdev->remoteaddr; - srcaddr->len = srcaddrlen; - - *len = x; - return 1; -} - - -static int dev_sck_write_stateful (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t* len, const qse_aio_devaddr_t* dstaddr) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - -#if defined(USE_SSL) - if (rdev->ssl) - { - int x; - - if (*len <= 0) - { - /* it's a writing finish indicator. close the writing end of - * the socket, probably leaving it in the half-closed state */ - if (SSL_shutdown ((SSL*)rdev->ssl) == -1) - { - rdev->aio->errnum = QSE_AIO_ESYSERR; - return -1; - } - - return 1; - } - - x = SSL_write ((SSL*)rdev->ssl, data, *len); - if (x <= -1) - { - int err = SSL_get_error ((SSL*)rdev->ssl, x); - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) return 0; - rdev->aio->errnum = QSE_AIO_ESYSERR; - return -1; - } - - *len = x; - } - else - { -#endif - ssize_t x; - int flags = 0; - - if (*len <= 0) - { - /* it's a writing finish indicator. close the writing end of - * the socket, probably leaving it in the half-closed state */ - if (shutdown (rdev->sck, SHUT_WR) == -1) - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - return 1; - } - - /* TODO: flags MSG_DONTROUTE, MSG_DONTWAIT, MSG_MORE, MSG_OOB, MSG_NOSIGNAL */ - #if defined(MSG_NOSIGNAL) - flags |= MSG_NOSIGNAL; - #endif - x = send (rdev->sck, data, *len, flags); - if (x == -1) - { - if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0; /* no data can be written */ - if (errno == EINTR) return 0; - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - *len = x; -#if defined(USE_SSL) - } -#endif - return 1; -} - -static int dev_sck_write_stateless (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t* len, const qse_aio_devaddr_t* dstaddr) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - ssize_t x; - - x = sendto (rdev->sck, data, *len, 0, dstaddr->ptr, dstaddr->len); - if (x <= -1) - { - if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0; /* no data can be written */ - if (errno == EINTR) return 0; - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - *len = x; - return 1; -} - -#if defined(USE_SSL) - -static int do_ssl (qse_aio_dev_sck_t* dev, int (*ssl_func)(SSL*)) -{ - int ret; - int watcher_cmd; - int watcher_events; - - QSE_ASSERT (dev->ssl_ctx); - - if (!dev->ssl) - { - SSL* ssl; - - ssl = SSL_new (dev->ssl_ctx); - if (!ssl) - { - dev->aio->errnum = QSE_AIO_ESYSERR; - return -1; - } - - if (SSL_set_fd (ssl, dev->sck) == 0) - { - dev->aio->errnum = QSE_AIO_ESYSERR; - return -1; - } - - SSL_set_read_ahead (ssl, 0); - - dev->ssl = ssl; - } - - watcher_cmd = QSE_AIO_DEV_WATCH_RENEW; - watcher_events = 0; - - ret = ssl_func ((SSL*)dev->ssl); - if (ret <= 0) - { - int err = SSL_get_error (dev->ssl, ret); - if (err == SSL_ERROR_WANT_READ) - { - /* handshaking isn't complete */ - ret = 0; - } - else if (err == SSL_ERROR_WANT_WRITE) - { - /* handshaking isn't complete */ - watcher_cmd = QSE_AIO_DEV_WATCH_UPDATE; - watcher_events = QSE_AIO_DEV_EVENT_IN | QSE_AIO_DEV_EVENT_OUT; - ret = 0; - } - else - { - dev->aio->errnum = QSE_AIO_ESYSERR; - ret = -1; - } - } - else - { - ret = 1; /* accepted */ - } - - if (qse_aio_dev_watch ((qse_aio_dev_t*)dev, watcher_cmd, watcher_events) <= -1) - { - qse_aio_stop (dev->aio, QSE_AIO_STOPREQ_WATCHER_ERROR); - ret = -1; - } - - return ret; -} - -static QSE_INLINE int connect_ssl (qse_aio_dev_sck_t* dev) -{ - return do_ssl (dev, SSL_connect); -} - -static QSE_INLINE int accept_ssl (qse_aio_dev_sck_t* dev) -{ - return do_ssl (dev, SSL_accept); -} -#endif - -static int dev_sck_ioctl (qse_aio_dev_t* dev, int cmd, void* arg) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - - switch (cmd) - { - case QSE_AIO_DEV_SCK_BIND: - { - qse_aio_dev_sck_bind_t* bnd = (qse_aio_dev_sck_bind_t*)arg; - struct sockaddr* sa = (struct sockaddr*)&bnd->localaddr; - qse_aio_scklen_t sl; - qse_aio_sckfam_t fam; - int x; - #if defined(USE_SSL) - SSL_CTX* ssl_ctx = QSE_NULL; - #endif - if (QSE_AIO_DEV_SCK_GET_PROGRESS(rdev)) - { - /* can't bind again */ - rdev->aio->errnum = QSE_AIO_EPERM; - return -1; - } - - if (bnd->options & QSE_AIO_DEV_SCK_BIND_BROADCAST) - { - int v = 1; - if (setsockopt (rdev->sck, SOL_SOCKET, SO_BROADCAST, &v, QSE_SIZEOF(v)) == -1) - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - } - - if (bnd->options & QSE_AIO_DEV_SCK_BIND_REUSEADDR) - { - #if defined(SO_REUSEADDR) - int v = 1; - if (setsockopt (rdev->sck, SOL_SOCKET, SO_REUSEADDR, &v, QSE_SIZEOF(v)) == -1) - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - #else - rdev->aio->errnum = QSE_AIO_ENOIMPL; - return -1; - #endif - } - - if (bnd->options & QSE_AIO_DEV_SCK_BIND_REUSEPORT) - { - #if defined(SO_REUSEPORT) - int v = 1; - if (setsockopt (rdev->sck, SOL_SOCKET, SO_REUSEPORT, &v, QSE_SIZEOF(v)) == -1) - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - #else - rdev->aio->errnum = QSE_AIO_ENOIMPL; - return -1; - #endif - } - - if (bnd->options & QSE_AIO_DEV_SCK_BIND_TRANSPARENT) - { - #if defined(IP_TRANSPARENT) - int v = 1; - if (setsockopt (rdev->sck, SOL_IP, IP_TRANSPARENT, &v, QSE_SIZEOF(v)) == -1) - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - #else - rdev->aio->errnum = QSE_AIO_ENOIMPL; - return -1; - #endif - } - - #if defined(USE_SSL) - if (rdev->ssl_ctx) - { - #if defined(USE_SSL) - SSL_CTX_free (rdev->ssl_ctx); - #endif - rdev->ssl_ctx = QSE_NULL; - - if (rdev->ssl) - { - #if defined(USE_SSL) - SSL_free (rdev->ssl); - #endif - rdev->ssl = QSE_NULL; - } - } - #endif - - if (bnd->options & QSE_AIO_DEV_SCK_BIND_SSL) - { - #if defined(USE_SSL) - if (!bnd->ssl_certfile || !bnd->ssl_keyfile) - { - rdev->aio->errnum = QSE_AIO_EINVAL; - return -1; - } - - ssl_ctx = SSL_CTX_new (SSLv23_server_method()); - if (!ssl_ctx) - { - rdev->aio->errnum = QSE_AIO_ESYSERR; - return -1; - } - - if (SSL_CTX_use_certificate_file (ssl_ctx, bnd->ssl_certfile, SSL_FILETYPE_PEM) == 0 || - SSL_CTX_use_PrivateKey_file (ssl_ctx, bnd->ssl_keyfile, SSL_FILETYPE_PEM) == 0 || - SSL_CTX_check_private_key (ssl_ctx) == 0 /*|| - SSL_CTX_use_certificate_chain_file (ssl_ctx, bnd->chainfile) == 0*/) - { - SSL_CTX_free (ssl_ctx); - rdev->aio->errnum = QSE_AIO_ESYSERR; - return -1; - } - - SSL_CTX_set_read_ahead (ssl_ctx, 0); - SSL_CTX_set_mode (ssl_ctx, SSL_CTX_get_mode(ssl_ctx) | - /*SSL_MODE_ENABLE_PARTIAL_WRITE |*/ - SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - - SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2); /* no outdated SSLv2 by default */ - - rdev->tmout = bnd->accept_tmout; - #else - rdev->aio->errnum = QSE_AIO_ENOIMPL; - return -1; - #endif - } - - if (qse_aio_getsckaddrinfo (dev->aio, &bnd->localaddr, &sl, &fam) <= -1) return -1; - - x = bind (rdev->sck, sa, sl); - if (x == -1) - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - #if defined(USE_SSL) - if (ssl_ctx) SSL_CTX_free (ssl_ctx); - #endif - return -1; - } - - rdev->localaddr = bnd->localaddr; - - #if defined(USE_SSL) - rdev->ssl_ctx = ssl_ctx; - #endif - - return 0; - } - - case QSE_AIO_DEV_SCK_CONNECT: - { - qse_aio_dev_sck_connect_t* conn = (qse_aio_dev_sck_connect_t*)arg; - struct sockaddr* sa = (struct sockaddr*)&conn->remoteaddr; - qse_aio_scklen_t sl; - qse_aio_sckaddr_t localaddr; - int x; - #if defined(USE_SSL) - SSL_CTX* ssl_ctx = QSE_NULL; - #endif - - if (QSE_AIO_DEV_SCK_GET_PROGRESS(rdev)) - { - /* can't connect again */ - rdev->aio->errnum = QSE_AIO_EPERM; - return -1; - } - - if (!IS_STATEFUL(rdev)) - { - dev->aio->errnum = QSE_AIO_ENOCAPA; - return -1; - } - - if (sa->sa_family == AF_INET) sl = QSE_SIZEOF(struct sockaddr_in); - else if (sa->sa_family == AF_INET6) sl = QSE_SIZEOF(struct sockaddr_in6); - else - { - dev->aio->errnum = QSE_AIO_EINVAL; - return -1; - } - - #if defined(USE_SSL) - if (rdev->ssl_ctx) - { - if (rdev->ssl) - { - SSL_free (rdev->ssl); - rdev->ssl = QSE_NULL; - } - - SSL_CTX_free (rdev->ssl_ctx); - rdev->ssl_ctx = QSE_NULL; - } - - if (conn->options & QSE_AIO_DEV_SCK_CONNECT_SSL) - { - ssl_ctx = SSL_CTX_new(SSLv23_client_method()); - if (!ssl_ctx) - { - rdev->aio->errnum = QSE_AIO_ESYSERR; - return -1; - } - - SSL_CTX_set_read_ahead (ssl_ctx, 0); - SSL_CTX_set_mode (ssl_ctx, SSL_CTX_get_mode(ssl_ctx) | - /* SSL_MODE_ENABLE_PARTIAL_WRITE | */ - SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - } - #endif -/*{ -int flags = fcntl (rdev->sck, F_GETFL); -fcntl (rdev->sck, F_SETFL, flags & ~O_NONBLOCK); -}*/ - - /* the socket is already non-blocking */ - x = connect (rdev->sck, sa, sl); -/*{ -int flags = fcntl (rdev->sck, F_GETFL); -fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK); -}*/ - if (x == -1) - { - if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) - { - if (qse_aio_dev_watch ((qse_aio_dev_t*)rdev, QSE_AIO_DEV_WATCH_UPDATE, QSE_AIO_DEV_EVENT_IN | QSE_AIO_DEV_EVENT_OUT) <= -1) - { - /* watcher update failure. it's critical */ - qse_aio_stop (rdev->aio, QSE_AIO_STOPREQ_WATCHER_ERROR); - goto oops_connect; - } - else - { - qse_inittime (&rdev->tmout, 0, 0); /* just in case */ - - if (qse_ispostime(&conn->connect_tmout)) - { - if (schedule_timer_job_after (rdev, &conn->connect_tmout, connect_timedout) <= -1) - { - goto oops_connect; - } - else - { - /* update rdev->tmout to the deadline of the connect timeout job */ - QSE_ASSERT (rdev->tmrjob_index != QSE_AIO_TMRIDX_INVALID); - qse_aio_gettmrjobdeadline (rdev->aio, rdev->tmrjob_index, &rdev->tmout); - } - } - - rdev->remoteaddr = conn->remoteaddr; - rdev->on_connect = conn->on_connect; - #if defined(USE_SSL) - rdev->ssl_ctx = ssl_ctx; - #endif - QSE_AIO_DEV_SCK_SET_PROGRESS (rdev, QSE_AIO_DEV_SCK_CONNECTING); - return 0; - } - } - - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - - oops_connect: - if (qse_aio_dev_watch ((qse_aio_dev_t*)rdev, QSE_AIO_DEV_WATCH_UPDATE, QSE_AIO_DEV_EVENT_IN) <= -1) - { - /* watcher update failure. it's critical */ - qse_aio_stop (rdev->aio, QSE_AIO_STOPREQ_WATCHER_ERROR); - } - - #if defined(USE_SSL) - if (ssl_ctx) SSL_CTX_free (ssl_ctx); - #endif - return -1; - } - else - { - /* connected immediately */ - rdev->remoteaddr = conn->remoteaddr; - rdev->on_connect = conn->on_connect; - - sl = QSE_SIZEOF(localaddr); - if (getsockname (rdev->sck, (struct sockaddr*)&localaddr, &sl) == 0) rdev->localaddr = localaddr; - - #if defined(USE_SSL) - if (ssl_ctx) - { - int x; - rdev->ssl_ctx = ssl_ctx; - - x = connect_ssl (rdev); - if (x <= -1) - { - SSL_CTX_free (rdev->ssl_ctx); - rdev->ssl_ctx = QSE_NULL; - - QSE_ASSERT (rdev->ssl == QSE_NULL); - return -1; - } - if (x == 0) - { - QSE_ASSERT (rdev->tmrjob_index == QSE_AIO_TMRIDX_INVALID); - qse_inittime (&rdev->tmout, 0, 0); /* just in case */ - - /* it's ok to use conn->connect_tmout for ssl-connect as - * the underlying socket connection has been established immediately */ - if (qse_ispostime(&conn->connect_tmout)) - { - if (schedule_timer_job_after (rdev, &conn->connect_tmout, ssl_connect_timedout) <= -1) - { - /* no device halting in spite of failure. - * let the caller handle this after having - * checked the return code as it is an IOCTL call. */ - SSL_CTX_free (rdev->ssl_ctx); - rdev->ssl_ctx = QSE_NULL; - - QSE_ASSERT (rdev->ssl == QSE_NULL); - return -1; - } - else - { - /* update rdev->tmout to the deadline of the connect timeout job */ - QSE_ASSERT (rdev->tmrjob_index != QSE_AIO_TMRIDX_INVALID); - qse_aio_gettmrjobdeadline (rdev->aio, rdev->tmrjob_index, &rdev->tmout); - } - } - - QSE_AIO_DEV_SCK_SET_PROGRESS (rdev, QSE_AIO_DEV_SCK_CONNECTING_SSL); - } - else - { - goto ssl_connected; - } - } - else - { - ssl_connected: - #endif - QSE_AIO_DEV_SCK_SET_PROGRESS (rdev, QSE_AIO_DEV_SCK_CONNECTED); - if (rdev->on_connect (rdev) <= -1) return -1; - #if defined(USE_SSL) - } - #endif - return 0; - } - } - - case QSE_AIO_DEV_SCK_LISTEN: - { - qse_aio_dev_sck_listen_t* lstn = (qse_aio_dev_sck_listen_t*)arg; - int x; - - if (QSE_AIO_DEV_SCK_GET_PROGRESS(rdev)) - { - /* can't listen again */ - rdev->aio->errnum = QSE_AIO_EPERM; - return -1; - } - - if (!IS_STATEFUL(rdev)) - { - dev->aio->errnum = QSE_AIO_ENOCAPA; - return -1; - } - - x = listen (rdev->sck, lstn->backlogs); - if (x == -1) - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - QSE_AIO_DEV_SCK_SET_PROGRESS (rdev, QSE_AIO_DEV_SCK_LISTENING); - rdev->on_connect = lstn->on_connect; - return 0; - } - } - - return 0; -} - -static qse_aio_dev_mth_t dev_sck_methods_stateless = -{ - dev_sck_make, - dev_sck_kill, - dev_sck_getsyshnd, - - dev_sck_read_stateless, - dev_sck_write_stateless, - dev_sck_ioctl, /* ioctl */ -}; - - -static qse_aio_dev_mth_t dev_sck_methods_stateful = -{ - dev_sck_make, - dev_sck_kill, - dev_sck_getsyshnd, - - dev_sck_read_stateful, - dev_sck_write_stateful, - dev_sck_ioctl, /* ioctl */ -}; - -static qse_aio_dev_mth_t dev_mth_clisck = -{ - dev_sck_make_client, - dev_sck_kill, - dev_sck_getsyshnd, - - dev_sck_read_stateful, - dev_sck_write_stateful, - dev_sck_ioctl -}; -/* ========================================================================= */ - -static int harvest_outgoing_connection (qse_aio_dev_sck_t* rdev) -{ - int errcode; - qse_aio_scklen_t len; - - QSE_ASSERT (!(rdev->state & QSE_AIO_DEV_SCK_CONNECTED)); - - len = QSE_SIZEOF(errcode); - if (getsockopt (rdev->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - else if (errcode == 0) - { - qse_aio_sckaddr_t localaddr; - qse_aio_scklen_t addrlen; - - /* connected */ - - if (rdev->tmrjob_index != QSE_AIO_TMRIDX_INVALID) - { - qse_aio_deltmrjob (rdev->aio, rdev->tmrjob_index); - QSE_ASSERT (rdev->tmrjob_index == QSE_AIO_TMRIDX_INVALID); - } - - addrlen = QSE_SIZEOF(localaddr); - if (getsockname (rdev->sck, (struct sockaddr*)&localaddr, &addrlen) == 0) rdev->localaddr = localaddr; - - if (qse_aio_dev_watch ((qse_aio_dev_t*)rdev, QSE_AIO_DEV_WATCH_RENEW, 0) <= -1) - { - /* watcher update failure. it's critical */ - qse_aio_stop (rdev->aio, QSE_AIO_STOPREQ_WATCHER_ERROR); - return -1; - } - - #if defined(USE_SSL) - if (rdev->ssl_ctx) - { - int x; - QSE_ASSERT (!rdev->ssl); /* must not be SSL-connected yet */ - - x = connect_ssl (rdev); - if (x <= -1) return -1; - if (x == 0) - { - /* underlying socket connected but not SSL-connected */ - QSE_AIO_DEV_SCK_SET_PROGRESS (rdev, QSE_AIO_DEV_SCK_CONNECTING_SSL); - - QSE_ASSERT (rdev->tmrjob_index == QSE_AIO_TMRIDX_INVALID); - - /* rdev->tmout has been set to the deadline of the connect task - * when the CONNECT IOCTL command has been executed. use the - * same deadline here */ - if (qse_ispostime(&rdev->tmout) && - schedule_timer_job_at (rdev, &rdev->tmout, ssl_connect_timedout) <= -1) - { - qse_aio_dev_halt ((qse_aio_dev_t*)rdev); - } - - return 0; - } - else - { - goto ssl_connected; - } - } - else - { - ssl_connected: - #endif - QSE_AIO_DEV_SCK_SET_PROGRESS (rdev, QSE_AIO_DEV_SCK_CONNECTED); - if (rdev->on_connect (rdev) <= -1) return -1; - #if defined(USE_SSL) - } - #endif - - return 0; - } - else if (errcode == EINPROGRESS || errcode == EWOULDBLOCK) - { - /* still in progress */ - return 0; - } - else - { - rdev->aio->errnum = qse_aio_syserrtoerrnum(errcode); - return -1; - } -} - -static int accept_incoming_connection (qse_aio_dev_sck_t* rdev) -{ - qse_aio_sckhnd_t clisck; - qse_aio_sckaddr_t remoteaddr; - qse_aio_scklen_t addrlen; - qse_aio_dev_sck_t* clidev; - - /* this is a server(lisening) socket */ - - addrlen = QSE_SIZEOF(remoteaddr); - clisck = accept (rdev->sck, (struct sockaddr*)&remoteaddr, &addrlen); - if (clisck == QSE_AIO_SCKHND_INVALID) - { - if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0; - if (errno == EINTR) return 0; /* if interrupted by a signal, treat it as if it's EINPROGRESS */ - - rdev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - /* use rdev->dev_size when instantiating a client sck device - * instead of QSE_SIZEOF(qse_aio_dev_sck_t). therefore, the - * extension area as big as that of the master sck device - * is created in the client sck device */ - clidev = (qse_aio_dev_sck_t*)qse_aio_makedev (rdev->aio, rdev->dev_size, &dev_mth_clisck, rdev->dev_evcb, &clisck); - if (!clidev) - { - close (clisck); - return -1; - } - - QSE_ASSERT (clidev->sck == clisck); - - clidev->dev_capa |= QSE_AIO_DEV_CAPA_IN | QSE_AIO_DEV_CAPA_OUT | QSE_AIO_DEV_CAPA_STREAM | QSE_AIO_DEV_CAPA_OUT_QUEUED; - clidev->remoteaddr = remoteaddr; - - addrlen = QSE_SIZEOF(clidev->localaddr); - if (getsockname(clisck, (struct sockaddr*)&clidev->localaddr, &addrlen) == -1) clidev->localaddr = rdev->localaddr; - -#if defined(SO_ORIGINAL_DST) - /* if REDIRECT is used, SO_ORIGINAL_DST returns the original - * destination address. When REDIRECT is not used, it returnes - * the address of the local socket. In this case, it should - * be same as the result of getsockname(). */ - addrlen = QSE_SIZEOF(clidev->orgdstaddr); - if (getsockopt (clisck, SOL_IP, SO_ORIGINAL_DST, &clidev->orgdstaddr, &addrlen) == -1) clidev->orgdstaddr = rdev->localaddr; -#else - clidev->orgdstaddr = rdev->localaddr; -#endif - - if (!qse_aio_equalsckaddrs (rdev->aio, &clidev->orgdstaddr, &clidev->localaddr)) - { - clidev->state |= QSE_AIO_DEV_SCK_INTERCEPTED; - } - else if (qse_aio_getsckaddrport (&clidev->localaddr) != qse_aio_getsckaddrport(&rdev->localaddr)) - { - /* When TPROXY is used, getsockname() and SO_ORIGNAL_DST return - * the same addresses. however, the port number may be different - * as a typical TPROXY rule is set to change the port number. - * However, this check is fragile if the server port number is - * set to 0. - * - * Take note that the above assumption gets wrong if the TPROXY - * rule doesn't change the port number. so it won't be able - * to handle such a TPROXYed packet without port transformation. */ - clidev->state |= QSE_AIO_DEV_SCK_INTERCEPTED; - } - #if 0 - else if ((clidev->initial_ifindex = resolve_ifindex (fd, clidev->localaddr)) <= -1) - { - /* the local_address is not one of a local address. - * it's probably proxied. */ - clidev->state |= QSE_AIO_DEV_SCK_INTERCEPTED; - } - #endif - - /* inherit some event handlers from the parent. - * you can still change them inside the on_connect handler */ - clidev->on_connect = rdev->on_connect; - clidev->on_disconnect = rdev->on_disconnect; - clidev->on_write = rdev->on_write; - clidev->on_read = rdev->on_read; - - QSE_ASSERT (clidev->tmrjob_index == QSE_AIO_TMRIDX_INVALID); - - if (rdev->ssl_ctx) - { - QSE_AIO_DEV_SCK_SET_PROGRESS (clidev, QSE_AIO_DEV_SCK_ACCEPTING_SSL); - QSE_ASSERT (clidev->state & QSE_AIO_DEV_SCK_ACCEPTING_SSL); - /* actual SSL acceptance must be completed in the client device */ - - /* let the client device know the SSL context to use */ - clidev->ssl_ctx = rdev->ssl_ctx; - - if (qse_ispostime(&rdev->tmout) && - schedule_timer_job_after (clidev, &rdev->tmout, ssl_accept_timedout) <= -1) - { - /* TODO: call a warning/error callback */ - /* timer job scheduling failed. halt the device */ - qse_aio_dev_halt ((qse_aio_dev_t*)clidev); - } - } - else - { - QSE_AIO_DEV_SCK_SET_PROGRESS (clidev, QSE_AIO_DEV_SCK_ACCEPTED); - if (clidev->on_connect(clidev) <= -1) qse_aio_dev_sck_halt (clidev); - } - - return 0; -} - -static int dev_evcb_sck_ready_stateful (qse_aio_dev_t* dev, int events) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - - if (events & QSE_AIO_DEV_EVENT_ERR) - { - int errcode; - qse_aio_scklen_t len; - - len = QSE_SIZEOF(errcode); - if (getsockopt(rdev->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) - { - /* the error number is set to the socket error code. - * errno resulting from getsockopt() doesn't reflect the actual - * socket error. so errno is not used to set the error number. - * instead, the generic device error QSE_AIO_EDEVERRR is used */ - rdev->aio->errnum = QSE_AIO_EDEVERR; - } - else - { - rdev->aio->errnum = qse_aio_syserrtoerrnum (errcode); - } - return -1; - } - - /* this socket can connect */ - switch (QSE_AIO_DEV_SCK_GET_PROGRESS(rdev)) - { - case QSE_AIO_DEV_SCK_CONNECTING: - if (events & QSE_AIO_DEV_EVENT_HUP) - { - /* device hang-up */ - rdev->aio->errnum = QSE_AIO_EDEVHUP; - return -1; - } - else if (events & (QSE_AIO_DEV_EVENT_PRI | QSE_AIO_DEV_EVENT_IN)) - { - /* invalid event masks. generic device error */ - rdev->aio->errnum = QSE_AIO_EDEVERR; - return -1; - } - else if (events & QSE_AIO_DEV_EVENT_OUT) - { - /* when connected, the socket becomes writable */ - return harvest_outgoing_connection (rdev); - } - else - { - return 0; /* success but don't invoke on_read() */ - } - - case QSE_AIO_DEV_SCK_CONNECTING_SSL: - #if defined(USE_SSL) - if (events & QSE_AIO_DEV_EVENT_HUP) - { - /* device hang-up */ - rdev->aio->errnum = QSE_AIO_EDEVHUP; - return -1; - } - else if (events & QSE_AIO_DEV_EVENT_PRI) - { - /* invalid event masks. generic device error */ - rdev->aio->errnum = QSE_AIO_EDEVERR; - return -1; - } - else if (events & (QSE_AIO_DEV_EVENT_IN | QSE_AIO_DEV_EVENT_OUT)) - { - int x; - - x = connect_ssl (rdev); - if (x <= -1) return -1; - if (x == 0) return 0; /* not SSL-Connected */ - - if (rdev->tmrjob_index != QSE_AIO_TMRIDX_INVALID) - { - qse_aio_deltmrjob (rdev->aio, rdev->tmrjob_index); - rdev->tmrjob_index = QSE_AIO_TMRIDX_INVALID; - } - - QSE_AIO_DEV_SCK_SET_PROGRESS (rdev, QSE_AIO_DEV_SCK_CONNECTED); - if (rdev->on_connect (rdev) <= -1) return -1; - return 0; - } - else - { - return 0; /* success. no actual I/O yet */ - } - #else - rdev->aio->errnum = QSE_AIO_EINTERN; - return -1; - #endif - - case QSE_AIO_DEV_SCK_LISTENING: - - if (events & QSE_AIO_DEV_EVENT_HUP) - { - /* device hang-up */ - rdev->aio->errnum = QSE_AIO_EDEVHUP; - return -1; - } - else if (events & (QSE_AIO_DEV_EVENT_PRI | QSE_AIO_DEV_EVENT_OUT)) - { - rdev->aio->errnum = QSE_AIO_EDEVERR; - return -1; - } - else if (events & QSE_AIO_DEV_EVENT_IN) - { - return accept_incoming_connection (rdev); - } - else - { - return 0; /* success but don't invoke on_read() */ - } - - case QSE_AIO_DEV_SCK_ACCEPTING_SSL: - #if defined(USE_SSL) - if (events & QSE_AIO_DEV_EVENT_HUP) - { - /* device hang-up */ - rdev->aio->errnum = QSE_AIO_EDEVHUP; - return -1; - } - else if (events & QSE_AIO_DEV_EVENT_PRI) - { - /* invalid event masks. generic device error */ - rdev->aio->errnum = QSE_AIO_EDEVERR; - return -1; - } - else if (events & (QSE_AIO_DEV_EVENT_IN | QSE_AIO_DEV_EVENT_OUT)) - { - int x; - x = accept_ssl (rdev); - if (x <= -1) return -1; - if (x <= 0) return 0; /* not SSL-accepted yet */ - - if (rdev->tmrjob_index != QSE_AIO_TMRIDX_INVALID) - { - qse_aio_deltmrjob (rdev->aio, rdev->tmrjob_index); - rdev->tmrjob_index = QSE_AIO_TMRIDX_INVALID; - } - - QSE_AIO_DEV_SCK_SET_PROGRESS (rdev, QSE_AIO_DEV_SCK_ACCEPTED); - if (rdev->on_connect(rdev) <= -1) qse_aio_dev_sck_halt (rdev); - - return 0; - } - else - { - return 0; /* no reading or writing yet */ - } - #else - rdev->aio->errnum = QSE_AIO_EINTERN; - return -1; - #endif - - - default: - if (events & QSE_AIO_DEV_EVENT_HUP) - { - if (events & (QSE_AIO_DEV_EVENT_PRI | QSE_AIO_DEV_EVENT_IN | QSE_AIO_DEV_EVENT_OUT)) - { - /* probably half-open? */ - return 1; - } - - rdev->aio->errnum = QSE_AIO_EDEVHUP; - return -1; - } - - return 1; /* the device is ok. carry on reading or writing */ - } -} - -static int dev_evcb_sck_ready_stateless (qse_aio_dev_t* dev, int events) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - - if (events & QSE_AIO_DEV_EVENT_ERR) - { - int errcode; - qse_aio_scklen_t len; - - len = QSE_SIZEOF(errcode); - if (getsockopt (rdev->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) - { - /* the error number is set to the socket error code. - * errno resulting from getsockopt() doesn't reflect the actual - * socket error. so errno is not used to set the error number. - * instead, the generic device error QSE_AIO_EDEVERRR is used */ - rdev->aio->errnum = QSE_AIO_EDEVERR; - } - else - { - rdev->aio->errnum = qse_aio_syserrtoerrnum (errcode); - } - return -1; - } - else if (events & QSE_AIO_DEV_EVENT_HUP) - { - rdev->aio->errnum = QSE_AIO_EDEVHUP; - return -1; - } - - return 1; /* the device is ok. carry on reading or writing */ -} - -static int dev_evcb_sck_on_read_stateful (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t dlen, const qse_aio_devaddr_t* srcaddr) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - return rdev->on_read (rdev, data, dlen, QSE_NULL); -} - -static int dev_evcb_sck_on_write_stateful (qse_aio_dev_t* dev, qse_aio_iolen_t wrlen, void* wrctx, const qse_aio_devaddr_t* dstaddr) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - return rdev->on_write (rdev, wrlen, wrctx, QSE_NULL); -} - -static int dev_evcb_sck_on_read_stateless (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t dlen, const qse_aio_devaddr_t* srcaddr) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - return rdev->on_read (rdev, data, dlen, srcaddr->ptr); -} - -static int dev_evcb_sck_on_write_stateless (qse_aio_dev_t* dev, qse_aio_iolen_t wrlen, void* wrctx, const qse_aio_devaddr_t* dstaddr) -{ - qse_aio_dev_sck_t* rdev = (qse_aio_dev_sck_t*)dev; - return rdev->on_write (rdev, wrlen, wrctx, dstaddr->ptr); -} - -static qse_aio_dev_evcb_t dev_sck_event_callbacks_stateful = -{ - dev_evcb_sck_ready_stateful, - dev_evcb_sck_on_read_stateful, - dev_evcb_sck_on_write_stateful -}; - -static qse_aio_dev_evcb_t dev_sck_event_callbacks_stateless = -{ - dev_evcb_sck_ready_stateless, - dev_evcb_sck_on_read_stateless, - dev_evcb_sck_on_write_stateless -}; - -/* ========================================================================= */ - -qse_aio_dev_sck_t* qse_aio_dev_sck_make (qse_aio_t* aio, qse_size_t xtnsize, const qse_aio_dev_sck_make_t* info) -{ - qse_aio_dev_sck_t* rdev; - - if (info->type < 0 && info->type >= QSE_COUNTOF(sck_type_map)) - { - aio->errnum = QSE_AIO_EINVAL; - return QSE_NULL; - } - - if (sck_type_map[info->type].extra_dev_capa & QSE_AIO_DEV_CAPA_STREAM) /* can't use the IS_STATEFUL() macro yet */ - { - rdev = (qse_aio_dev_sck_t*)qse_aio_makedev ( - aio, QSE_SIZEOF(qse_aio_dev_sck_t) + xtnsize, - &dev_sck_methods_stateful, &dev_sck_event_callbacks_stateful, (void*)info); - } - else - { - rdev = (qse_aio_dev_sck_t*)qse_aio_makedev ( - aio, QSE_SIZEOF(qse_aio_dev_sck_t) + xtnsize, - &dev_sck_methods_stateless, &dev_sck_event_callbacks_stateless, (void*)info); - } - - return rdev; -} - -int qse_aio_dev_sck_bind (qse_aio_dev_sck_t* dev, qse_aio_dev_sck_bind_t* info) -{ - return qse_aio_dev_ioctl ((qse_aio_dev_t*)dev, QSE_AIO_DEV_SCK_BIND, info); -} - -int qse_aio_dev_sck_connect (qse_aio_dev_sck_t* dev, qse_aio_dev_sck_connect_t* info) -{ - return qse_aio_dev_ioctl ((qse_aio_dev_t*)dev, QSE_AIO_DEV_SCK_CONNECT, info); -} - -int qse_aio_dev_sck_listen (qse_aio_dev_sck_t* dev, qse_aio_dev_sck_listen_t* info) -{ - return qse_aio_dev_ioctl ((qse_aio_dev_t*)dev, QSE_AIO_DEV_SCK_LISTEN, info); -} - -int qse_aio_dev_sck_write (qse_aio_dev_sck_t* dev, const void* data, qse_aio_iolen_t dlen, void* wrctx, const qse_aio_sckaddr_t* dstaddr) -{ - qse_aio_devaddr_t devaddr; - return qse_aio_dev_write ((qse_aio_dev_t*)dev, data, dlen, wrctx, sckaddr_to_devaddr(dev, dstaddr, &devaddr)); -} - -int qse_aio_dev_sck_timedwrite (qse_aio_dev_sck_t* dev, const void* data, qse_aio_iolen_t dlen, const qse_ntime_t* tmout, void* wrctx, const qse_aio_sckaddr_t* dstaddr) -{ - qse_aio_devaddr_t devaddr; - return qse_aio_dev_timedwrite ((qse_aio_dev_t*)dev, data, dlen, tmout, wrctx, sckaddr_to_devaddr(dev, dstaddr, &devaddr)); -} - - - -/* ========================================================================= */ - -qse_uint16_t qse_aio_checksumip (const void* hdr, qse_size_t len) -{ - qse_uint32_t sum = 0; - qse_uint16_t *ptr = (qse_uint16_t*)hdr; - - - while (len > 1) - { - sum += *ptr++; - if (sum & 0x80000000) - sum = (sum & 0xFFFF) + (sum >> 16); - len -= 2; - } - - while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16); - - return (qse_uint16_t)~sum; -} diff --git a/qse/lib/si/aio-tmr.c b/qse/lib/si/aio-tmr.c deleted file mode 100644 index 6ca7a43b..00000000 --- a/qse/lib/si/aio-tmr.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * $Id$ - * - Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include "aio-prv.h" - -#define HEAP_PARENT(x) (((x) - 1) / 2) -#define HEAP_LEFT(x) ((x) * 2 + 1) -#define HEAP_RIGHT(x) ((x) * 2 + 2) - -#define YOUNGER_THAN(x,y) (qse_cmptime(&(x)->when, &(y)->when) < 0) - -void qse_aio_cleartmrjobs (qse_aio_t* aio) -{ - while (aio->tmr.size > 0) qse_aio_deltmrjob (aio, 0); -} - -static qse_aio_tmridx_t sift_up (qse_aio_t* aio, qse_aio_tmridx_t index, int notify) -{ - qse_aio_tmridx_t parent; - - parent = HEAP_PARENT(index); - if (index > 0 && YOUNGER_THAN(&aio->tmr.jobs[index], &aio->tmr.jobs[parent])) - { - qse_aio_tmrjob_t item; - - item = aio->tmr.jobs[index]; - - do - { - /* move down the parent to my current position */ - aio->tmr.jobs[index] = aio->tmr.jobs[parent]; - if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index; - - /* traverse up */ - index = parent; - parent = HEAP_PARENT(parent); - } - while (index > 0 && YOUNGER_THAN(&item, &aio->tmr.jobs[parent])); - - aio->tmr.jobs[index] = item; - if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index; - } - - return index; -} - -static qse_aio_tmridx_t sift_down (qse_aio_t* aio, qse_aio_tmridx_t index, int notify) -{ - qse_size_t base = aio->tmr.size / 2; - - if (index < base) /* at least 1 child is under the 'index' position */ - { - qse_aio_tmrjob_t item; - - item = aio->tmr.jobs[index]; - - do - { - qse_aio_tmridx_t left, right, younger; - - left = HEAP_LEFT(index); - right = HEAP_RIGHT(index); - - if (right < aio->tmr.size && YOUNGER_THAN(&aio->tmr.jobs[right], &aio->tmr.jobs[left])) - { - younger = right; - } - else - { - younger = left; - } - - if (YOUNGER_THAN(&item, &aio->tmr.jobs[younger])) break; - - aio->tmr.jobs[index] = aio->tmr.jobs[younger]; - if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index; - - index = younger; - } - while (index < base); - - aio->tmr.jobs[index] = item; - if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index; - } - - return index; -} - -void qse_aio_deltmrjob (qse_aio_t* aio, qse_aio_tmridx_t index) -{ - qse_aio_tmrjob_t item; - - QSE_ASSERT (index < aio->tmr.size); - - item = aio->tmr.jobs[index]; - if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = QSE_AIO_TMRIDX_INVALID; - - aio->tmr.size = aio->tmr.size - 1; - if (aio->tmr.size > 0 && index != aio->tmr.size) - { - aio->tmr.jobs[index] = aio->tmr.jobs[aio->tmr.size]; - if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index; - YOUNGER_THAN(&aio->tmr.jobs[index], &item)? sift_up(aio, index, 1): sift_down(aio, index, 1); - } -} - -qse_aio_tmridx_t qse_aio_instmrjob (qse_aio_t* aio, const qse_aio_tmrjob_t* job) -{ - qse_aio_tmridx_t index = aio->tmr.size; - - if (index >= aio->tmr.capa) - { - qse_aio_tmrjob_t* tmp; - qse_size_t new_capa; - - QSE_ASSERT (aio->tmr.capa >= 1); - new_capa = aio->tmr.capa * 2; - tmp = (qse_aio_tmrjob_t*)QSE_MMGR_REALLOC (aio->mmgr, aio->tmr.jobs, new_capa * QSE_SIZEOF(*tmp)); - if (tmp == QSE_NULL) - { - aio->errnum = QSE_AIO_ENOMEM; - return QSE_AIO_TMRIDX_INVALID; - } - - aio->tmr.jobs = tmp; - aio->tmr.capa = new_capa; - } - - aio->tmr.size = aio->tmr.size + 1; - aio->tmr.jobs[index] = *job; - if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index; - return sift_up (aio, index, 0); -} - -qse_aio_tmridx_t qse_aio_updtmrjob (qse_aio_t* aio, qse_aio_tmridx_t index, const qse_aio_tmrjob_t* job) -{ - qse_aio_tmrjob_t item; - item = aio->tmr.jobs[index]; - aio->tmr.jobs[index] = *job; - if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index; - return YOUNGER_THAN(job, &item)? sift_up (aio, index, 0): sift_down (aio, index, 0); -} - -void qse_aio_firetmrjobs (qse_aio_t* aio, const qse_ntime_t* tm, qse_size_t* firecnt) -{ - qse_ntime_t now; - qse_aio_tmrjob_t tmrjob; - qse_size_t count = 0; - - /* if the current time is not specified, get it from the system */ - if (tm) now = *tm; - else qse_gettime (&now); - - while (aio->tmr.size > 0) - { - if (qse_cmptime(&aio->tmr.jobs[0].when, &now) > 0) break; - - tmrjob = aio->tmr.jobs[0]; /* copy the scheduled job */ - qse_aio_deltmrjob (aio, 0); /* deschedule the job */ - - count++; - tmrjob.handler (aio, &now, &tmrjob); /* then fire the job */ - } - - if (firecnt) *firecnt = count; -} - -int qse_aio_gettmrtmout (qse_aio_t* aio, const qse_ntime_t* tm, qse_ntime_t* tmout) -{ - qse_ntime_t now; - - /* time-out can't be calculated when there's no job scheduled */ - if (aio->tmr.size <= 0) - { - aio->errnum = QSE_AIO_ENOENT; - return -1; - } - - /* if the current time is not specified, get it from the system */ - if (tm) now = *tm; - else qse_gettime (&now); - - qse_subtime (&aio->tmr.jobs[0].when, &now, tmout); - if (tmout->sec < 0) qse_cleartime (tmout); - - return 0; -} - -qse_aio_tmrjob_t* qse_aio_gettmrjob (qse_aio_t* aio, qse_aio_tmridx_t index) -{ - if (index < 0 || index >= aio->tmr.size) - { - aio->errnum = QSE_AIO_ENOENT; - return QSE_NULL; - } - - return &aio->tmr.jobs[index]; -} - -int qse_aio_gettmrjobdeadline (qse_aio_t* aio, qse_aio_tmridx_t index, qse_ntime_t* deadline) -{ - if (index < 0 || index >= aio->tmr.size) - { - aio->errnum = QSE_AIO_ENOENT; - return -1; - } - - *deadline = aio->tmr.jobs[index].when; - return 0; -} diff --git a/qse/lib/si/aio.c b/qse/lib/si/aio.c deleted file mode 100644 index d8248af1..00000000 --- a/qse/lib/si/aio.c +++ /dev/null @@ -1,1468 +0,0 @@ -/* - * $Id$ - * - Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "aio-prv.h" - -#if defined(HAVE_SYS_EPOLL_H) -# include -# define USE_EPOLL -#elif defined(HAVE_SYS_POLL_H) -# include -# define USE_POLL -#else -# error NO SUPPORTED MULTIPLEXER -#endif - -#include -#include -#include - -#define DEV_CAPA_ALL_WATCHED (QSE_AIO_DEV_CAPA_IN_WATCHED | QSE_AIO_DEV_CAPA_OUT_WATCHED | QSE_AIO_DEV_CAPA_PRI_WATCHED) - -static int schedule_kill_zombie_job (qse_aio_dev_t* dev); -static int kill_and_free_device (qse_aio_dev_t* dev, int force); - -#define APPEND_DEVICE_TO_LIST(list,dev) do { \ - if ((list)->tail) (list)->tail->dev_next = (dev); \ - else (list)->head = (dev); \ - (dev)->dev_prev = (list)->tail; \ - (dev)->dev_next = QSE_NULL; \ - (list)->tail = (dev); \ -} while(0) - -#define UNLINK_DEVICE_FROM_LIST(list,dev) do { \ - if ((dev)->dev_prev) (dev)->dev_prev->dev_next = (dev)->dev_next; \ - else (list)->head = (dev)->dev_next; \ - if ((dev)->dev_next) (dev)->dev_next->dev_prev = (dev)->dev_prev; \ - else (list)->tail = (dev)->dev_prev; \ -} while (0) - - - -/* ========================================================================= */ -#if defined(USE_POLL) - -#define MUX_CMD_INSERT 1 -#define MUX_CMD_UPDATE 2 -#define MUX_CMD_DELETE 3 - -#define MUX_INDEX_INVALID QSE_TYPE_MAX(qse_size_t) - -struct qse_aio_mux_t -{ - struct - { - qse_size_t* ptr; - qse_size_t size; - qse_size_t capa; - } map; /* handle to index */ - - struct - { - struct pollfd* pfd; - qse_aio_dev_t** dptr; - qse_size_t size; - qse_size_t capa; - } pd; /* poll data */ -}; - - -static int mux_open (qse_aio_t* aio) -{ - qse_aio_mux_t* mux; - - mux = QSE_MMGR_ALLOC (aio->mmgr, QSE_SIZEOF(*mux)); - if (!mux) - { - aio->errnum = QSE_AIO_ENOMEM; - return -1; - } - - QSE_MEMSET (mux, 0, QSE_SIZEOF(*mux)); - - aio->mux = mux; - return 0; -} - -static void mux_close (qse_aio_t* aio) -{ - if (aio->mux) - { - QSE_MMGR_FREE (aio->mmgr, aio->mux); - aio->mux = QSE_NULL; - } -} - -static int mux_control (qse_aio_dev_t* dev, int cmd, qse_aio_syshnd_t hnd, int dev_capa) -{ - qse_aio_t* aio; - qse_aio_mux_t* mux; - qse_size_t idx; - - aio = dev->aio; - mux = (qse_aio_mux_t*)aio->mux; - - if (hnd >= mux->map.capa) - { - qse_size_t new_capa; - qse_size_t* tmp; - - if (cmd != MUX_CMD_INSERT) - { - aio->errnum = QSE_AIO_ENOENT; - return -1; - } - - new_capa = QSE_ALIGNTO_POW2((hnd + 1), 256); - - tmp = QSE_MMGR_REALLOC (aio->mmgr, mux->map.ptr, new_capa * QSE_SIZEOF(*tmp)); - if (!tmp) - { - aio->errnum = QSE_AIO_ENOMEM; - return -1; - } - - for (idx = mux->map.capa; idx < new_capa; idx++) - tmp[idx] = MUX_INDEX_INVALID; - - mux->map.ptr = tmp; - mux->map.capa = new_capa; - } - - idx = mux->map.ptr[hnd]; - if (idx != MUX_INDEX_INVALID) - { - if (cmd == MUX_CMD_INSERT) - { - aio->errnum = QSE_AIO_EEXIST; - return -1; - } - } - else - { - if (cmd != MUX_CMD_INSERT) - { - aio->errnum = QSE_AIO_ENOENT; - return -1; - } - } - - switch (cmd) - { - case MUX_CMD_INSERT: - - if (mux->pd.size >= mux->pd.capa) - { - qse_size_t new_capa; - struct pollfd* tmp1; - qse_aio_dev_t** tmp2; - - new_capa = QSE_ALIGNTO_POW2(mux->pd.size + 1, 256); - - tmp1 = QSE_MMGR_REALLOC (aio->mmgr, mux->pd.pfd, new_capa * QSE_SIZEOF(*tmp1)); - if (!tmp1) - { - aio->errnum = QSE_AIO_ENOMEM; - return -1; - } - - tmp2 = QSE_MMGR_REALLOC (aio->mmgr, mux->pd.dptr, new_capa * QSE_SIZEOF(*tmp2)); - if (!tmp2) - { - QSE_MMGR_FREE (aio->mmgr, tmp1); - aio->errnum = QSE_AIO_ENOMEM; - return -1; - } - - mux->pd.pfd = tmp1; - mux->pd.dptr = tmp2; - mux->pd.capa = new_capa; - } - - idx = mux->pd.size++; - - mux->pd.pfd[idx].fd = hnd; - mux->pd.pfd[idx].events = 0; - if (dev_capa & QSE_AIO_DEV_CAPA_IN_WATCHED) mux->pd.pfd[idx].events |= POLLIN; - if (dev_capa & QSE_AIO_DEV_CAPA_OUT_WATCHED) mux->pd.pfd[idx].events |= POLLOUT; - mux->pd.pfd[idx].revents = 0; - mux->pd.dptr[idx] = dev; - - mux->map.ptr[hnd] = idx; - - return 0; - - case MUX_CMD_UPDATE: - QSE_ASSERT (mux->pd.dptr[idx] == dev); - mux->pd.pfd[idx].events = 0; - if (dev_capa & QSE_AIO_DEV_CAPA_IN_WATCHED) mux->pd.pfd[idx].events |= POLLIN; - if (dev_capa & QSE_AIO_DEV_CAPA_OUT_WATCHED) mux->pd.pfd[idx].events |= POLLOUT; - return 0; - - case MUX_CMD_DELETE: - QSE_ASSERT (mux->pd.dptr[idx] == dev); - mux->map.ptr[hnd] = MUX_INDEX_INVALID; - - /* TODO: speed up deletion. allow a hole in the array. - * delay array compaction if there is a hole. - * set fd for the hole to -1 such that poll() - * ignores it. compact the array if another deletion - * is requested when there is an existing hole. */ - idx++; - while (idx < mux->pd.size) - { - int fd; - - mux->pd.pfd[idx - 1] = mux->pd.pfd[idx]; - mux->pd.dptr[idx - 1] = mux->pd.dptr[idx]; - - fd = mux->pd.pfd[idx].fd; - mux->map.ptr[fd] = idx - 1; - - idx++; - } - - mux->pd.size--; - - return 0; - - default: - aio->errnum = QSE_AIO_EINVAL; - return -1; - } -} - -#elif defined(USE_EPOLL) - -#define MUX_CMD_INSERT EPOLL_CTL_ADD -#define MUX_CMD_UPDATE EPOLL_CTL_MOD -#define MUX_CMD_DELETE EPOLL_CTL_DEL - -struct qse_aio_mux_t -{ - int hnd; - struct epoll_event revs[100]; /* TODO: is it a good size? */ -}; - -static int mux_open (qse_aio_t* aio) -{ - qse_aio_mux_t* mux; - - mux = QSE_MMGR_ALLOC (aio->mmgr, QSE_SIZEOF(*mux)); - if (!mux) - { - aio->errnum = QSE_AIO_ENOMEM; - return -1; - } - - QSE_MEMSET (mux, 0, QSE_SIZEOF(*mux)); - - mux->hnd = epoll_create (1000); - if (mux->hnd == -1) - { - aio->errnum = qse_aio_syserrtoerrnum(errno); - QSE_MMGR_FREE (aio->mmgr, mux); - return -1; - } - - aio->mux = mux; - return 0; -} - -static void mux_close (qse_aio_t* aio) -{ - if (aio->mux) - { - close (aio->mux->hnd); - QSE_MMGR_FREE (aio->mmgr, aio->mux); - aio->mux = QSE_NULL; - } -} - - -static QSE_INLINE int mux_control (qse_aio_dev_t* dev, int cmd, qse_aio_syshnd_t hnd, int dev_capa) -{ - struct epoll_event ev; - - ev.data.ptr = dev; - ev.events = EPOLLHUP | EPOLLERR /*| EPOLLET*/; - - if (dev_capa & QSE_AIO_DEV_CAPA_IN_WATCHED) - { - ev.events |= EPOLLIN; - #if defined(EPOLLRDHUP) - ev.events |= EPOLLRDHUP; - #endif - if (dev_capa & QSE_AIO_DEV_CAPA_PRI_WATCHED) ev.events |= EPOLLPRI; - } - - if (dev_capa & QSE_AIO_DEV_CAPA_OUT_WATCHED) ev.events |= EPOLLOUT; - - if (epoll_ctl (dev->aio->mux->hnd, cmd, hnd, &ev) == -1) - { - dev->aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - return 0; -} -#endif - -/* ========================================================================= */ - -qse_aio_t* qse_aio_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_size_t tmrcapa, qse_aio_errnum_t* errnum) -{ - qse_aio_t* aio; - - aio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_aio_t) + xtnsize); - if (aio) - { - if (qse_aio_init (aio, mmgr, tmrcapa) <= -1) - { - if (errnum) *errnum = aio->errnum; - QSE_MMGR_FREE (mmgr, aio); - aio = QSE_NULL; - } - else QSE_MEMSET (aio + 1, 0, xtnsize); - } - else - { - if (errnum) *errnum = QSE_AIO_ENOMEM; - } - - return aio; -} - -void qse_aio_close (qse_aio_t* aio) -{ - qse_aio_fini (aio); - QSE_MMGR_FREE (aio->mmgr, aio); -} - -int qse_aio_init (qse_aio_t* aio, qse_mmgr_t* mmgr, qse_size_t tmrcapa) -{ - QSE_MEMSET (aio, 0, QSE_SIZEOF(*aio)); - aio->mmgr = mmgr; - - /* intialize the multiplexer object */ - - if (mux_open (aio) <= -1) return -1; - - /* initialize the timer object */ - if (tmrcapa <= 0) tmrcapa = 1; - aio->tmr.jobs = QSE_MMGR_ALLOC (aio->mmgr, tmrcapa * QSE_SIZEOF(qse_aio_tmrjob_t)); - if (!aio->tmr.jobs) - { - aio->errnum = QSE_AIO_ENOMEM; - mux_close (aio); - return -1; - } - aio->tmr.capa = tmrcapa; - - return 0; -} - -void qse_aio_fini (qse_aio_t* aio) -{ - qse_aio_dev_t* dev, * next_dev; - struct - { - qse_aio_dev_t* head; - qse_aio_dev_t* tail; - } diehard; - - /* kill all registered devices */ - while (aio->actdev.head) - { - qse_aio_killdev (aio, aio->actdev.head); - } - - while (aio->hltdev.head) - { - qse_aio_killdev (aio, aio->hltdev.head); - } - - /* clean up all zombie devices */ - QSE_MEMSET (&diehard, 0, QSE_SIZEOF(diehard)); - for (dev = aio->zmbdev.head; dev; ) - { - kill_and_free_device (dev, 1); - if (aio->zmbdev.head == dev) - { - /* the deive has not been freed. go on to the next one */ - next_dev = dev->dev_next; - - /* remove the device from the zombie device list */ - UNLINK_DEVICE_FROM_LIST (&aio->zmbdev, dev); - dev->dev_capa &= ~QSE_AIO_DEV_CAPA_ZOMBIE; - - /* put it to a private list for aborting */ - APPEND_DEVICE_TO_LIST (&diehard, dev); - - dev = next_dev; - } - else dev = aio->zmbdev.head; - } - - while (diehard.head) - { - /* if the kill method returns failure, it can leak some resource - * because the device is freed regardless of the failure when 2 - * is given to kill_and_free_device(). */ - dev = diehard.head; - QSE_ASSERT (!(dev->dev_capa & (QSE_AIO_DEV_CAPA_ACTIVE | QSE_AIO_DEV_CAPA_HALTED | QSE_AIO_DEV_CAPA_ZOMBIE))); - UNLINK_DEVICE_FROM_LIST (&diehard, dev); - kill_and_free_device (dev, 2); - } - - /* purge scheduled timer jobs and kill the timer */ - qse_aio_cleartmrjobs (aio); - QSE_MMGR_FREE (aio->mmgr, aio->tmr.jobs); - - /* close the multiplexer */ - mux_close (aio); -} - - -int qse_aio_prologue (qse_aio_t* aio) -{ - /* TODO: */ - return 0; -} - -void qse_aio_epilogue (qse_aio_t* aio) -{ - /* TODO: */ -} - -static QSE_INLINE void unlink_wq (qse_aio_t* aio, qse_aio_wq_t* q) -{ - if (q->tmridx != QSE_AIO_TMRIDX_INVALID) - { - qse_aio_deltmrjob (aio, q->tmridx); - QSE_ASSERT (q->tmridx == QSE_AIO_TMRIDX_INVALID); - } - QSE_AIO_WQ_UNLINK (q); -} - -static QSE_INLINE void handle_event (qse_aio_dev_t* dev, int events, int rdhup) -{ - qse_aio_t* aio; - - aio = dev->aio; - aio->renew_watch = 0; - - QSE_ASSERT (aio == dev->aio); - - if (dev->dev_evcb->ready) - { - int x, xevents; - - xevents = events; - if (rdhup) xevents |= QSE_AIO_DEV_EVENT_HUP; - - /* return value of ready() - * <= -1 - failure. kill the device. - * == 0 - ok. but don't invoke recv() or send(). - * >= 1 - everything is ok. */ - x = dev->dev_evcb->ready (dev, xevents); - if (x <= -1) - { - qse_aio_dev_halt (dev); - return; - } - else if (x == 0) goto skip_evcb; - } - - if (dev && (events & QSE_AIO_DEV_EVENT_PRI)) - { - /* urgent data */ - /* TODO: implement urgent data handling */ - /*x = dev->dev_mth->urgread (dev, aio->bugbuf, &len);*/ - } - - if (dev && (events & QSE_AIO_DEV_EVENT_OUT)) - { - /* write pending requests */ - while (!QSE_AIO_WQ_ISEMPTY(&dev->wq)) - { - qse_aio_wq_t* q; - const qse_uint8_t* uptr; - qse_aio_iolen_t urem, ulen; - int x; - - q = QSE_AIO_WQ_HEAD(&dev->wq); - - uptr = q->ptr; - urem = q->len; - - send_leftover: - ulen = urem; - x = dev->dev_mth->write (dev, uptr, &ulen, &q->dstaddr); - if (x <= -1) - { - qse_aio_dev_halt (dev); - dev = QSE_NULL; - break; - } - else if (x == 0) - { - /* keep the left-over */ - QSE_MEMMOVE (q->ptr, uptr, urem); - q->len = urem; - break; - } - else - { - uptr += ulen; - urem -= ulen; - - if (urem <= 0) - { - /* finished writing a single write request */ - int y, out_closed = 0; - - if (q->len <= 0 && (dev->dev_capa & QSE_AIO_DEV_CAPA_STREAM)) - { - /* it was a zero-length write request. - * for a stream, it is to close the output. */ - dev->dev_capa |= QSE_AIO_DEV_CAPA_OUT_CLOSED; - aio->renew_watch = 1; - out_closed = 1; - } - - unlink_wq (aio, q); - y = dev->dev_evcb->on_write (dev, q->olen, q->ctx, &q->dstaddr); - QSE_MMGR_FREE (aio->mmgr, q); - - if (y <= -1) - { - qse_aio_dev_halt (dev); - dev = QSE_NULL; - break; - } - - if (out_closed) - { - /* drain all pending requests. - * callbacks are skipped for drained requests */ - while (!QSE_AIO_WQ_ISEMPTY(&dev->wq)) - { - q = QSE_AIO_WQ_HEAD(&dev->wq); - unlink_wq (aio, q); - QSE_MMGR_FREE (dev->aio->mmgr, q); - } - break; - } - } - else goto send_leftover; - } - } - - if (dev && QSE_AIO_WQ_ISEMPTY(&dev->wq)) - { - /* no pending request to write */ - if ((dev->dev_capa & QSE_AIO_DEV_CAPA_IN_CLOSED) && - (dev->dev_capa & QSE_AIO_DEV_CAPA_OUT_CLOSED)) - { - qse_aio_dev_halt (dev); - dev = QSE_NULL; - } - else - { - aio->renew_watch = 1; - } - } - } - - if (dev && (events & QSE_AIO_DEV_EVENT_IN)) - { - qse_aio_devaddr_t srcaddr; - qse_aio_iolen_t len; - int x; - - /* the devices are all non-blocking. read as much as possible - * if on_read callback returns 1 or greater. read only once - * if the on_read calllback returns 0. */ - while (1) - { - len = QSE_COUNTOF(aio->bigbuf); - x = dev->dev_mth->read (dev, aio->bigbuf, &len, &srcaddr); - if (x <= -1) - { - qse_aio_dev_halt (dev); - dev = QSE_NULL; - break; - } - else if (x == 0) - { - /* no data is available - EWOULDBLOCK or something similar */ - break; - } - else if (x >= 1) - { - if (len <= 0 && (dev->dev_capa & QSE_AIO_DEV_CAPA_STREAM)) - { - /* EOF received. for a stream device, a zero-length - * read is interpreted as EOF. */ - dev->dev_capa |= QSE_AIO_DEV_CAPA_IN_CLOSED; - aio->renew_watch = 1; - - /* call the on_read callback to report EOF */ - if (dev->dev_evcb->on_read (dev, aio->bigbuf, len, &srcaddr) <= -1 || - (dev->dev_capa & QSE_AIO_DEV_CAPA_OUT_CLOSED)) - { - /* 1. input ended and its reporting failed or - * 2. input ended and no writing is possible */ - qse_aio_dev_halt (dev); - dev = QSE_NULL; - } - - /* since EOF is received, reading can't be greedy */ - break; - } - else - { - int y; - /* TODO: for a stream device, merge received data if bigbuf isn't full and fire the on_read callback - * when x == 0 or <= -1. you can */ - - /* data available */ - y = dev->dev_evcb->on_read (dev, aio->bigbuf, len, &srcaddr); - if (y <= -1) - { - qse_aio_dev_halt (dev); - dev = QSE_NULL; - break; - } - else if (y == 0) - { - /* don't be greedy. read only once - * for this loop iteration */ - break; - } - } - } - } - } - - if (dev) - { - if (events & (QSE_AIO_DEV_EVENT_ERR | QSE_AIO_DEV_EVENT_HUP)) - { - /* if error or hangup has been reported on the device, - * halt the device. this check is performed after - * EPOLLIN or EPOLLOUT check because EPOLLERR or EPOLLHUP - * can be set together with EPOLLIN or EPOLLOUT. */ - dev->dev_capa |= QSE_AIO_DEV_CAPA_IN_CLOSED | QSE_AIO_DEV_CAPA_OUT_CLOSED; - aio->renew_watch = 1; - } - else if (dev && rdhup) - { - if (events & (QSE_AIO_DEV_EVENT_IN | QSE_AIO_DEV_EVENT_OUT | QSE_AIO_DEV_EVENT_PRI)) - { - /* it may be a half-open state. don't do anything here - * to let the next read detect EOF */ - } - else - { - dev->dev_capa |= QSE_AIO_DEV_CAPA_IN_CLOSED | QSE_AIO_DEV_CAPA_OUT_CLOSED; - aio->renew_watch = 1; - } - } - - if ((dev->dev_capa & QSE_AIO_DEV_CAPA_IN_CLOSED) && - (dev->dev_capa & QSE_AIO_DEV_CAPA_OUT_CLOSED)) - { - qse_aio_dev_halt (dev); - dev = QSE_NULL; - } - } - -skip_evcb: - if (dev && aio->renew_watch && qse_aio_dev_watch (dev, QSE_AIO_DEV_WATCH_RENEW, 0) <= -1) - { - qse_aio_dev_halt (dev); - dev = QSE_NULL; - } -} - -static QSE_INLINE int __exec (qse_aio_t* aio) -{ - qse_ntime_t tmout; - -#if defined(_WIN32) - ULONG nentries, i; -#else - int nentries, i; - qse_aio_mux_t* mux; -#endif - - /*if (!aio->actdev.head) return 0;*/ - - /* execute the scheduled jobs before checking devices with the - * multiplexer. the scheduled jobs can safely destroy the devices */ - qse_aio_firetmrjobs (aio, QSE_NULL, QSE_NULL); - - if (qse_aio_gettmrtmout (aio, QSE_NULL, &tmout) <= -1) - { - /* defaults to 1 second if timeout can't be acquired */ - tmout.sec = 1; /* TODO: make the default timeout configurable */ - tmout.nsec = 0; - } - -#if defined(_WIN32) -/* - if (GetQueuedCompletionStatusEx (aio->iocp, aio->ovls, QSE_COUNTOF(aio->ovls), &nentries, timeout, FALSE) == FALSE) - { - // TODO: set errnum - return -1; - } - - for (i = 0; i < nentries; i++) - { - } -*/ -#elif defined(USE_POLL) - - mux = (qse_aio_mux_t*)aio->mux; - - nentries = poll (mux->pd.pfd, mux->pd.size, QSE_SECNSEC_TO_MSEC(tmout.sec, tmout.nsec)); - if (nentries == -1) - { - if (errno == EINTR) return 0; - aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - for (i = 0; i < mux->pd.size; i++) - { - if (mux->pd.pfd[i].fd >= 0 && mux->pd.pfd[i].revents) - { - int events = 0; - qse_aio_dev_t* dev; - - dev = mux->pd.dptr[i]; - - QSE_ASSERT (!(mux->pd.pfd[i].revents & POLLNVAL)); - if (mux->pd.pfd[i].revents & POLLIN) events |= QSE_AIO_DEV_EVENT_IN; - if (mux->pd.pfd[i].revents & POLLOUT) events |= QSE_AIO_DEV_EVENT_OUT; - if (mux->pd.pfd[i].revents & POLLPRI) events |= QSE_AIO_DEV_EVENT_PRI; - if (mux->pd.pfd[i].revents & POLLERR) events |= QSE_AIO_DEV_EVENT_ERR; - if (mux->pd.pfd[i].revents & POLLHUP) events |= QSE_AIO_DEV_EVENT_HUP; - - handle_event (dev, events, 0); - } - } - -#elif defined(USE_EPOLL) - - mux = (qse_aio_mux_t*)aio->mux; - - nentries = epoll_wait (mux->hnd, mux->revs, QSE_COUNTOF(mux->revs), QSE_SECNSEC_TO_MSEC(tmout.sec, tmout.nsec)); - if (nentries == -1) - { - if (errno == EINTR) return 0; /* it's actually ok */ - /* other errors are critical - EBADF, EFAULT, EINVAL */ - aio->errnum = qse_aio_syserrtoerrnum(errno); - return -1; - } - - /* TODO: merge events??? for the same descriptor */ - - for (i = 0; i < nentries; i++) - { - int events = 0, rdhup = 0; - qse_aio_dev_t* dev; - - dev = mux->revs[i].data.ptr; - - if (mux->revs[i].events & EPOLLIN) events |= QSE_AIO_DEV_EVENT_IN; - if (mux->revs[i].events & EPOLLOUT) events |= QSE_AIO_DEV_EVENT_OUT; - if (mux->revs[i].events & EPOLLPRI) events |= QSE_AIO_DEV_EVENT_PRI; - if (mux->revs[i].events & EPOLLERR) events |= QSE_AIO_DEV_EVENT_ERR; - if (mux->revs[i].events & EPOLLHUP) events |= QSE_AIO_DEV_EVENT_HUP; - #if defined(EPOLLRDHUP) - else if (mux->revs[i].events & EPOLLRDHUP) rdhup = 1; - #endif - handle_event (dev, events, rdhup); - } - -#else - -# error NO SUPPORTED MULTIPLEXER -#endif - - /* kill all halted devices */ - while (aio->hltdev.head) - { -printf (">>>>>>>>>>>>>> KILLING HALTED DEVICE %p\n", aio->hltdev.head); - qse_aio_killdev (aio, aio->hltdev.head); - } - QSE_ASSERT (aio->hltdev.tail == QSE_NULL); - - return 0; -} - -int qse_aio_exec (qse_aio_t* aio) -{ - int n; - - aio->in_exec = 1; - n = __exec (aio); - aio->in_exec = 0; - - return n; -} - -void qse_aio_stop (qse_aio_t* aio, qse_aio_stopreq_t stopreq) -{ - aio->stopreq = stopreq; -} - -int qse_aio_loop (qse_aio_t* aio) -{ - if (!aio->actdev.head) return 0; - - aio->stopreq = QSE_AIO_STOPREQ_NONE; - aio->renew_watch = 0; - - if (qse_aio_prologue (aio) <= -1) return -1; - - while (aio->stopreq == QSE_AIO_STOPREQ_NONE && aio->actdev.head) - { - if (qse_aio_exec (aio) <= -1) break; - /* you can do other things here */ - } - - qse_aio_epilogue (aio); - return 0; -} - -qse_aio_dev_t* qse_aio_makedev (qse_aio_t* aio, qse_size_t dev_size, qse_aio_dev_mth_t* dev_mth, qse_aio_dev_evcb_t* dev_evcb, void* make_ctx) -{ - qse_aio_dev_t* dev; - - if (dev_size < QSE_SIZEOF(qse_aio_dev_t)) - { - aio->errnum = QSE_AIO_EINVAL; - return QSE_NULL; - } - - dev = QSE_MMGR_ALLOC (aio->mmgr, dev_size); - if (!dev) - { - aio->errnum = QSE_AIO_ENOMEM; - return QSE_NULL; - } - - QSE_MEMSET (dev, 0, dev_size); - dev->aio = aio; - dev->dev_size = dev_size; - /* default capability. dev->dev_mth->make() can change this. - * qse_aio_dev_watch() is affected by the capability change. */ - dev->dev_capa = QSE_AIO_DEV_CAPA_IN | QSE_AIO_DEV_CAPA_OUT; - dev->dev_mth = dev_mth; - dev->dev_evcb = dev_evcb; - QSE_AIO_WQ_INIT(&dev->wq); - - /* call the callback function first */ - aio->errnum = QSE_AIO_ENOERR; - if (dev->dev_mth->make (dev, make_ctx) <= -1) - { - if (aio->errnum == QSE_AIO_ENOERR) aio->errnum = QSE_AIO_EDEVMAKE; - goto oops; - } - - /* the make callback must not change these fields */ - QSE_ASSERT (dev->dev_mth == dev_mth); - QSE_ASSERT (dev->dev_evcb == dev_evcb); - QSE_ASSERT (dev->dev_prev == QSE_NULL); - QSE_ASSERT (dev->dev_next == QSE_NULL); - - /* set some internal capability bits according to the capabilities - * removed by the device making callback for convenience sake. */ - if (!(dev->dev_capa & QSE_AIO_DEV_CAPA_IN)) dev->dev_capa |= QSE_AIO_DEV_CAPA_IN_CLOSED; - if (!(dev->dev_capa & QSE_AIO_DEV_CAPA_OUT)) dev->dev_capa |= QSE_AIO_DEV_CAPA_OUT_CLOSED; - -#if defined(_WIN32) - if (CreateIoCompletionPort ((HANDLE)dev->dev_mth->getsyshnd(dev), aio->iocp, QSE_AIO_IOCP_KEY, 0) == NULL) - { - /* TODO: set errnum from GetLastError()... */ - goto oops_after_make; - } -#else - if (qse_aio_dev_watch (dev, QSE_AIO_DEV_WATCH_START, 0) <= -1) goto oops_after_make; -#endif - - /* and place the new device object at the back of the active device list */ - APPEND_DEVICE_TO_LIST (&aio->actdev, dev); - dev->dev_capa |= QSE_AIO_DEV_CAPA_ACTIVE; - - return dev; - -oops_after_make: - if (kill_and_free_device (dev, 0) <= -1) - { - /* schedule a timer job that reattempts to destroy the device */ - if (schedule_kill_zombie_job (dev) <= -1) - { - /* job scheduling failed. i have no choice but to - * destroy the device now. - * - * NOTE: this while loop can block the process - * if the kill method keep returning failure */ - while (kill_and_free_device (dev, 1) <= -1) - { - if (aio->stopreq != QSE_AIO_STOPREQ_NONE) - { - /* i can't wait until destruction attempt gets - * fully successful. there is a chance that some - * resources can leak inside the device */ - kill_and_free_device (dev, 2); - break; - } - } - } - - return QSE_NULL; - } - -oops: - QSE_MMGR_FREE (aio->mmgr, dev); - return QSE_NULL; -} - -static int kill_and_free_device (qse_aio_dev_t* dev, int force) -{ - qse_aio_t* aio; - - QSE_ASSERT (!(dev->dev_capa & QSE_AIO_DEV_CAPA_ACTIVE)); - QSE_ASSERT (!(dev->dev_capa & QSE_AIO_DEV_CAPA_HALTED)); - - aio = dev->aio; - - if (dev->dev_mth->kill(dev, force) <= -1) - { - if (force >= 2) goto free_device; - - if (!(dev->dev_capa & QSE_AIO_DEV_CAPA_ZOMBIE)) - { - APPEND_DEVICE_TO_LIST (&aio->zmbdev, dev); - dev->dev_capa |= QSE_AIO_DEV_CAPA_ZOMBIE; - } - - return -1; - } - -free_device: - if (dev->dev_capa & QSE_AIO_DEV_CAPA_ZOMBIE) - { - /* detach it from the zombie device list */ - UNLINK_DEVICE_FROM_LIST (&aio->zmbdev, dev); - dev->dev_capa &= ~QSE_AIO_DEV_CAPA_ZOMBIE; - } - - QSE_MMGR_FREE (aio->mmgr, dev); - return 0; -} - -static void kill_zombie_job_handler (qse_aio_t* aio, const qse_ntime_t* now, qse_aio_tmrjob_t* job) -{ - qse_aio_dev_t* dev = (qse_aio_dev_t*)job->ctx; - - QSE_ASSERT (dev->dev_capa & QSE_AIO_DEV_CAPA_ZOMBIE); - - if (kill_and_free_device (dev, 0) <= -1) - { - if (schedule_kill_zombie_job (dev) <= -1) - { - /* i have to choice but to free up the devide by force */ - while (kill_and_free_device (dev, 1) <= -1) - { - if (aio->stopreq != QSE_AIO_STOPREQ_NONE) - { - /* i can't wait until destruction attempt gets - * fully successful. there is a chance that some - * resources can leak inside the device */ - kill_and_free_device (dev, 2); - break; - } - } - } - } -} - -static int schedule_kill_zombie_job (qse_aio_dev_t* dev) -{ - qse_aio_tmrjob_t kill_zombie_job; - qse_ntime_t tmout; - - qse_inittime (&tmout, 3, 0); /* TODO: take it from configuration */ - - QSE_MEMSET (&kill_zombie_job, 0, QSE_SIZEOF(kill_zombie_job)); - kill_zombie_job.ctx = dev; - qse_gettime (&kill_zombie_job.when); - qse_addtime (&kill_zombie_job.when, &tmout, &kill_zombie_job.when); - kill_zombie_job.handler = kill_zombie_job_handler; - /*kill_zombie_job.idxptr = &rdev->tmridx_kill_zombie;*/ - - return qse_aio_instmrjob (dev->aio, &kill_zombie_job) == QSE_AIO_TMRIDX_INVALID? -1: 0; -} - -void qse_aio_killdev (qse_aio_t* aio, qse_aio_dev_t* dev) -{ - QSE_ASSERT (aio == dev->aio); - - if (dev->dev_capa & QSE_AIO_DEV_CAPA_ZOMBIE) - { - QSE_ASSERT (QSE_AIO_WQ_ISEMPTY(&dev->wq)); - goto kill_device; - } - - /* clear pending send requests */ - while (!QSE_AIO_WQ_ISEMPTY(&dev->wq)) - { - qse_aio_wq_t* q; - q = QSE_AIO_WQ_HEAD(&dev->wq); - unlink_wq (aio, q); - QSE_MMGR_FREE (aio->mmgr, q); - } - - if (dev->dev_capa & QSE_AIO_DEV_CAPA_HALTED) - { - /* this device is in the halted state. - * unlink it from the halted device list */ - UNLINK_DEVICE_FROM_LIST (&aio->hltdev, dev); - dev->dev_capa &= ~QSE_AIO_DEV_CAPA_HALTED; - } - else - { - QSE_ASSERT (dev->dev_capa & QSE_AIO_DEV_CAPA_ACTIVE); - UNLINK_DEVICE_FROM_LIST (&aio->actdev, dev); - dev->dev_capa &= ~QSE_AIO_DEV_CAPA_ACTIVE; - } - - qse_aio_dev_watch (dev, QSE_AIO_DEV_WATCH_STOP, 0); - -kill_device: - if (kill_and_free_device(dev, 0) <= -1) - { - QSE_ASSERT (dev->dev_capa & QSE_AIO_DEV_CAPA_ZOMBIE); - if (schedule_kill_zombie_job (dev) <= -1) - { - /* i have to choice but to free up the devide by force */ - while (kill_and_free_device (dev, 1) <= -1) - { - if (aio->stopreq != QSE_AIO_STOPREQ_NONE) - { - /* i can't wait until destruction attempt gets - * fully successful. there is a chance that some - * resources can leak inside the device */ - kill_and_free_device (dev, 2); - break; - } - } - } - } -} - -void qse_aio_dev_halt (qse_aio_dev_t* dev) -{ - if (dev->dev_capa & QSE_AIO_DEV_CAPA_ACTIVE) - { - qse_aio_t* aio; - - aio = dev->aio; - - /* delink the device object from the active device list */ - UNLINK_DEVICE_FROM_LIST (&aio->actdev, dev); - dev->dev_capa &= ~QSE_AIO_DEV_CAPA_ACTIVE; - - /* place it at the back of the halted device list */ - APPEND_DEVICE_TO_LIST (&aio->hltdev, dev); - dev->dev_capa |= QSE_AIO_DEV_CAPA_HALTED; - } -} - -int qse_aio_dev_ioctl (qse_aio_dev_t* dev, int cmd, void* arg) -{ - if (dev->dev_mth->ioctl) return dev->dev_mth->ioctl (dev, cmd, arg); - dev->aio->errnum = QSE_AIO_ENOSUP; /* TODO: different error code ? */ - return -1; -} - -int qse_aio_dev_watch (qse_aio_dev_t* dev, qse_aio_dev_watch_cmd_t cmd, int events) -{ - int mux_cmd; - int dev_capa; - - /* the virtual device doesn't perform actual I/O. - * it's different from not hanving QSE_AIO_DEV_CAPA_IN and QSE_AIO_DEV_CAPA_OUT. - * a non-virtual device without the capabilities still gets attention - * of the system multiplexer for hangup and error. */ - if (dev->dev_capa & QSE_AIO_DEV_CAPA_VIRTUAL) return 0; - - /*ev.data.ptr = dev;*/ - switch (cmd) - { - case QSE_AIO_DEV_WATCH_START: - /* upon start, only input watching is requested */ - events = QSE_AIO_DEV_EVENT_IN; - mux_cmd = MUX_CMD_INSERT; - break; - - case QSE_AIO_DEV_WATCH_RENEW: - /* auto-renwal mode. input watching is requested all the time. - * output watching is requested only if there're enqueued - * data for writing. */ - events = QSE_AIO_DEV_EVENT_IN; - if (!QSE_AIO_WQ_ISEMPTY(&dev->wq)) events |= QSE_AIO_DEV_EVENT_OUT; - /* fall through */ - case QSE_AIO_DEV_WATCH_UPDATE: - /* honor event watching requests as given by the caller */ - mux_cmd = MUX_CMD_UPDATE; - break; - - case QSE_AIO_DEV_WATCH_STOP: - events = 0; /* override events */ - mux_cmd = MUX_CMD_DELETE; - break; - - default: - dev->aio->errnum = QSE_AIO_EINVAL; - return -1; - } - - dev_capa = dev->dev_capa; - dev_capa &= ~(DEV_CAPA_ALL_WATCHED); - - /* this function honors QSE_AIO_DEV_EVENT_IN and QSE_AIO_DEV_EVENT_OUT only - * as valid input event bits. it intends to provide simple abstraction - * by reducing the variety of event bits that the caller has to handle. */ - - if ((events & QSE_AIO_DEV_EVENT_IN) && !(dev->dev_capa & (QSE_AIO_DEV_CAPA_IN_CLOSED | QSE_AIO_DEV_CAPA_IN_DISABLED))) - { - if (dev->dev_capa & QSE_AIO_DEV_CAPA_IN) - { - if (dev->dev_capa & QSE_AIO_DEV_CAPA_PRI) dev_capa |= QSE_AIO_DEV_CAPA_PRI_WATCHED; - dev_capa |= QSE_AIO_DEV_CAPA_IN_WATCHED; - } - } - - if ((events & QSE_AIO_DEV_EVENT_OUT) && !(dev->dev_capa & QSE_AIO_DEV_CAPA_OUT_CLOSED)) - { - if (dev->dev_capa & QSE_AIO_DEV_CAPA_OUT) dev_capa |= QSE_AIO_DEV_CAPA_OUT_WATCHED; - } - - if (mux_cmd == MUX_CMD_UPDATE && (dev_capa & DEV_CAPA_ALL_WATCHED) == (dev->dev_capa & DEV_CAPA_ALL_WATCHED)) - { - /* no change in the device capacity. skip calling epoll_ctl */ - } - else - { - if (mux_control (dev, mux_cmd, dev->dev_mth->getsyshnd(dev), dev_capa) <= -1) return -1; - } - - dev->dev_capa = dev_capa; - return 0; -} - -int qse_aio_dev_read (qse_aio_dev_t* dev, int enabled) -{ - if (dev->dev_capa & QSE_AIO_DEV_CAPA_IN_CLOSED) - { - dev->aio->errnum = QSE_AIO_ENOCAPA; - return -1; - } - - if (enabled) - { - dev->dev_capa &= ~QSE_AIO_DEV_CAPA_IN_DISABLED; - if (!dev->aio->in_exec && (dev->dev_capa & QSE_AIO_DEV_CAPA_IN_WATCHED)) goto renew_watch_now; - } - else - { - dev->dev_capa |= QSE_AIO_DEV_CAPA_IN_DISABLED; - if (!dev->aio->in_exec && !(dev->dev_capa & QSE_AIO_DEV_CAPA_IN_WATCHED)) goto renew_watch_now; - } - - dev->aio->renew_watch = 1; - return 0; - -renew_watch_now: - if (qse_aio_dev_watch (dev, QSE_AIO_DEV_WATCH_RENEW, 0) <= -1) return -1; - return 0; -} - -static void on_write_timeout (qse_aio_t* aio, const qse_ntime_t* now, qse_aio_tmrjob_t* job) -{ - qse_aio_wq_t* q; - qse_aio_dev_t* dev; - int x; - - q = (qse_aio_wq_t*)job->ctx; - dev = q->dev; - - dev->aio->errnum = QSE_AIO_ETMOUT; - x = dev->dev_evcb->on_write (dev, -1, q->ctx, &q->dstaddr); - - QSE_ASSERT (q->tmridx == QSE_AIO_TMRIDX_INVALID); - QSE_AIO_WQ_UNLINK(q); - QSE_MMGR_FREE (aio->mmgr, q); - - if (x <= -1) qse_aio_dev_halt (dev); -} - -static int __dev_write (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t len, const qse_ntime_t* tmout, void* wrctx, const qse_aio_devaddr_t* dstaddr) -{ - const qse_uint8_t* uptr; - qse_aio_iolen_t urem, ulen; - qse_aio_wq_t* q; - int x; - - if (dev->dev_capa & QSE_AIO_DEV_CAPA_OUT_CLOSED) - { - dev->aio->errnum = QSE_AIO_ENOCAPA; - return -1; - } - - uptr = data; - urem = len; - - if (!QSE_AIO_WQ_ISEMPTY(&dev->wq)) - { - /* the writing queue is not empty. - * enqueue this request immediately */ - goto enqueue_data; - } - - if (dev->dev_capa & QSE_AIO_DEV_CAPA_STREAM) - { - /* use the do..while() loop to be able to send a zero-length data */ - do - { - ulen = urem; - x = dev->dev_mth->write (dev, data, &ulen, dstaddr); - if (x <= -1) return -1; - else if (x == 0) - { - /* [NOTE] - * the write queue is empty at this moment. a zero-length - * request for a stream device can still get enqueued if the - * write callback returns 0 though i can't figure out if there - * is a compelling reason to do so - */ - goto enqueue_data; /* enqueue remaining data */ - } - else - { - urem -= ulen; - uptr += ulen; - } - } - while (urem > 0); - - if (len <= 0) /* original length */ - { - /* a zero-length writing request is to close the writing end */ - dev->dev_capa |= QSE_AIO_DEV_CAPA_OUT_CLOSED; - } - - if (dev->dev_evcb->on_write (dev, len, wrctx, dstaddr) <= -1) return -1; - } - else - { - ulen = urem; - - x = dev->dev_mth->write (dev, data, &ulen, dstaddr); - if (x <= -1) return -1; - else if (x == 0) goto enqueue_data; - - /* partial writing is still considered ok for a non-stream device */ - if (dev->dev_evcb->on_write (dev, ulen, wrctx, dstaddr) <= -1) return -1; - } - - return 1; /* written immediately and called on_write callback */ - -enqueue_data: - if (!(dev->dev_capa & QSE_AIO_DEV_CAPA_OUT_QUEUED)) - { - /* writing queuing is not requested. so return failure */ - dev->aio->errnum = QSE_AIO_ENOCAPA; - return -1; - } - - /* queue the remaining data*/ - q = (qse_aio_wq_t*)QSE_MMGR_ALLOC (dev->aio->mmgr, QSE_SIZEOF(*q) + (dstaddr? dstaddr->len: 0) + urem); - if (!q) - { - dev->aio->errnum = QSE_AIO_ENOMEM; - return -1; - } - - q->tmridx = QSE_AIO_TMRIDX_INVALID; - q->dev = dev; - q->ctx = wrctx; - - if (dstaddr) - { - q->dstaddr.ptr = (qse_uint8_t*)(q + 1); - q->dstaddr.len = dstaddr->len; - QSE_MEMCPY (q->dstaddr.ptr, dstaddr->ptr, dstaddr->len); - } - else - { - q->dstaddr.len = 0; - } - - q->ptr = (qse_uint8_t*)(q + 1) + q->dstaddr.len; - q->len = urem; - q->olen = len; - QSE_MEMCPY (q->ptr, uptr, urem); - - if (tmout && qse_ispostime(tmout)) - { - qse_aio_tmrjob_t tmrjob; - - QSE_MEMSET (&tmrjob, 0, QSE_SIZEOF(tmrjob)); - tmrjob.ctx = q; - qse_gettime (&tmrjob.when); - qse_addtime (&tmrjob.when, tmout, &tmrjob.when); - tmrjob.handler = on_write_timeout; - tmrjob.idxptr = &q->tmridx; - - q->tmridx = qse_aio_instmrjob (dev->aio, &tmrjob); - if (q->tmridx == QSE_AIO_TMRIDX_INVALID) - { - QSE_MMGR_FREE (dev->aio->mmgr, q); - return -1; - } - } - - QSE_AIO_WQ_ENQ (&dev->wq, q); - if (!dev->aio->in_exec && !(dev->dev_capa & QSE_AIO_DEV_CAPA_OUT_WATCHED)) - { - /* if output is not being watched, arrange to do so */ - if (qse_aio_dev_watch (dev, QSE_AIO_DEV_WATCH_RENEW, 0) <= -1) - { - unlink_wq (dev->aio, q); - QSE_MMGR_FREE (dev->aio->mmgr, q); - return -1; - } - } - else - { - dev->aio->renew_watch = 1; - } - - return 0; /* request pused to a write queue. */ -} - -int qse_aio_dev_write (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t len, void* wrctx, const qse_aio_devaddr_t* dstaddr) -{ - return __dev_write (dev, data, len, QSE_NULL, wrctx, dstaddr); -} - -int qse_aio_dev_timedwrite (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t len, const qse_ntime_t* tmout, void* wrctx, const qse_aio_devaddr_t* dstaddr) -{ - return __dev_write (dev, data, len, tmout, wrctx, dstaddr); -} - -int qse_aio_makesyshndasync (qse_aio_t* aio, qse_aio_syshnd_t hnd) -{ -#if defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) - int flags; - - if ((flags = fcntl (hnd, F_GETFL)) <= -1 || - (flags = fcntl (hnd, F_SETFL, flags | O_NONBLOCK)) <= -1) - { - aio->errnum = qse_aio_syserrtoerrnum (errno); - return -1; - } - - return 0; -#else - aio->errnum = QSE_AIO_ENOSUP; - return -1; -#endif -} - -qse_aio_errnum_t qse_aio_syserrtoerrnum (int no) -{ - switch (no) - { - case ENOMEM: - return QSE_AIO_ENOMEM; - - case EINVAL: - return QSE_AIO_EINVAL; - - case EEXIST: - return QSE_AIO_EEXIST; - - case ENOENT: - return QSE_AIO_ENOENT; - - case EMFILE: - return QSE_AIO_EMFILE; - - #if defined(ENFILE) - case ENFILE: - return QSE_AIO_ENFILE; - #endif - - #if defined(EWOULDBLOCK) && defined(EAGAIN) && (EWOULDBLOCK != EAGAIN) - case EAGAIN: - case EWOULDBLOCK: - return QSE_AIO_EAGAIN; - #elif defined(EAGAIN) - case EAGAIN: - return QSE_AIO_EAGAIN; - #elif defined(EWOULDBLOCK) - case EWOULDBLOCK: - return QSE_AIO_EAGAIN; - #endif - - #if defined(ECONNREFUSED) - case ECONNREFUSED: - return QSE_AIO_ECONRF; - #endif - - #if defined(ECONNRESETD) - case ECONNRESET: - return QSE_AIO_ECONRS; - #endif - - #if defined(EPERM) - case EPERM: - return QSE_AIO_EPERM; - #endif - - default: - return QSE_AIO_ESYSERR; - } -} diff --git a/qse/samples/si/Makefile.am b/qse/samples/si/Makefile.am index a2385dca..7b634150 100644 --- a/qse/samples/si/Makefile.am +++ b/qse/samples/si/Makefile.am @@ -6,7 +6,6 @@ AM_CPPFLAGS = \ -I$(includedir) bin_PROGRAMS = \ - aio01 \ dir01 \ fio01 \ fio02 \ @@ -38,7 +37,6 @@ LDADD += $(UNICOWS_LIBS) endif endif -aio01_SOURCES = aio01.c dir01_SOURCES = dir01.c fio01_SOURCES = fio01.c fio02_SOURCES = fio02.c diff --git a/qse/samples/si/aio01.c b/qse/samples/si/aio01.c deleted file mode 100644 index 0894c0bb..00000000 --- a/qse/samples/si/aio01.c +++ /dev/null @@ -1,713 +0,0 @@ -/* - * $Id$ - * - Copyright (c) 2015-2016 Chung, Hyung-Hwan. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#if defined(HAVE_OPENSSL_SSL_H) && defined(HAVE_SSL) -# include -# if defined(HAVE_OPENSSL_ERR_H) -# include -# endif -# if defined(HAVE_OPENSSL_ENGINE_H) -# include -# endif -# define USE_SSL -#endif - -/* ========================================================================= */ - -/* ========================================================================= */ - -#if defined(USE_SSL) -static void cleanup_openssl () -{ - /* ERR_remove_state() should be called for each thread if the application is thread */ - ERR_remove_state (0); -#if defined(HAVE_ENGINE_CLEANUP) - ENGINE_cleanup (); -#endif - ERR_free_strings (); - EVP_cleanup (); -#if defined(HAVE_CRYPTO_CLEANUP_ALL_EX_DATA) - CRYPTO_cleanup_all_ex_data (); -#endif -} -#endif - -struct tcp_server_t -{ - int tally; -}; -typedef struct tcp_server_t tcp_server_t; - -static void tcp_sck_on_disconnect (qse_aio_dev_sck_t* tcp) -{ - switch (QSE_AIO_DEV_SCK_GET_PROGRESS(tcp)) - { - case QSE_AIO_DEV_SCK_CONNECTING: - printf ("OUTGOING SESSION DISCONNECTED - FAILED TO CONNECT (%d) TO REMOTE SERVER\n", (int)tcp->sck); - break; - - case QSE_AIO_DEV_SCK_CONNECTING_SSL: - printf ("OUTGOING SESSION DISCONNECTED - FAILED TO SSL-CONNECT (%d) TO REMOTE SERVER\n", (int)tcp->sck); - break; - - case QSE_AIO_DEV_SCK_LISTENING: - printf ("SHUTTING DOWN THE SERVER SOCKET(%d)...\n", (int)tcp->sck); - break; - - case QSE_AIO_DEV_SCK_CONNECTED: - printf ("OUTGOING CLIENT CONNECTION GOT TORN DOWN(%d).......\n", (int)tcp->sck); - break; - - case QSE_AIO_DEV_SCK_ACCEPTING_SSL: - printf ("INCOMING SSL-ACCEPT GOT DISCONNECTED(%d) ....\n", (int)tcp->sck); - break; - - case QSE_AIO_DEV_SCK_ACCEPTED: - printf ("INCOMING CLIENT BEING SERVED GOT DISCONNECTED(%d).......\n", (int)tcp->sck); - break; - - default: - printf ("SOCKET DEVICE DISCONNECTED (%d - %x)\n", (int)tcp->sck, (unsigned int)tcp->state); - break; - } -} -static int tcp_sck_on_connect (qse_aio_dev_sck_t* tcp) -{ - - qse_aio_sckfam_t fam; - qse_aio_scklen_t len; - qse_mchar_t buf1[128], buf2[128]; - - memset (buf1, 0, QSE_SIZEOF(buf1)); - memset (buf2, 0, QSE_SIZEOF(buf2)); - - qse_aio_getsckaddrinfo (tcp->aio, &tcp->localaddr, &len, &fam); - inet_ntop (fam, tcp->localaddr.data, buf1, QSE_COUNTOF(buf1)); - - qse_aio_getsckaddrinfo (tcp->aio, &tcp->remoteaddr, &len, &fam); - inet_ntop (fam, tcp->remoteaddr.data, buf2, QSE_COUNTOF(buf2)); - - if (tcp->state & QSE_AIO_DEV_SCK_CONNECTED) - { - -printf ("device connected to a remote server... LOCAL %s:%d REMOTE %s:%d.", buf1, qse_aio_getsckaddrport(&tcp->localaddr), buf2, qse_aio_getsckaddrport(&tcp->remoteaddr)); - - } - else if (tcp->state & QSE_AIO_DEV_SCK_ACCEPTED) - { -printf ("device accepted client device... .LOCAL %s:%d REMOTE %s:%d\n", buf1, qse_aio_getsckaddrport(&tcp->localaddr), buf2, qse_aio_getsckaddrport(&tcp->remoteaddr)); - } - - return qse_aio_dev_sck_write (tcp, "hello", 5, QSE_NULL, QSE_NULL); -} - -static int tcp_sck_on_write (qse_aio_dev_sck_t* tcp, qse_aio_iolen_t wrlen, void* wrctx, const qse_aio_sckaddr_t* dstaddr) -{ - tcp_server_t* ts; - -if (wrlen <= -1) -{ -printf ("SEDING TIMED OUT...........\n"); - qse_aio_dev_sck_halt(tcp); -} -else -{ - ts = (tcp_server_t*)(tcp + 1); - printf (">>> SENT MESSAGE %d of length %ld\n", ts->tally, (long int)wrlen); - - ts->tally++; -// if (ts->tally >= 2) qse_aio_dev_sck_halt (tcp); - -printf ("ENABLING READING..............................\n"); - qse_aio_dev_sck_read (tcp, 1); - - //qse_aio_dev_sck_timedread (tcp, 1, 1000); -} - return 0; -} - -static int tcp_sck_on_read (qse_aio_dev_sck_t* tcp, const void* buf, qse_aio_iolen_t len, const qse_aio_sckaddr_t* srcaddr) -{ - int n; - - if (len <= 0) - { - printf ("STREAM DEVICE: EOF RECEIVED...\n"); - /* no outstanding request. but EOF */ - qse_aio_dev_sck_halt (tcp); - return 0; - } - -printf ("on read %d\n", (int)len); - -{ -qse_ntime_t tmout; - -static char a ='A'; -char* xxx = malloc (1000000); -memset (xxx, a++ ,1000000); - - //return qse_aio_dev_sck_write (tcp, "HELLO", 5, QSE_NULL); - qse_inittime (&tmout, 5, 0); - n = qse_aio_dev_sck_timedwrite (tcp, xxx, 1000000, &tmout, QSE_NULL, QSE_NULL); -free (xxx); - - - if (n <= -1) return -1; -} - - -printf ("DISABLING READING..............................\n"); - qse_aio_dev_sck_read (tcp, 0); - - /* post the write finisher */ - n = qse_aio_dev_sck_write (tcp, QSE_NULL, 0, QSE_NULL, QSE_NULL); - if (n <= -1) return -1; - - return 0; - -/* return 1; let the main loop to read more greedily without consulting the multiplexer */ -} - -/* ========================================================================= */ - -static void pro_on_close (qse_aio_dev_pro_t* dev, qse_aio_dev_pro_sid_t sid) -{ -printf (">>>>>>>>>>>>> ON CLOSE OF SLAVE %d.\n", sid); -} - -static int pro_on_read (qse_aio_dev_pro_t* dev, const void* data, qse_aio_iolen_t dlen, qse_aio_dev_pro_sid_t sid) -{ -printf ("PROCESS READ DATA on SLAVE[%d]... [%.*s]\n", (int)sid, (int)dlen, (char*)data); - return 0; -} - - -static int pro_on_write (qse_aio_dev_pro_t* dev, qse_aio_iolen_t wrlen, void* wrctx) -{ -printf ("PROCESS WROTE DATA...\n"); - return 0; -} - -/* ========================================================================= */ - -static int arp_sck_on_read (qse_aio_dev_sck_t* dev, const void* data, qse_aio_iolen_t dlen, const qse_aio_sckaddr_t* srcaddr) -{ - qse_aio_etharp_pkt_t* eap; - - - if (dlen < QSE_SIZEOF(*eap)) return 0; /* drop */ - - eap = (qse_aio_etharp_pkt_t*)data; - - printf ("ARP ON IFINDEX %d OPCODE: %d", qse_aio_getsckaddrifindex(srcaddr), ntohs(eap->arphdr.opcode)); - - printf (" SHA: %02X:%02X:%02X:%02X:%02X:%02X", eap->arppld.sha[0], eap->arppld.sha[1], eap->arppld.sha[2], eap->arppld.sha[3], eap->arppld.sha[4], eap->arppld.sha[5]); - printf (" SPA: %d.%d.%d.%d", eap->arppld.spa[0], eap->arppld.spa[1], eap->arppld.spa[2], eap->arppld.spa[3]); - printf (" THA: %02X:%02X:%02X:%02X:%02X:%02X", eap->arppld.tha[0], eap->arppld.tha[1], eap->arppld.tha[2], eap->arppld.tha[3], eap->arppld.tha[4], eap->arppld.tha[5]); - printf (" TPA: %d.%d.%d.%d", eap->arppld.tpa[0], eap->arppld.tpa[1], eap->arppld.tpa[2], eap->arppld.tpa[3]); - printf ("\n"); - return 0; -} - -static int arp_sck_on_write (qse_aio_dev_sck_t* dev, qse_aio_iolen_t wrlen, void* wrctx, const qse_aio_sckaddr_t* dstaddr) -{ - return 0; -} - -static void arp_sck_on_disconnect (qse_aio_dev_sck_t* dev) -{ -printf ("SHUTTING DOWN ARP SOCKET %d...\n", dev->sck); -} - -static int setup_arp_tester (qse_aio_t* aio) -{ - qse_aio_sckaddr_t ethdst; - qse_aio_etharp_pkt_t etharp; - qse_aio_dev_sck_make_t sck_make; - qse_aio_dev_sck_t* sck; - - memset (&sck_make, 0, QSE_SIZEOF(sck_make)); - sck_make.type = QSE_AIO_DEV_SCK_ARP; - //sck_make.type = QSE_AIO_DEV_SCK_ARP_DGRAM; - sck_make.on_write = arp_sck_on_write; - sck_make.on_read = arp_sck_on_read; - sck_make.on_disconnect = arp_sck_on_disconnect; - sck = qse_aio_dev_sck_make (aio, 0, &sck_make); - if (!sck) - { - printf ("Cannot make socket device\n"); - return -1; - } - - //qse_aio_sckaddr_initforeth (ðdst, if_nametoindex("enp0s25.3"), (qse_aio_ethaddr_t*)"\xFF\xFF\xFF\xFF\xFF\xFF"); - qse_aio_sckaddr_initforeth (ðdst, if_nametoindex("enp0s25.3"), (qse_aio_ethaddr_t*)"\xAA\xBB\xFF\xCC\xDD\xFF"); - - memset (ðarp, 0, sizeof(etharp)); - - memcpy (etharp.ethhdr.source, "\xB8\x6B\x23\x9C\x10\x76", QSE_AIO_ETHADDR_LEN); - //memcpy (etharp.ethhdr.dest, "\xFF\xFF\xFF\xFF\xFF\xFF", QSE_AIO_ETHADDR_LEN); - memcpy (etharp.ethhdr.dest, "\xAA\xBB\xFF\xCC\xDD\xFF", QSE_AIO_ETHADDR_LEN); - etharp.ethhdr.proto = QSE_CONST_HTON16(QSE_AIO_ETHHDR_PROTO_ARP); - - etharp.arphdr.htype = QSE_CONST_HTON16(QSE_AIO_ARPHDR_HTYPE_ETH); - etharp.arphdr.ptype = QSE_CONST_HTON16(QSE_AIO_ARPHDR_PTYPE_IP4); - etharp.arphdr.hlen = QSE_AIO_ETHADDR_LEN; - etharp.arphdr.plen = QSE_AIO_IP4ADDR_LEN; - etharp.arphdr.opcode = QSE_CONST_HTON16(QSE_AIO_ARPHDR_OPCODE_REQUEST); - - memcpy (etharp.arppld.sha, "\xB8\x6B\x23\x9C\x10\x76", QSE_AIO_ETHADDR_LEN); - - if (qse_aio_dev_sck_write (sck, ðarp, sizeof(etharp), NULL, ðdst) <= -1) - //if (qse_aio_dev_sck_write (sck, ðarp.arphdr, sizeof(etharp) - sizeof(etharp.ethhdr), NULL, ðaddr) <= -1) - { - printf ("CANNOT WRITE ARP...\n"); - } - - - return 0; -} - -/* ========================================================================= */ - -struct icmpxtn_t -{ - qse_uint16_t icmp_seq; - qse_aio_tmridx_t tmout_jobidx; - int reply_received; -}; - -typedef struct icmpxtn_t icmpxtn_t; - -static int schedule_icmp_wait (qse_aio_dev_sck_t* dev); - -static void send_icmp (qse_aio_dev_sck_t* dev, qse_uint16_t seq) -{ - qse_aio_sckaddr_t dstaddr; - qse_aio_ip4addr_t ia; - qse_aio_icmphdr_t* icmphdr; - qse_uint8_t buf[512]; - - inet_pton (AF_INET, "192.168.1.131", &ia); - qse_aio_sckaddr_initforip4 (&dstaddr, 0, &ia); - - memset(buf, 0, QSE_SIZEOF(buf)); - icmphdr = (qse_aio_icmphdr_t*)buf; - icmphdr->type = QSE_AIO_ICMP_ECHO_REQUEST; - icmphdr->u.echo.id = QSE_CONST_HTON16(100); - icmphdr->u.echo.seq = qse_hton16(seq); - - memset (&buf[QSE_SIZEOF(*icmphdr)], 'A', QSE_SIZEOF(buf) - QSE_SIZEOF(*icmphdr)); - icmphdr->checksum = qse_aio_checksumip (icmphdr, QSE_SIZEOF(buf)); - - if (qse_aio_dev_sck_write (dev, buf, QSE_SIZEOF(buf), NULL, &dstaddr) <= -1) - { - printf ("CANNOT WRITE ICMP...\n"); - qse_aio_dev_sck_halt (dev); - } - - if (schedule_icmp_wait (dev) <= -1) - { - printf ("CANNOT SCHEDULE ICMP WAIT...\n"); - qse_aio_dev_sck_halt (dev); - } -} - -static void on_icmp_due (qse_aio_t* aio, const qse_ntime_t* now, qse_aio_tmrjob_t* tmrjob) -{ - qse_aio_dev_sck_t* dev; - icmpxtn_t* icmpxtn; - - dev = tmrjob->ctx; - icmpxtn = (icmpxtn_t*)(dev + 1); - - if (icmpxtn->reply_received) - icmpxtn->reply_received = 0; - else - printf ("NO ICMP REPLY RECEIVED....\n"); - - send_icmp (dev, ++icmpxtn->icmp_seq); -} - -static int schedule_icmp_wait (qse_aio_dev_sck_t* dev) -{ - icmpxtn_t* icmpxtn; - qse_aio_tmrjob_t tmrjob; - qse_ntime_t fire_after; - - icmpxtn = (icmpxtn_t*)(dev + 1); - qse_inittime (&fire_after, 2, 0); - - memset (&tmrjob, 0, QSE_SIZEOF(tmrjob)); - tmrjob.ctx = dev; - qse_gettime (&tmrjob.when); - qse_addtime (&tmrjob.when, &fire_after, &tmrjob.when); - tmrjob.handler = on_icmp_due; - tmrjob.idxptr = &icmpxtn->tmout_jobidx; - - assert (icmpxtn->tmout_jobidx == QSE_AIO_TMRIDX_INVALID); - - return (qse_aio_instmrjob (dev->aio, &tmrjob) == QSE_AIO_TMRIDX_INVALID)? -1: 0; -} - -static int icmp_sck_on_read (qse_aio_dev_sck_t* dev, const void* data, qse_aio_iolen_t dlen, const qse_aio_sckaddr_t* srcaddr) -{ - icmpxtn_t* icmpxtn; - qse_aio_iphdr_t* iphdr; - qse_aio_icmphdr_t* icmphdr; - - /* when received, the data contains the IP header.. */ - icmpxtn = (icmpxtn_t*)(dev + 1); - - if (dlen < QSE_SIZEOF(*iphdr) + QSE_SIZEOF(*icmphdr)) - { - printf ("INVALID ICMP PACKET.. TOO SHORT...%d\n", (int)dlen); - } - else - { - /* TODO: consider IP options... */ - iphdr = (qse_aio_iphdr_t*)data; - - if (iphdr->ihl * 4 + QSE_SIZEOF(*icmphdr) > dlen) - { - printf ("INVALID ICMP PACKET.. WRONG IHL...%d\n", (int)iphdr->ihl * 4); - } - else - { - icmphdr = (qse_aio_icmphdr_t*)((qse_uint8_t*)data + (iphdr->ihl * 4)); - - /* TODO: check srcaddr against target */ - - if (icmphdr->type == QSE_AIO_ICMP_ECHO_REPLY && - qse_ntoh16(icmphdr->u.echo.seq) == icmpxtn->icmp_seq) /* TODO: more check.. echo.id.. */ - { - icmpxtn->reply_received = 1; - printf ("ICMP REPLY RECEIVED...ID %d SEQ %d\n", (int)qse_ntoh16(icmphdr->u.echo.id), (int)qse_ntoh16(icmphdr->u.echo.seq)); - } - else - { - printf ("GARBAGE ICMP PACKET...LEN %d SEQ %d,%d\n", (int)dlen, (int)icmpxtn->icmp_seq, (int)qse_ntoh16(icmphdr->u.echo.seq)); - } - } - } - return 0; -} - - -static int icmp_sck_on_write (qse_aio_dev_sck_t* dev, qse_aio_iolen_t wrlen, void* wrctx, const qse_aio_sckaddr_t* dstaddr) -{ - /*icmpxtn_t* icmpxtn; - - icmpxtn = (icmpxtn_t*)(dev + 1); */ - - return 0; -} - -static void icmp_sck_on_disconnect (qse_aio_dev_sck_t* dev) -{ - icmpxtn_t* icmpxtn; - - icmpxtn = (icmpxtn_t*)(dev + 1); - -printf ("SHUTTING DOWN ICMP SOCKET %d...\n", dev->sck); - if (icmpxtn->tmout_jobidx != QSE_AIO_TMRIDX_INVALID) - { - - qse_aio_deltmrjob (dev->aio, icmpxtn->tmout_jobidx); - icmpxtn->tmout_jobidx = QSE_AIO_TMRIDX_INVALID; - } -} - -static int setup_ping4_tester (qse_aio_t* aio) -{ - qse_aio_dev_sck_make_t sck_make; - qse_aio_dev_sck_t* sck; - icmpxtn_t* icmpxtn; - - memset (&sck_make, 0, QSE_SIZEOF(sck_make)); - sck_make.type = QSE_AIO_DEV_SCK_ICMP4; - sck_make.on_write = icmp_sck_on_write; - sck_make.on_read = icmp_sck_on_read; - sck_make.on_disconnect = icmp_sck_on_disconnect; - - sck = qse_aio_dev_sck_make (aio, QSE_SIZEOF(icmpxtn_t), &sck_make); - if (!sck) - { - printf ("Cannot make ICMP4 socket device\n"); - return -1; - } - - icmpxtn = (icmpxtn_t*)(sck + 1); - icmpxtn->tmout_jobidx = QSE_AIO_TMRIDX_INVALID; - icmpxtn->icmp_seq = 0; - - /*TODO: qse_aio_dev_sck_setbroadcast (sck, 1);*/ - - send_icmp (sck, ++icmpxtn->icmp_seq); - - return 0; -} - - -/* ========================================================================= */ - -static qse_aio_t* g_aio; - -static void handle_signal (int sig) -{ - if (g_aio) qse_aio_stop (g_aio, QSE_AIO_STOPREQ_TERMINATION); -} - -int main () -{ - int i; - - qse_aio_t* aio; - qse_aio_dev_sck_t* tcp[3]; - - struct sigaction sigact; - qse_aio_dev_sck_connect_t tcp_conn; - qse_aio_dev_sck_listen_t tcp_lstn; - qse_aio_dev_sck_bind_t tcp_bind; - qse_aio_dev_sck_make_t tcp_make; - - tcp_server_t* ts; - -#if defined(USE_SSL) - SSL_load_error_strings (); - SSL_library_init (); -#endif - - aio = qse_aio_open(QSE_MMGR_GETDFL(), 0, 512, QSE_NULL); - if (!aio) - { - printf ("Cannot open aio\n"); - return -1; - } - - g_aio = aio; - - memset (&sigact, 0, QSE_SIZEOF(sigact)); - sigact.sa_flags = SA_RESTART; - sigact.sa_handler = handle_signal; - sigaction (SIGINT, &sigact, QSE_NULL); - - memset (&sigact, 0, QSE_SIZEOF(sigact)); - sigact.sa_handler = SIG_IGN; - sigaction (SIGPIPE, &sigact, QSE_NULL); - -/* - memset (&sigact, 0, QSE_SIZEOF(sigact)); - sigact.sa_handler = SIG_IGN; - sigaction (SIGCHLD, &sigact, QSE_NULL); -*/ - - /*memset (&sin, 0, QSE_SIZEOF(sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons(1234); */ -/* - udp = (qse_aio_dev_udp_t*)qse_aio_makedev (aio, QSE_SIZEOF(*udp), &udp_mth, &udp_evcb, &sin); - if (!udp) - { - printf ("Cannot make udp\n"); - goto oops; - } -*/ - - memset (&tcp_make, 0, QSE_SIZEOF(&tcp_make)); - tcp_make.type = QSE_AIO_DEV_SCK_TCP4; - tcp_make.on_write = tcp_sck_on_write; - tcp_make.on_read = tcp_sck_on_read; - tcp_make.on_disconnect = tcp_sck_on_disconnect; - tcp[0] = qse_aio_dev_sck_make(aio, QSE_SIZEOF(tcp_server_t), &tcp_make); - if (!tcp[0]) - { - printf ("Cannot make tcp\n"); - goto oops; - } - - ts = (tcp_server_t*)(tcp[0] + 1); - ts->tally = 0; - - - memset (&tcp_conn, 0, QSE_SIZEOF(tcp_conn)); -{ - in_addr_t ia = inet_addr("192.168.1.119"); - qse_aio_sckaddr_initforip4 (&tcp_conn.remoteaddr, 9999, (qse_aio_ip4addr_t*)&ia); -} - - qse_inittime (&tcp_conn.connect_tmout, 5, 0); - tcp_conn.on_connect = tcp_sck_on_connect; - tcp_conn.options = QSE_AIO_DEV_SCK_CONNECT_SSL; - if (qse_aio_dev_sck_connect(tcp[0], &tcp_conn) <= -1) - { - printf ("qse_aio_dev_sck_connect() failed....\n"); - /* carry on regardless of failure */ - } - - /* -------------------------------------------------------------- */ - memset (&tcp_make, 0, QSE_SIZEOF(&tcp_make)); - tcp_make.type = QSE_AIO_DEV_SCK_TCP4; - tcp_make.on_write = tcp_sck_on_write; - tcp_make.on_read = tcp_sck_on_read; - tcp_make.on_disconnect = tcp_sck_on_disconnect; - - tcp[1] = qse_aio_dev_sck_make(aio, QSE_SIZEOF(tcp_server_t), &tcp_make); - if (!tcp[1]) - { - printf ("Cannot make tcp\n"); - goto oops; - } - ts = (tcp_server_t*)(tcp[1] + 1); - ts->tally = 0; - - memset (&tcp_bind, 0, QSE_SIZEOF(tcp_bind)); - qse_aio_sckaddr_initforip4 (&tcp_bind.localaddr, 1234, QSE_NULL); - tcp_bind.options = QSE_AIO_DEV_SCK_BIND_REUSEADDR; - - if (qse_aio_dev_sck_bind (tcp[1],&tcp_bind) <= -1) - { - printf ("qse_aio_dev_sck_bind() failed....\n"); - goto oops; - } - - - tcp_lstn.backlogs = 100; - tcp_lstn.on_connect = tcp_sck_on_connect; - if (qse_aio_dev_sck_listen (tcp[1], &tcp_lstn) <= -1) - { - printf ("qse_aio_dev_sck_listen() failed....\n"); - goto oops; - } - - /* -------------------------------------------------------------- */ - memset (&tcp_make, 0, QSE_SIZEOF(&tcp_make)); - tcp_make.type = QSE_AIO_DEV_SCK_TCP4; - tcp_make.on_write = tcp_sck_on_write; - tcp_make.on_read = tcp_sck_on_read; - tcp_make.on_disconnect = tcp_sck_on_disconnect; - - tcp[2] = qse_aio_dev_sck_make (aio, QSE_SIZEOF(tcp_server_t), &tcp_make); - if (!tcp[2]) - { - printf ("Cannot make tcp\n"); - goto oops; - } - ts = (tcp_server_t*)(tcp[2] + 1); - ts->tally = 0; - - memset (&tcp_bind, 0, QSE_SIZEOF(tcp_bind)); - qse_aio_sckaddr_initforip4 (&tcp_bind.localaddr, 1235, QSE_NULL); - tcp_bind.options = QSE_AIO_DEV_SCK_BIND_REUSEADDR | /*QSE_AIO_DEV_SCK_BIND_REUSEPORT |*/ QSE_AIO_DEV_SCK_BIND_SSL; - tcp_bind.ssl_certfile = QSE_MT("localhost.crt"); - tcp_bind.ssl_keyfile = QSE_MT("localhost.key"); - qse_inittime (&tcp_bind.accept_tmout, 5, 1); - - if (qse_aio_dev_sck_bind (tcp[2],&tcp_bind) <= -1) - { - printf ("qse_aio_dev_sck_bind() failed....\n"); - goto oops; - } - - tcp_lstn.backlogs = 100; - tcp_lstn.on_connect = tcp_sck_on_connect; - if (qse_aio_dev_sck_listen (tcp[2], &tcp_lstn) <= -1) - { - printf ("qse_aio_dev_sck_listen() failed....\n"); - goto oops; - } - - //qse_aio_dev_sck_sendfile (tcp[2], fd, offset, count); - - if (setup_arp_tester(aio) <= -1) goto oops; - if (setup_ping4_tester(aio) <= -1) goto oops; - - -for (i = 0; i < 5; i++) -{ - qse_aio_dev_pro_t* pro; - qse_aio_dev_pro_make_t pro_make; - - memset (&pro_make, 0, QSE_SIZEOF(pro_make)); - pro_make.flags = QSE_AIO_DEV_PRO_READOUT | QSE_AIO_DEV_PRO_READERR | QSE_AIO_DEV_PRO_WRITEIN /*| QSE_AIO_DEV_PRO_FORGET_CHILD*/; - //pro_make.cmd = "/bin/ls -laF /usr/bin"; - //pro_make.cmd = "/bin/ls -laF"; - pro_make.cmd = "./a"; - pro_make.on_read = pro_on_read; - pro_make.on_write = pro_on_write; - pro_make.on_close = pro_on_close; - - pro = qse_aio_dev_pro_make (aio, 0, &pro_make); - if (!pro) - { - printf ("CANNOT CREATE PROCESS PIPE\n"); - goto oops; - } - - qse_aio_dev_pro_write (pro, "MY AIO LIBRARY\n", 16, QSE_NULL); -//qse_aio_dev_pro_killchild (pro); -//qse_aio_dev_pro_close (pro, QSE_AIO_DEV_PRO_IN); -//qse_aio_dev_pro_close (pro, QSE_AIO_DEV_PRO_OUT); -//qse_aio_dev_pro_close (pro, QSE_AIO_DEV_PRO_ERR); -} - - qse_aio_loop (aio); - - g_aio = QSE_NULL; - qse_aio_close (aio); -#if defined(USE_SSL) - cleanup_openssl (); -#endif - - return 0; - -oops: - g_aio = QSE_NULL; - qse_aio_close (aio); -#if defined(USE_SSL) - cleanup_openssl (); -#endif - return -1; -}